--- /dev/null
+--Upgrade Script for 2.9.3 to 2.10.0
+\set eg_version '''2.10.0'''
+BEGIN;
+
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('2.10.0', :eg_version);
+
+SELECT evergreen.upgrade_deps_block_check('0945', :eg_version);
+
+-- run the entire update inside a DO block for managing the logic
+-- of whether to recreate the optional reporter views
+DO $$
+DECLARE
+ has_current_circ BOOLEAN;
+ has_billing_summary BOOLEAN;
+BEGIN
+
+SELECT INTO has_current_circ TRUE FROM pg_views
+ WHERE schemaname = 'reporter' AND viewname = 'classic_current_circ';
+
+SELECT INTO has_billing_summary TRUE FROM pg_views
+ WHERE schemaname = 'reporter' AND
+ viewname = 'classic_current_billing_summary';
+
+DROP VIEW action.all_circulation;
+DROP VIEW IF EXISTS reporter.classic_current_circ;
+DROP VIEW IF EXISTS reporter.classic_current_billing_summary;
+DROP VIEW reporter.demographic;
+DROP VIEW auditor.actor_usr_lifecycle;
+DROP VIEW action.all_hold_request;
+
+ALTER TABLE actor.usr
+ ALTER dob TYPE DATE USING (dob + '3 hours'::INTERVAL)::DATE;
+
+-- alter the auditor table manually to apply the same
+-- dob mangling logic as above.
+ALTER TABLE auditor.actor_usr_history
+ ALTER dob TYPE DATE USING (dob + '3 hours'::INTERVAL)::DATE;
+
+-- this recreates auditor.actor_usr_lifecycle
+PERFORM auditor.update_auditors();
+
+CREATE VIEW reporter.demographic AS
+ SELECT u.id, u.dob,
+ CASE
+ WHEN u.dob IS NULL THEN 'Adult'::text
+ WHEN age(u.dob) > '18 years'::interval THEN 'Adult'::text
+ ELSE 'Juvenile'::text
+ END AS general_division
+ FROM actor.usr u;
+
+CREATE VIEW action.all_circulation AS
+ SELECT aged_circulation.id, aged_circulation.usr_post_code,
+ aged_circulation.usr_home_ou, aged_circulation.usr_profile,
+ aged_circulation.usr_birth_year, aged_circulation.copy_call_number,
+ aged_circulation.copy_location, aged_circulation.copy_owning_lib,
+ aged_circulation.copy_circ_lib, aged_circulation.copy_bib_record,
+ aged_circulation.xact_start, aged_circulation.xact_finish,
+ aged_circulation.target_copy, aged_circulation.circ_lib,
+ aged_circulation.circ_staff, aged_circulation.checkin_staff,
+ aged_circulation.checkin_lib, aged_circulation.renewal_remaining,
+ aged_circulation.grace_period, aged_circulation.due_date,
+ aged_circulation.stop_fines_time, aged_circulation.checkin_time,
+ aged_circulation.create_time, aged_circulation.duration,
+ aged_circulation.fine_interval, aged_circulation.recurring_fine,
+ aged_circulation.max_fine, aged_circulation.phone_renewal,
+ aged_circulation.desk_renewal, aged_circulation.opac_renewal,
+ aged_circulation.duration_rule,
+ aged_circulation.recurring_fine_rule,
+ aged_circulation.max_fine_rule, aged_circulation.stop_fines,
+ aged_circulation.workstation, aged_circulation.checkin_workstation,
+ aged_circulation.checkin_scan_time, aged_circulation.parent_circ
+ FROM action.aged_circulation
+UNION ALL
+ SELECT DISTINCT circ.id,
+ COALESCE(a.post_code, b.post_code) AS usr_post_code,
+ p.home_ou AS usr_home_ou, p.profile AS usr_profile,
+ date_part('year'::text, p.dob)::integer AS usr_birth_year,
+ cp.call_number AS copy_call_number, circ.copy_location,
+ cn.owning_lib AS copy_owning_lib, cp.circ_lib AS copy_circ_lib,
+ cn.record AS copy_bib_record, circ.xact_start, circ.xact_finish,
+ circ.target_copy, circ.circ_lib, circ.circ_staff,
+ circ.checkin_staff, circ.checkin_lib, circ.renewal_remaining,
+ circ.grace_period, circ.due_date, circ.stop_fines_time,
+ circ.checkin_time, circ.create_time, circ.duration,
+ circ.fine_interval, circ.recurring_fine, circ.max_fine,
+ circ.phone_renewal, circ.desk_renewal, circ.opac_renewal,
+ circ.duration_rule, circ.recurring_fine_rule, circ.max_fine_rule,
+ circ.stop_fines, circ.workstation, circ.checkin_workstation,
+ circ.checkin_scan_time, circ.parent_circ
+ FROM action.circulation circ
+ JOIN asset.copy cp ON circ.target_copy = cp.id
+ JOIN asset.call_number cn ON cp.call_number = cn.id
+ JOIN actor.usr p ON circ.usr = p.id
+ LEFT JOIN actor.usr_address a ON p.mailing_address = a.id
+ LEFT JOIN actor.usr_address b ON p.billing_address = b.id;
+
+CREATE OR REPLACE VIEW action.all_hold_request AS
+ SELECT DISTINCT COALESCE(a.post_code, b.post_code) AS usr_post_code,
+ p.home_ou AS usr_home_ou, p.profile AS usr_profile,
+ date_part('year'::text, p.dob)::integer AS usr_birth_year,
+ ahr.requestor <> ahr.usr AS staff_placed, ahr.id, ahr.request_time,
+ ahr.capture_time, ahr.fulfillment_time, ahr.checkin_time,
+ ahr.return_time, ahr.prev_check_time, ahr.expire_time,
+ ahr.cancel_time, ahr.cancel_cause, ahr.cancel_note, ahr.target,
+ ahr.current_copy, ahr.fulfillment_staff, ahr.fulfillment_lib,
+ ahr.request_lib, ahr.selection_ou, ahr.selection_depth,
+ ahr.pickup_lib, ahr.hold_type, ahr.holdable_formats,
+ CASE
+ WHEN ahr.phone_notify IS NULL THEN false
+ WHEN ahr.phone_notify = ''::text THEN false
+ ELSE true
+ END AS phone_notify,
+ ahr.email_notify,
+ CASE
+ WHEN ahr.sms_notify IS NULL THEN false
+ WHEN ahr.sms_notify = ''::text THEN false
+ ELSE true
+ END AS sms_notify,
+ ahr.frozen, ahr.thaw_date, ahr.shelf_time, ahr.cut_in_line,
+ ahr.mint_condition, ahr.shelf_expire_time, ahr.current_shelf_lib,
+ ahr.behind_desk
+ FROM action.hold_request ahr
+ JOIN actor.usr p ON ahr.usr = p.id
+ LEFT JOIN actor.usr_address a ON p.mailing_address = a.id
+ LEFT JOIN actor.usr_address b ON p.billing_address = b.id
+UNION ALL
+ SELECT aged_hold_request.usr_post_code, aged_hold_request.usr_home_ou,
+ aged_hold_request.usr_profile, aged_hold_request.usr_birth_year,
+ aged_hold_request.staff_placed, aged_hold_request.id,
+ aged_hold_request.request_time, aged_hold_request.capture_time,
+ aged_hold_request.fulfillment_time, aged_hold_request.checkin_time,
+ aged_hold_request.return_time, aged_hold_request.prev_check_time,
+ aged_hold_request.expire_time, aged_hold_request.cancel_time,
+ aged_hold_request.cancel_cause, aged_hold_request.cancel_note,
+ aged_hold_request.target, aged_hold_request.current_copy,
+ aged_hold_request.fulfillment_staff,
+ aged_hold_request.fulfillment_lib, aged_hold_request.request_lib,
+ aged_hold_request.selection_ou, aged_hold_request.selection_depth,
+ aged_hold_request.pickup_lib, aged_hold_request.hold_type,
+ aged_hold_request.holdable_formats, aged_hold_request.phone_notify,
+ aged_hold_request.email_notify, aged_hold_request.sms_notify,
+ aged_hold_request.frozen, aged_hold_request.thaw_date,
+ aged_hold_request.shelf_time, aged_hold_request.cut_in_line,
+ aged_hold_request.mint_condition,
+ aged_hold_request.shelf_expire_time,
+ aged_hold_request.current_shelf_lib, aged_hold_request.behind_desk
+ FROM action.aged_hold_request;
+
+IF has_current_circ THEN
+RAISE NOTICE 'Recreating optional view reporter.classic_current_circ';
+
+CREATE OR REPLACE VIEW reporter.classic_current_circ AS
+SELECT cl.shortname AS circ_lib,
+ cl.id AS circ_lib_id,
+ circ.xact_start AS xact_start,
+ circ_type.type AS circ_type,
+ cp.id AS copy_id,
+ cp.circ_modifier,
+ ol.shortname AS owning_lib_name,
+ lm.value AS language,
+ lfm.value AS lit_form,
+ ifm.value AS item_form,
+ itm.value AS item_type,
+ sl.name AS shelving_location,
+ p.id AS patron_id,
+ g.name AS profile_group,
+ dem.general_division AS demographic_general_division,
+ circ.id AS id,
+ cn.id AS call_number,
+ cn.label AS call_number_label,
+ call_number_dewey(cn.label) AS dewey,
+ CASE
+ WHEN call_number_dewey(cn.label) ~ E'^[0-9.]+$'
+ THEN
+ btrim(
+ to_char(
+ 10 * floor((call_number_dewey(cn.label)::float) / 10), '000'
+ )
+ )
+ ELSE NULL
+ END AS dewey_block_tens,
+ CASE
+ WHEN call_number_dewey(cn.label) ~ E'^[0-9.]+$'
+ THEN
+ btrim(
+ to_char(
+ 100 * floor((call_number_dewey(cn.label)::float) / 100), '000'
+ )
+ )
+ ELSE NULL
+ END AS dewey_block_hundreds,
+ CASE
+ WHEN call_number_dewey(cn.label) ~ E'^[0-9.]+$'
+ THEN
+ btrim(
+ to_char(
+ 10 * floor((call_number_dewey(cn.label)::float) / 10), '000'
+ )
+ )
+ || '-' ||
+ btrim(
+ to_char(
+ 10 * floor((call_number_dewey(cn.label)::float) / 10) + 9, '000'
+ )
+ )
+ ELSE NULL
+ END AS dewey_range_tens,
+ CASE
+ WHEN call_number_dewey(cn.label) ~ E'^[0-9.]+$'
+ THEN
+ btrim(
+ to_char(
+ 100 * floor((call_number_dewey(cn.label)::float) / 100), '000'
+ )
+ )
+ || '-' ||
+ btrim(
+ to_char(
+ 100 * floor((call_number_dewey(cn.label)::float) / 100) + 99, '000'
+ )
+ )
+ ELSE NULL
+ END AS dewey_range_hundreds,
+ hl.id AS patron_home_lib,
+ hl.shortname AS patron_home_lib_shortname,
+ paddr.county AS patron_county,
+ paddr.city AS patron_city,
+ paddr.post_code AS patron_zip,
+ sc1.stat_cat_entry AS stat_cat_1,
+ sc2.stat_cat_entry AS stat_cat_2,
+ sce1.value AS stat_cat_1_value,
+ sce2.value AS stat_cat_2_value
+ FROM action.circulation circ
+ JOIN reporter.circ_type circ_type ON (circ.id = circ_type.id)
+ JOIN asset.copy cp ON (cp.id = circ.target_copy)
+ JOIN asset.copy_location sl ON (cp.location = sl.id)
+ JOIN asset.call_number cn ON (cp.call_number = cn.id)
+ JOIN actor.org_unit ol ON (cn.owning_lib = ol.id)
+ JOIN metabib.rec_descriptor rd ON (rd.record = cn.record)
+ JOIN actor.org_unit cl ON (circ.circ_lib = cl.id)
+ JOIN actor.usr p ON (p.id = circ.usr)
+ JOIN actor.org_unit hl ON (p.home_ou = hl.id)
+ JOIN permission.grp_tree g ON (p.profile = g.id)
+ JOIN reporter.demographic dem ON (dem.id = p.id)
+ JOIN actor.usr_address paddr ON (paddr.id = p.billing_address)
+ LEFT JOIN config.language_map lm ON (rd.item_lang = lm.code)
+ LEFT JOIN config.lit_form_map lfm ON (rd.lit_form = lfm.code)
+ LEFT JOIN config.item_form_map ifm ON (rd.item_form = ifm.code)
+ LEFT JOIN config.item_type_map itm ON (rd.item_type = itm.code)
+ LEFT JOIN asset.stat_cat_entry_copy_map sc1 ON (sc1.owning_copy = cp.id AND sc1.stat_cat = 1)
+ LEFT JOIN asset.stat_cat_entry sce1 ON (sce1.id = sc1.stat_cat_entry)
+ LEFT JOIN asset.stat_cat_entry_copy_map sc2 ON (sc2.owning_copy = cp.id AND sc2.stat_cat = 2)
+ LEFT JOIN asset.stat_cat_entry sce2 ON (sce2.id = sc2.stat_cat_entry);
+END IF;
+
+IF has_billing_summary THEN
+RAISE NOTICE 'Recreating optional view reporter.classic_current_billing_summary';
+
+CREATE OR REPLACE VIEW reporter.classic_current_billing_summary AS
+SELECT x.id AS id,
+ x.usr AS usr,
+ bl.shortname AS billing_location_shortname,
+ bl.name AS billing_location_name,
+ x.billing_location AS billing_location,
+ c.barcode AS barcode,
+ u.home_ou AS usr_home_ou,
+ ul.shortname AS usr_home_ou_shortname,
+ ul.name AS usr_home_ou_name,
+ x.xact_start AS xact_start,
+ x.xact_finish AS xact_finish,
+ x.xact_type AS xact_type,
+ x.total_paid AS total_paid,
+ x.total_owed AS total_owed,
+ x.balance_owed AS balance_owed,
+ x.last_payment_ts AS last_payment_ts,
+ x.last_payment_note AS last_payment_note,
+ x.last_payment_type AS last_payment_type,
+ x.last_billing_ts AS last_billing_ts,
+ x.last_billing_note AS last_billing_note,
+ x.last_billing_type AS last_billing_type,
+ paddr.county AS patron_county,
+ paddr.city AS patron_city,
+ paddr.post_code AS patron_zip,
+ g.name AS profile_group,
+ dem.general_division AS demographic_general_division
+ FROM money.open_billable_xact_summary x
+ JOIN actor.org_unit bl ON (x.billing_location = bl.id)
+ JOIN actor.usr u ON (u.id = x.usr)
+ JOIN actor.org_unit ul ON (u.home_ou = ul.id)
+ JOIN actor.card c ON (u.card = c.id)
+ JOIN permission.grp_tree g ON (u.profile = g.id)
+ JOIN reporter.demographic dem ON (dem.id = u.id)
+ JOIN actor.usr_address paddr ON (paddr.id = u.billing_address);
+END IF;
+
+END $$;
+
+SELECT evergreen.upgrade_deps_block_check('0946', :eg_version);
+
+CREATE OR REPLACE FUNCTION actor.org_unit_ancestor_setting_batch( org_id INT, VARIADIC setting_names TEXT[] ) RETURNS SETOF actor.org_unit_setting AS $$
+DECLARE
+ setting RECORD;
+ setting_name TEXT;
+ cur_org INT;
+BEGIN
+ FOREACH setting_name IN ARRAY setting_names
+ LOOP
+ cur_org := org_id;
+ LOOP
+ SELECT INTO setting * FROM actor.org_unit_setting WHERE org_unit = cur_org AND name = setting_name;
+ IF FOUND THEN
+ RETURN NEXT setting;
+ EXIT;
+ END IF;
+ SELECT INTO cur_org parent_ou FROM actor.org_unit WHERE id = cur_org;
+ EXIT WHEN cur_org IS NULL;
+ END LOOP;
+ END LOOP;
+ RETURN;
+END;
+$$ LANGUAGE plpgsql STABLE;
+
+COMMENT ON FUNCTION actor.org_unit_ancestor_setting_batch( INT, VARIADIC TEXT[] ) IS $$
+For each setting name passed, search "up" the org_unit tree until
+we find the first occurrence of an org_unit_setting with the given name.
+$$;
+
+SELECT evergreen.upgrade_deps_block_check('0947', :eg_version);
+
+CREATE OR REPLACE FUNCTION evergreen.lpad_number_substrings( TEXT, TEXT, INT ) RETURNS TEXT AS $$
+ my $string = shift; # Source string
+ my $pad = shift; # string to fill. Typically '0'. This should be a single character.
+ my $len = shift; # length of resultant padded field
+
+ $string =~ s/([0-9]+)/$pad x ($len - length($1)) . $1/eg;
+
+ return $string;
+$$ LANGUAGE PLPERLU;
+
+SELECT evergreen.upgrade_deps_block_check('0951', :eg_version);
+
+ALTER TABLE config.standing_penalty
+ ADD COLUMN ignore_proximity INTEGER;
+
+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;
+ item_prox INT;
+ pickup_prox INT;
+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;
+
+ -- Proximity of user's home_ou to the pickup_lib to see if penalty should be ignored.
+ SELECT INTO pickup_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = v_pickup_ou;
+ -- Proximity of user's home_ou to the items' lib to see if penalty should be ignored.
+ IF hold_test.distance_is_from_owner THEN
+ SELECT INTO item_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = item_cn_object.owning_lib;
+ ELSE
+ SELECT INTO item_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = item_object.circ_lib;
+ 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.ignore_proximity IS NULL OR csp.ignore_proximity < item_prox
+ OR csp.ignore_proximity < pickup_prox)
+ 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;
+
+CREATE OR REPLACE FUNCTION action.item_user_circ_test( circ_ou INT, match_item BIGINT, match_user INT, renewal BOOL ) RETURNS SETOF action.circ_matrix_test_result AS $func$
+DECLARE
+ user_object actor.usr%ROWTYPE;
+ standing_penalty config.standing_penalty%ROWTYPE;
+ item_object asset.copy%ROWTYPE;
+ item_status_object config.copy_status%ROWTYPE;
+ item_location_object asset.copy_location%ROWTYPE;
+ result action.circ_matrix_test_result;
+ circ_test action.found_circ_matrix_matchpoint;
+ circ_matchpoint config.circ_matrix_matchpoint%ROWTYPE;
+ circ_limit_set config.circ_limit_set%ROWTYPE;
+ hold_ratio action.hold_stats%ROWTYPE;
+ penalty_type TEXT;
+ items_out INT;
+ context_org_list INT[];
+ done BOOL := FALSE;
+ item_prox INT;
+ home_prox INT;
+BEGIN
+ -- Assume success unless we hit a failure condition
+ result.success := TRUE;
+
+ -- Need user info to look up matchpoints
+ SELECT INTO user_object * FROM actor.usr WHERE id = match_user AND NOT deleted;
+
+ -- (Insta)Fail if we couldn't find the user
+ IF user_object.id IS NULL THEN
+ result.fail_part := 'no_user';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ RETURN;
+ END IF;
+
+ -- Need item info to look up matchpoints
+ SELECT INTO item_object * FROM asset.copy WHERE id = match_item AND NOT deleted;
+
+ -- (Insta)Fail if we couldn't find the item
+ 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 circ_test * FROM action.find_circ_matrix_matchpoint(circ_ou, item_object, user_object, renewal);
+
+ circ_matchpoint := circ_test.matchpoint;
+ result.matchpoint := circ_matchpoint.id;
+ result.circulate := circ_matchpoint.circulate;
+ result.duration_rule := circ_matchpoint.duration_rule;
+ result.recurring_fine_rule := circ_matchpoint.recurring_fine_rule;
+ result.max_fine_rule := circ_matchpoint.max_fine_rule;
+ result.hard_due_date := circ_matchpoint.hard_due_date;
+ result.renewals := circ_matchpoint.renewals;
+ result.grace_period := circ_matchpoint.grace_period;
+ result.buildrows := circ_test.buildrows;
+
+ -- (Insta)Fail if we couldn't find a matchpoint
+ IF circ_test.success = false THEN
+ result.fail_part := 'no_matchpoint';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ RETURN;
+ END IF;
+
+ -- All failures before this point are non-recoverable
+ -- Below this point are possibly overridable failures
+
+ -- Fail if the user is barred
+ IF user_object.barred IS TRUE THEN
+ result.fail_part := 'actor.usr.barred';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+
+ -- Fail if the item can't circulate
+ IF item_object.circulate IS FALSE THEN
+ result.fail_part := 'asset.copy.circulate';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+
+ -- Fail if the item isn't in a circulateable status on a non-renewal
+ IF NOT renewal AND item_object.status NOT IN ( 0, 7, 8 ) THEN
+ result.fail_part := 'asset.copy.status';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ -- Alternately, fail if the item isn't checked out on a renewal
+ ELSIF renewal AND item_object.status <> 1 THEN
+ result.fail_part := 'asset.copy.status';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+
+ -- Fail if the item can't circulate because of the shelving location
+ SELECT INTO item_location_object * FROM asset.copy_location WHERE id = item_object.location;
+ IF item_location_object.circulate IS FALSE THEN
+ result.fail_part := 'asset.copy_location.circulate';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+
+ -- Use Circ OU for penalties and such
+ SELECT INTO context_org_list ARRAY_AGG(id) FROM actor.org_unit_full_path( circ_ou );
+
+ -- Proximity of user's home_ou to circ_ou to see if penalties should be ignored.
+ SELECT INTO home_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = circ_ou;
+
+ -- Proximity of user's home_ou to item circ_lib to see if penalties should be ignored.
+ SELECT INTO item_prox prox FROM actor.org_unit_proximity WHERE from_org = user_object.home_ou AND to_org = item_object.circ_lib;
+
+ IF renewal THEN
+ penalty_type = '%RENEW%';
+ ELSE
+ penalty_type = '%CIRC%';
+ 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.ignore_proximity IS NULL
+ OR csp.ignore_proximity < home_prox
+ OR csp.ignore_proximity < item_prox)
+ AND csp.block_list LIKE penalty_type LOOP
+
+ result.fail_part := standing_penalty.name;
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END LOOP;
+
+ -- Fail if the test is set to hard non-circulating
+ IF circ_matchpoint.circulate IS FALSE THEN
+ result.fail_part := 'config.circ_matrix_test.circulate';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+
+ -- Fail if the total copy-hold ratio is too low
+ IF circ_matchpoint.total_copy_hold_ratio IS NOT NULL THEN
+ SELECT INTO hold_ratio * FROM action.copy_related_hold_stats(match_item);
+ IF hold_ratio.total_copy_ratio IS NOT NULL AND hold_ratio.total_copy_ratio < circ_matchpoint.total_copy_hold_ratio THEN
+ result.fail_part := 'config.circ_matrix_test.total_copy_hold_ratio';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+ END IF;
+
+ -- Fail if the available copy-hold ratio is too low
+ IF circ_matchpoint.available_copy_hold_ratio IS NOT NULL THEN
+ IF hold_ratio.hold_count IS NULL THEN
+ SELECT INTO hold_ratio * FROM action.copy_related_hold_stats(match_item);
+ END IF;
+ IF hold_ratio.available_copy_ratio IS NOT NULL AND hold_ratio.available_copy_ratio < circ_matchpoint.available_copy_hold_ratio THEN
+ result.fail_part := 'config.circ_matrix_test.available_copy_hold_ratio';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+ END IF;
+
+ -- Fail if the user has too many items out by defined limit sets
+ FOR circ_limit_set IN SELECT ccls.* FROM config.circ_limit_set ccls
+ JOIN config.circ_matrix_limit_set_map ccmlsm ON ccmlsm.limit_set = ccls.id
+ WHERE ccmlsm.active AND ( ccmlsm.matchpoint = circ_matchpoint.id OR
+ ( ccmlsm.matchpoint IN (SELECT * FROM unnest(result.buildrows)) AND ccmlsm.fallthrough )
+ ) LOOP
+ IF circ_limit_set.items_out > 0 AND NOT renewal THEN
+ SELECT INTO context_org_list ARRAY_AGG(aou.id)
+ FROM actor.org_unit_full_path( circ_ou ) aou
+ JOIN actor.org_unit_type aout ON aou.ou_type = aout.id
+ WHERE aout.depth >= circ_limit_set.depth;
+ IF circ_limit_set.global THEN
+ WITH RECURSIVE descendant_depth AS (
+ SELECT ou.id,
+ ou.parent_ou
+ FROM actor.org_unit ou
+ WHERE ou.id IN (SELECT * FROM unnest(context_org_list))
+ UNION
+ SELECT ou.id,
+ ou.parent_ou
+ FROM actor.org_unit ou
+ JOIN descendant_depth ot ON (ot.id = ou.parent_ou)
+ ) SELECT INTO context_org_list ARRAY_AGG(ou.id) FROM actor.org_unit ou JOIN descendant_depth USING (id);
+ END IF;
+ SELECT INTO items_out COUNT(DISTINCT circ.id)
+ FROM action.circulation circ
+ JOIN asset.copy copy ON (copy.id = circ.target_copy)
+ LEFT JOIN action.circulation_limit_group_map aclgm ON (circ.id = aclgm.circ)
+ WHERE circ.usr = match_user
+ AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list))
+ AND circ.checkin_time IS NULL
+ AND (circ.stop_fines IN ('MAXFINES','LONGOVERDUE') OR circ.stop_fines IS NULL)
+ AND (copy.circ_modifier IN (SELECT circ_mod FROM config.circ_limit_set_circ_mod_map WHERE limit_set = circ_limit_set.id)
+ OR copy.location IN (SELECT copy_loc FROM config.circ_limit_set_copy_loc_map WHERE limit_set = circ_limit_set.id)
+ OR aclgm.limit_group IN (SELECT limit_group FROM config.circ_limit_set_group_map WHERE limit_set = circ_limit_set.id)
+ );
+ IF items_out >= circ_limit_set.items_out THEN
+ result.fail_part := 'config.circ_matrix_circ_mod_test';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+ END IF;
+ SELECT INTO result.limit_groups result.limit_groups || ARRAY_AGG(limit_group) FROM config.circ_limit_set_group_map WHERE limit_set = circ_limit_set.id AND NOT check_only;
+ END LOOP;
+
+ -- If we passed everything, return the successful matchpoint
+ IF NOT done THEN
+ RETURN NEXT result;
+ END IF;
+
+ RETURN;
+END;
+$func$ LANGUAGE plpgsql;
+
+SELECT evergreen.upgrade_deps_block_check('0952', :eg_version); --miker/kmlussier/gmcharlt
+
+INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field, facet_field, facet_xpath, joiner ) VALUES
+ (33, 'identifier', 'genre', oils_i18n_gettext(33, 'Genre', 'cmf', 'label'), 'marcxml', $$//marc:datafield[@tag='655']$$, FALSE, TRUE, $$//*[local-name()='subfield' and contains('abvxyz',@code)]$$, ' -- ' ); -- /* to fool vim */;
+
+INSERT INTO config.metabib_field_index_norm_map (field,norm)
+ SELECT m.id,
+ i.id
+ FROM config.metabib_field m,
+ config.index_normalizer i
+ WHERE i.func IN ('search_normalize','split_date_range')
+ AND m.id IN (33);
+
+SELECT evergreen.upgrade_deps_block_check('0953', :eg_version);
+
+CREATE OR REPLACE FUNCTION unapi.bre (
+ 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
+ me biblio.record_entry%ROWTYPE;
+ layout unapi.bre_output_layout%ROWTYPE;
+ xfrm config.xml_transform%ROWTYPE;
+ ouid INT;
+ tmp_xml TEXT;
+ top_el TEXT;
+ output XML;
+ hxml XML;
+ axml XML;
+ source XML;
+BEGIN
+
+ 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;
+
+ IF format = 'holdings_xml' THEN -- the special case
+ output := unapi.holdings_xml( obj_id, ouid, org, depth, includes, slimit, soffset, include_xmlns);
+ 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 me FROM biblio.record_entry WHERE id = obj_id;
+
+ -- grab bib_source, if any
+ IF ('cbs' = ANY (includes) AND me.source IS NOT NULL) THEN
+ source := unapi.cbs(me.source,NULL,NULL,NULL,NULL);
+ ELSE
+ source := NULL::XML;
+ END IF;
+
+ -- grab SVF if we need them
+ IF ('mra' = ANY (includes)) THEN
+ axml := unapi.mra(obj_id,NULL,NULL,NULL,NULL);
+ ELSE
+ axml := NULL::XML;
+ END IF;
+
+ -- grab holdings if we need them
+ IF ('holdings_xml' = ANY (includes)) THEN
+ hxml := unapi.holdings_xml(obj_id, ouid, org, depth, evergreen.array_remove_item_by_value(includes,'holdings_xml'), slimit, soffset, include_xmlns, pref_lib);
+ ELSE
+ hxml := NULL::XML;
+ END IF;
+
+
+ -- generate our item node
+
+
+ IF format = 'marcxml' THEN
+ tmp_xml := me.marc;
+ IF tmp_xml !~ E'<marc:' THEN -- If we're not using the prefixed namespace in this record, then remove all declarations of it
+ tmp_xml := REGEXP_REPLACE(tmp_xml, ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g');
+ END IF;
+ ELSE
+ tmp_xml := oils_xslt_process(me.marc, xfrm.xslt)::XML;
+ END IF;
+
+ top_el := REGEXP_REPLACE(tmp_xml, E'^.*?<((?:\\S+:)?' || layout.holdings_element || ').*$', E'\\1');
+
+ IF source IS NOT NULL THEN
+ tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', source || '</' || top_el || E'>\\1');
+ END IF;
+
+ IF axml IS NOT NULL THEN
+ tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1');
+ END IF;
+
+ IF hxml IS NOT NULL THEN -- XXX how do we configure the holdings position?
+ tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1');
+ END IF;
+
+ IF ('bre.unapi' = ANY (includes)) THEN
+ output := REGEXP_REPLACE(
+ tmp_xml,
+ '</' || top_el || '>(.*?)',
+ XMLELEMENT(
+ name abbr,
+ XMLATTRIBUTES(
+ 'http://www.w3.org/1999/xhtml' AS xmlns,
+ 'unapi-id' AS class,
+ 'tag:open-ils.org:U2@bre/' || obj_id || '/' || org AS title
+ )
+ )::TEXT || '</' || top_el || E'>\\1'
+ );
+ ELSE
+ output := tmp_xml;
+ END IF;
+
+ IF ('bre.extern' = ANY (includes)) THEN
+ output := REGEXP_REPLACE(
+ tmp_xml,
+ '</' || top_el || '>(.*?)',
+ XMLELEMENT(
+ name extern,
+ XMLATTRIBUTES(
+ 'http://open-ils.org/spec/biblio/v1' AS xmlns,
+ me.creator AS creator,
+ me.editor AS editor,
+ me.create_date AS create_date,
+ me.edit_date AS edit_date,
+ me.quality AS quality,
+ me.fingerprint AS fingerprint,
+ me.tcn_source AS tcn_source,
+ me.tcn_value AS tcn_value,
+ me.owner AS owner,
+ me.share_depth AS share_depth,
+ me.active AS active,
+ me.deleted AS deleted
+ )
+ )::TEXT || '</' || top_el || E'>\\1'
+ );
+ ELSE
+ output := tmp_xml;
+ END IF;
+
+ output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML;
+ RETURN output;
+END;
+$F$ LANGUAGE PLPGSQL STABLE;
+
+SELECT evergreen.upgrade_deps_block_check('0954', :eg_version);
+
+ALTER TABLE acq.fund_debit
+ ADD COLUMN invoice_entry INTEGER
+ REFERENCES acq.invoice_entry (id)
+ ON DELETE SET NULL;
+
+CREATE INDEX fund_debit_invoice_entry_idx ON acq.fund_debit (invoice_entry);
+CREATE INDEX lineitem_detail_fund_debit_idx ON acq.lineitem_detail (fund_debit);
+
+SELECT evergreen.upgrade_deps_block_check('0955', :eg_version);
+
+UPDATE config.org_unit_setting_type
+SET description = 'Regular expression defining the password format. Note: Be sure to update the update_password_msg.tt2 TPAC template with a user-friendly description of your password strength requirements.'
+WHERE NAME = 'global.password_regex';
+
+SELECT evergreen.upgrade_deps_block_check('0956', :eg_version);
+
+ALTER TABLE money.credit_card_payment
+ DROP COLUMN cc_type,
+ DROP COLUMN expire_month,
+ DROP COLUMN expire_year,
+ DROP COLUMN cc_first_name,
+ DROP COLUMN cc_last_name;
+
+SELECT evergreen.upgrade_deps_block_check('0957', :eg_version);
+
+-- Remove references to dropped CC payment columns in the print/email
+-- payment receipt templates, but only if the in-db template matches
+-- the stock template.
+-- The actual diff here is only about 8 lines.
+
+UPDATE action_trigger.event_definition SET template =
+$$
+[%- USE date -%]
+[%- SET user = target.0.xact.usr -%]
+To: [%- params.recipient_email || user.email %]
+From: [%- params.sender_email || default_sender %]
+Subject: Payment Receipt
+
+[% date.format -%]
+[%- SET xact_mp_hash = {} -%]
+[%- FOR mp IN target %][%# Template is hooked around payments, but let us make the receipt focused on transactions -%]
+ [%- SET xact_id = mp.xact.id -%]
+ [%- IF ! xact_mp_hash.defined( xact_id ) -%][%- xact_mp_hash.$xact_id = { 'xact' => mp.xact, 'payments' => [] } -%][%- END -%]
+ [%- xact_mp_hash.$xact_id.payments.push(mp) -%]
+[%- END -%]
+[%- FOR xact_id IN xact_mp_hash.keys.sort -%]
+ [%- SET xact = xact_mp_hash.$xact_id.xact %]
+Transaction ID: [% xact_id %]
+ [% IF xact.circulation %][% helpers.get_copy_bib_basics(xact.circulation.target_copy).title %]
+ [% ELSE %]Miscellaneous
+ [% END %]
+ Line item billings:
+ [%- SET mb_type_hash = {} -%]
+ [%- FOR mb IN xact.billings %][%# Group billings by their btype -%]
+ [%- IF mb.voided == 'f' -%]
+ [%- SET mb_type = mb.btype.id -%]
+ [%- IF ! mb_type_hash.defined( mb_type ) -%][%- mb_type_hash.$mb_type = { 'sum' => 0.00, 'billings' => [] } -%][%- END -%]
+ [%- IF ! mb_type_hash.$mb_type.defined( 'first_ts' ) -%][%- mb_type_hash.$mb_type.first_ts = mb.billing_ts -%][%- END -%]
+ [%- mb_type_hash.$mb_type.last_ts = mb.billing_ts -%]
+ [%- mb_type_hash.$mb_type.sum = mb_type_hash.$mb_type.sum + mb.amount -%]
+ [%- mb_type_hash.$mb_type.billings.push( mb ) -%]
+ [%- END -%]
+ [%- END -%]
+ [%- FOR mb_type IN mb_type_hash.keys.sort -%]
+ [%- IF mb_type == 1 %][%-# Consolidated view of overdue billings -%]
+ $[% mb_type_hash.$mb_type.sum %] for [% mb_type_hash.$mb_type.billings.0.btype.name %]
+ on [% mb_type_hash.$mb_type.first_ts %] through [% mb_type_hash.$mb_type.last_ts %]
+ [%- ELSE -%][%# all other billings show individually %]
+ [% FOR mb IN mb_type_hash.$mb_type.billings %]
+ $[% mb.amount %] for [% mb.btype.name %] on [% mb.billing_ts %] [% mb.note %]
+ [% END %]
+ [% END %]
+ [% END %]
+ Line item payments:
+ [% FOR mp IN xact_mp_hash.$xact_id.payments %]
+ Payment ID: [% mp.id %]
+ Paid [% mp.amount %] via [% SWITCH mp.payment_type -%]
+ [% CASE "cash_payment" %]cash
+ [% CASE "check_payment" %]check
+ [% CASE "credit_card_payment" %]credit card
+ [%- IF mp.credit_card_payment.cc_number %] ([% mp.credit_card_payment.cc_number %])[% END %]
+ [% CASE "credit_payment" %]credit
+ [% CASE "forgive_payment" %]forgiveness
+ [% CASE "goods_payment" %]goods
+ [% CASE "work_payment" %]work
+ [%- END %] on [% mp.payment_ts %] [% mp.note %]
+ [% END %]
+[% END %]
+$$
+
+WHERE id = 29 AND template =
+
+$$
+[%- USE date -%]
+[%- SET user = target.0.xact.usr -%]
+To: [%- params.recipient_email || user.email %]
+From: [%- params.sender_email || default_sender %]
+Subject: Payment Receipt
+
+[% date.format -%]
+[%- SET xact_mp_hash = {} -%]
+[%- FOR mp IN target %][%# Template is hooked around payments, but let us make the receipt focused on transactions -%]
+ [%- SET xact_id = mp.xact.id -%]
+ [%- IF ! xact_mp_hash.defined( xact_id ) -%][%- xact_mp_hash.$xact_id = { 'xact' => mp.xact, 'payments' => [] } -%][%- END -%]
+ [%- xact_mp_hash.$xact_id.payments.push(mp) -%]
+[%- END -%]
+[%- FOR xact_id IN xact_mp_hash.keys.sort -%]
+ [%- SET xact = xact_mp_hash.$xact_id.xact %]
+Transaction ID: [% xact_id %]
+ [% IF xact.circulation %][% helpers.get_copy_bib_basics(xact.circulation.target_copy).title %]
+ [% ELSE %]Miscellaneous
+ [% END %]
+ Line item billings:
+ [%- SET mb_type_hash = {} -%]
+ [%- FOR mb IN xact.billings %][%# Group billings by their btype -%]
+ [%- IF mb.voided == 'f' -%]
+ [%- SET mb_type = mb.btype.id -%]
+ [%- IF ! mb_type_hash.defined( mb_type ) -%][%- mb_type_hash.$mb_type = { 'sum' => 0.00, 'billings' => [] } -%][%- END -%]
+ [%- IF ! mb_type_hash.$mb_type.defined( 'first_ts' ) -%][%- mb_type_hash.$mb_type.first_ts = mb.billing_ts -%][%- END -%]
+ [%- mb_type_hash.$mb_type.last_ts = mb.billing_ts -%]
+ [%- mb_type_hash.$mb_type.sum = mb_type_hash.$mb_type.sum + mb.amount -%]
+ [%- mb_type_hash.$mb_type.billings.push( mb ) -%]
+ [%- END -%]
+ [%- END -%]
+ [%- FOR mb_type IN mb_type_hash.keys.sort -%]
+ [%- IF mb_type == 1 %][%-# Consolidated view of overdue billings -%]
+ $[% mb_type_hash.$mb_type.sum %] for [% mb_type_hash.$mb_type.billings.0.btype.name %]
+ on [% mb_type_hash.$mb_type.first_ts %] through [% mb_type_hash.$mb_type.last_ts %]
+ [%- ELSE -%][%# all other billings show individually %]
+ [% FOR mb IN mb_type_hash.$mb_type.billings %]
+ $[% mb.amount %] for [% mb.btype.name %] on [% mb.billing_ts %] [% mb.note %]
+ [% END %]
+ [% END %]
+ [% END %]
+ Line item payments:
+ [% FOR mp IN xact_mp_hash.$xact_id.payments %]
+ Payment ID: [% mp.id %]
+ Paid [% mp.amount %] via [% SWITCH mp.payment_type -%]
+ [% CASE "cash_payment" %]cash
+ [% CASE "check_payment" %]check
+ [% CASE "credit_card_payment" %]credit card (
+ [%- SET cc_chunks = mp.credit_card_payment.cc_number.replace(' ','').chunk(4); -%]
+ [%- cc_chunks.slice(0, -1+cc_chunks.max).join.replace('\S','X') -%]
+ [% cc_chunks.last -%]
+ exp [% mp.credit_card_payment.expire_month %]/[% mp.credit_card_payment.expire_year -%]
+ )
+ [% CASE "credit_payment" %]credit
+ [% CASE "forgive_payment" %]forgiveness
+ [% CASE "goods_payment" %]goods
+ [% CASE "work_payment" %]work
+ [%- END %] on [% mp.payment_ts %] [% mp.note %]
+ [% END %]
+[% END %]
+$$;
+
+
+UPDATE action_trigger.event_definition SET template =
+$$
+[%- USE date -%][%- SET user = target.0.xact.usr -%]
+<div style="li { padding: 8px; margin 5px; }">
+ <div>[% date.format %]</div><br/>
+ <ol>
+ [% SET xact_mp_hash = {} %]
+ [% FOR mp IN target %][%# Template is hooked around payments, but let us make the receipt focused on transactions %]
+ [% SET xact_id = mp.xact.id %]
+ [% IF ! xact_mp_hash.defined( xact_id ) %][% xact_mp_hash.$xact_id = { 'xact' => mp.xact, 'payments' => [] } %][% END %]
+ [% xact_mp_hash.$xact_id.payments.push(mp) %]
+ [% END %]
+ [% FOR xact_id IN xact_mp_hash.keys.sort %]
+ [% SET xact = xact_mp_hash.$xact_id.xact %]
+ <li>Transaction ID: [% xact_id %]
+ [% IF xact.circulation %][% helpers.get_copy_bib_basics(xact.circulation.target_copy).title %]
+ [% ELSE %]Miscellaneous
+ [% END %]
+ Line item billings:<ol>
+ [% SET mb_type_hash = {} %]
+ [% FOR mb IN xact.billings %][%# Group billings by their btype %]
+ [% IF mb.voided == 'f' %]
+ [% SET mb_type = mb.btype.id %]
+ [% IF ! mb_type_hash.defined( mb_type ) %][% mb_type_hash.$mb_type = { 'sum' => 0.00, 'billings' => [] } %][% END %]
+ [% IF ! mb_type_hash.$mb_type.defined( 'first_ts' ) %][% mb_type_hash.$mb_type.first_ts = mb.billing_ts %][% END %]
+ [% mb_type_hash.$mb_type.last_ts = mb.billing_ts %]
+ [% mb_type_hash.$mb_type.sum = mb_type_hash.$mb_type.sum + mb.amount %]
+ [% mb_type_hash.$mb_type.billings.push( mb ) %]
+ [% END %]
+ [% END %]
+ [% FOR mb_type IN mb_type_hash.keys.sort %]
+ <li>[% IF mb_type == 1 %][%# Consolidated view of overdue billings %]
+ $[% mb_type_hash.$mb_type.sum %] for [% mb_type_hash.$mb_type.billings.0.btype.name %]
+ on [% mb_type_hash.$mb_type.first_ts %] through [% mb_type_hash.$mb_type.last_ts %]
+ [% ELSE %][%# all other billings show individually %]
+ [% FOR mb IN mb_type_hash.$mb_type.billings %]
+ $[% mb.amount %] for [% mb.btype.name %] on [% mb.billing_ts %] [% mb.note %]
+ [% END %]
+ [% END %]</li>
+ [% END %]
+ </ol>
+ Line item payments:<ol>
+ [% FOR mp IN xact_mp_hash.$xact_id.payments %]
+ <li>Payment ID: [% mp.id %]
+ Paid [% mp.amount %] via [% SWITCH mp.payment_type -%]
+ [% CASE "cash_payment" %]cash
+ [% CASE "check_payment" %]check
+ [% CASE "credit_card_payment" %]credit card
+ [%- IF mp.credit_card_payment.cc_number %] ([% mp.credit_card_payment.cc_number %])[% END %]
+ [% CASE "credit_payment" %]credit
+ [% CASE "forgive_payment" %]forgiveness
+ [% CASE "goods_payment" %]goods
+ [% CASE "work_payment" %]work
+ [%- END %] on [% mp.payment_ts %] [% mp.note %]
+ </li>
+ [% END %]
+ </ol>
+ </li>
+ [% END %]
+ </ol>
+</div>
+$$
+
+WHERE id = 30 AND template =
+
+$$
+[%- USE date -%][%- SET user = target.0.xact.usr -%]
+<div style="li { padding: 8px; margin 5px; }">
+ <div>[% date.format %]</div><br/>
+ <ol>
+ [% SET xact_mp_hash = {} %]
+ [% FOR mp IN target %][%# Template is hooked around payments, but let us make the receipt focused on transactions %]
+ [% SET xact_id = mp.xact.id %]
+ [% IF ! xact_mp_hash.defined( xact_id ) %][% xact_mp_hash.$xact_id = { 'xact' => mp.xact, 'payments' => [] } %][% END %]
+ [% xact_mp_hash.$xact_id.payments.push(mp) %]
+ [% END %]
+ [% FOR xact_id IN xact_mp_hash.keys.sort %]
+ [% SET xact = xact_mp_hash.$xact_id.xact %]
+ <li>Transaction ID: [% xact_id %]
+ [% IF xact.circulation %][% helpers.get_copy_bib_basics(xact.circulation.target_copy).title %]
+ [% ELSE %]Miscellaneous
+ [% END %]
+ Line item billings:<ol>
+ [% SET mb_type_hash = {} %]
+ [% FOR mb IN xact.billings %][%# Group billings by their btype %]
+ [% IF mb.voided == 'f' %]
+ [% SET mb_type = mb.btype.id %]
+ [% IF ! mb_type_hash.defined( mb_type ) %][% mb_type_hash.$mb_type = { 'sum' => 0.00, 'billings' => [] } %][% END %]
+ [% IF ! mb_type_hash.$mb_type.defined( 'first_ts' ) %][% mb_type_hash.$mb_type.first_ts = mb.billing_ts %][% END %]
+ [% mb_type_hash.$mb_type.last_ts = mb.billing_ts %]
+ [% mb_type_hash.$mb_type.sum = mb_type_hash.$mb_type.sum + mb.amount %]
+ [% mb_type_hash.$mb_type.billings.push( mb ) %]
+ [% END %]
+ [% END %]
+ [% FOR mb_type IN mb_type_hash.keys.sort %]
+ <li>[% IF mb_type == 1 %][%# Consolidated view of overdue billings %]
+ $[% mb_type_hash.$mb_type.sum %] for [% mb_type_hash.$mb_type.billings.0.btype.name %]
+ on [% mb_type_hash.$mb_type.first_ts %] through [% mb_type_hash.$mb_type.last_ts %]
+ [% ELSE %][%# all other billings show individually %]
+ [% FOR mb IN mb_type_hash.$mb_type.billings %]
+ $[% mb.amount %] for [% mb.btype.name %] on [% mb.billing_ts %] [% mb.note %]
+ [% END %]
+ [% END %]</li>
+ [% END %]
+ </ol>
+ Line item payments:<ol>
+ [% FOR mp IN xact_mp_hash.$xact_id.payments %]
+ <li>Payment ID: [% mp.id %]
+ Paid [% mp.amount %] via [% SWITCH mp.payment_type -%]
+ [% CASE "cash_payment" %]cash
+ [% CASE "check_payment" %]check
+ [% CASE "credit_card_payment" %]credit card (
+ [%- SET cc_chunks = mp.credit_card_payment.cc_number.replace(' ','').chunk(4); -%]
+ [%- cc_chunks.slice(0, -1+cc_chunks.max).join.replace('\S','X') -%]
+ [% cc_chunks.last -%]
+ exp [% mp.credit_card_payment.expire_month %]/[% mp.credit_card_payment.expire_year -%]
+ )
+ [% CASE "credit_payment" %]credit
+ [% CASE "forgive_payment" %]forgiveness
+ [% CASE "goods_payment" %]goods
+ [% CASE "work_payment" %]work
+ [%- END %] on [% mp.payment_ts %] [% mp.note %]
+ </li>
+ [% END %]
+ </ol>
+ </li>
+ [% END %]
+ </ol>
+</div>
+$$;
+
+
+SELECT evergreen.upgrade_deps_block_check('0958', :eg_version);
+
+CREATE OR REPLACE FUNCTION search.facets_for_record_set(ignore_facet_classes TEXT[], hits BIGINT[]) RETURNS TABLE (id INT, value TEXT, count BIGINT) AS $$
+ SELECT id, value, count FROM (
+ SELECT mfae.field AS id,
+ mfae.value,
+ COUNT(DISTINCT mmrsm.source),
+ row_number() OVER (
+ PARTITION BY mfae.field ORDER BY COUNT(distinct mmrsm.source) DESC
+ ) AS rownum
+ FROM metabib.facet_entry mfae
+ JOIN metabib.metarecord_source_map mmrsm ON (mfae.source = mmrsm.source)
+ JOIN config.metabib_field cmf ON (cmf.id = mfae.field)
+ WHERE mmrsm.source IN (SELECT * FROM unnest($2))
+ AND cmf.facet_field
+ AND cmf.field_class NOT IN (SELECT * FROM unnest($1))
+ GROUP by 1, 2
+ ) all_facets
+ WHERE rownum <= (SELECT COALESCE((SELECT value::INT FROM config.global_flag WHERE name = 'search.max_facets_per_field' AND enabled), 1000));
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION search.facets_for_metarecord_set(ignore_facet_classes TEXT[], hits BIGINT[]) RETURNS TABLE (id INT, value TEXT, count BIGINT) AS $$
+ SELECT id, value, count FROM (
+ SELECT mfae.field AS id,
+ mfae.value,
+ COUNT(DISTINCT mmrsm.metarecord),
+ row_number() OVER (
+ PARTITION BY mfae.field ORDER BY COUNT(distinct mmrsm.metarecord) DESC
+ ) AS rownum
+ FROM metabib.facet_entry mfae
+ JOIN metabib.metarecord_source_map mmrsm ON (mfae.source = mmrsm.source)
+ JOIN config.metabib_field cmf ON (cmf.id = mfae.field)
+ WHERE mmrsm.metarecord IN (SELECT * FROM unnest($2))
+ AND cmf.facet_field
+ AND cmf.field_class NOT IN (SELECT * FROM unnest($1))
+ GROUP by 1, 2
+ ) all_facets
+ WHERE rownum <= (SELECT COALESCE((SELECT value::INT FROM config.global_flag WHERE name = 'search.max_facets_per_field' AND enabled), 1000));
+$$ LANGUAGE SQL;
+
+INSERT INTO config.global_flag (name, value, label, enabled)
+ VALUES (
+ 'search.max_facets_per_field',
+ '1000',
+ oils_i18n_gettext(
+ 'search.max_facets_per_field',
+ 'Search: maximum number of facet values to retrieve for each facet field',
+ 'cgf',
+ 'label'
+ ),
+ TRUE
+ );
+
+SELECT evergreen.upgrade_deps_block_check('0960', :eg_version);
+
+CREATE TABLE action.usr_circ_history (
+ id BIGSERIAL PRIMARY KEY,
+ usr INTEGER NOT NULL REFERENCES actor.usr(id)
+ DEFERRABLE INITIALLY DEFERRED,
+ xact_start TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
+ target_copy BIGINT NOT NULL REFERENCES asset.copy(id)
+ DEFERRABLE INITIALLY DEFERRED,
+ due_date TIMESTAMP WITH TIME ZONE NOT NULL,
+ checkin_time TIMESTAMP WITH TIME ZONE,
+ source_circ BIGINT REFERENCES action.circulation(id)
+ ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED
+);
+
+CREATE OR REPLACE FUNCTION action.maintain_usr_circ_history()
+ RETURNS TRIGGER AS $FUNK$
+DECLARE
+ cur_circ BIGINT;
+ first_circ BIGINT;
+BEGIN
+
+ -- Any retention value signifies history is enabled.
+ -- This assumes that clearing these values via external
+ -- process deletes the action.usr_circ_history rows.
+ -- TODO: replace these settings w/ a single bool setting?
+ PERFORM 1 FROM actor.usr_setting
+ WHERE usr = NEW.usr AND value IS NOT NULL AND name IN (
+ 'history.circ.retention_age',
+ 'history.circ.retention_start'
+ );
+
+ IF NOT FOUND THEN
+ RETURN NEW;
+ END IF;
+
+ IF TG_OP = 'INSERT' AND NEW.parent_circ IS NULL THEN
+ -- Starting a new circulation. Insert the history row.
+ INSERT INTO action.usr_circ_history
+ (usr, xact_start, target_copy, due_date, source_circ)
+ VALUES (
+ NEW.usr,
+ NEW.xact_start,
+ NEW.target_copy,
+ NEW.due_date,
+ NEW.id
+ );
+
+ RETURN NEW;
+ END IF;
+
+ -- find the first and last circs in the circ chain
+ -- for the currently modified circ.
+ FOR cur_circ IN SELECT id FROM action.circ_chain(NEW.id) LOOP
+ IF first_circ IS NULL THEN
+ first_circ := cur_circ;
+ CONTINUE;
+ END IF;
+ -- Allow the loop to continue so that at as the loop
+ -- completes cur_circ points to the final circulation.
+ END LOOP;
+
+ IF NEW.id <> cur_circ THEN
+ -- Modifying an intermediate circ. Ignore it.
+ RETURN NEW;
+ END IF;
+
+ -- Update the due_date/checkin_time on the history row if the current
+ -- circ is the last circ in the chain and an update is warranted.
+
+ UPDATE action.usr_circ_history
+ SET
+ due_date = NEW.due_date,
+ checkin_time = NEW.checkin_time
+ WHERE
+ source_circ = first_circ
+ AND (
+ due_date <> NEW.due_date OR (
+ (checkin_time IS NULL AND NEW.checkin_time IS NOT NULL) OR
+ (checkin_time IS NOT NULL AND NEW.checkin_time IS NULL) OR
+ (checkin_time <> NEW.checkin_time)
+ )
+ );
+ RETURN NEW;
+END;
+$FUNK$ LANGUAGE PLPGSQL;
+
+CREATE TRIGGER maintain_usr_circ_history_tgr
+ AFTER INSERT OR UPDATE ON action.circulation
+ FOR EACH ROW EXECUTE PROCEDURE action.maintain_usr_circ_history();
+
+UPDATE action_trigger.hook
+ SET core_type = 'auch'
+ WHERE key ~ '^circ.format.history.';
+
+UPDATE action_trigger.event_definition SET template =
+$$
+[%- USE date -%]
+[%- SET user = target.0.usr -%]
+To: [%- params.recipient_email || user.email %]
+From: [%- params.sender_email || default_sender %]
+Subject: Circulation History
+
+ [% FOR circ IN target %]
+ [% helpers.get_copy_bib_basics(circ.target_copy.id).title %]
+ Barcode: [% circ.target_copy.barcode %]
+ Checked Out: [% date.format(helpers.format_date(circ.xact_start), '%Y-%m-%d') %]
+ Due Date: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]
+ Returned: [%
+ date.format(
+ helpers.format_date(circ.checkin_time), '%Y-%m-%d')
+ IF circ.checkin_time;
+ %]
+ [% END %]
+$$
+WHERE id = 25 AND template =
+$$
+[%- USE date -%]
+[%- SET user = target.0.usr -%]
+To: [%- params.recipient_email || user.email %]
+From: [%- params.sender_email || default_sender %]
+Subject: Circulation History
+
+ [% FOR circ IN target %]
+ [% helpers.get_copy_bib_basics(circ.target_copy.id).title %]
+ Barcode: [% circ.target_copy.barcode %]
+ Checked Out: [% date.format(helpers.format_date(circ.xact_start), '%Y-%m-%d') %]
+ Due Date: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]
+ Returned: [% date.format(helpers.format_date(circ.checkin_time), '%Y-%m-%d') %]
+ [% END %]
+$$;
+
+-- avoid TT undef date errors
+UPDATE action_trigger.event_definition SET template =
+$$
+[%- USE date -%]
+<div>
+ <style> li { padding: 8px; margin 5px; }</style>
+ <div>[% date.format %]</div>
+ <br/>
+
+ [% user.family_name %], [% user.first_given_name %]
+ <ol>
+ [% FOR circ IN target %]
+ <li>
+ <div>[% helpers.get_copy_bib_basics(circ.target_copy.id).title %]</div>
+ <div>Barcode: [% circ.target_copy.barcode %]</div>
+ <div>Checked Out: [% date.format(helpers.format_date(circ.xact_start), '%Y-%m-%d') %]</div>
+ <div>Due Date: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]</div>
+ <div>Returned: [%
+ date.format(
+ helpers.format_date(circ.checkin_time), '%Y-%m-%d')
+ IF circ.checkin_time; -%]
+ </div>
+ </li>
+ [% END %]
+ </ol>
+</div>
+$$
+WHERE id = 26 AND template = -- only replace template if it matches stock
+$$
+[%- USE date -%]
+<div>
+ <style> li { padding: 8px; margin 5px; }</style>
+ <div>[% date.format %]</div>
+ <br/>
+
+ [% user.family_name %], [% user.first_given_name %]
+ <ol>
+ [% FOR circ IN target %]
+ <li>
+ <div>[% helpers.get_copy_bib_basics(circ.target_copy.id).title %]</div>
+ <div>Barcode: [% circ.target_copy.barcode %]</div>
+ <div>Checked Out: [% date.format(helpers.format_date(circ.xact_start), '%Y-%m-%d') %]</div>
+ <div>Due Date: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]</div>
+ <div>Returned: [% date.format(helpers.format_date(circ.checkin_time), '%Y-%m-%d') %]</div>
+ </li>
+ [% END %]
+ </ol>
+</div>
+$$;
+
+-- NOTE: ^-- stock CSV template does not include checkin_time, so
+-- no modifications are required.
+
+-- Create circ history rows for existing circ history data.
+DO $FUNK$
+DECLARE
+ cur_usr INTEGER;
+ cur_circ action.circulation%ROWTYPE;
+ last_circ action.circulation%ROWTYPE;
+ counter INTEGER DEFAULT 1;
+BEGIN
+
+ RAISE NOTICE
+ 'Migrating circ history for % users. This might take a while...',
+ (SELECT COUNT(DISTINCT(au.id)) FROM actor.usr au
+ JOIN actor.usr_setting aus ON (aus.usr = au.id)
+ WHERE NOT au.deleted AND
+ aus.name ~ '^history.circ.retention_');
+
+ FOR cur_usr IN
+ SELECT DISTINCT(au.id)
+ FROM actor.usr au
+ JOIN actor.usr_setting aus ON (aus.usr = au.id)
+ WHERE NOT au.deleted AND
+ aus.name ~ '^history.circ.retention_' LOOP
+
+ FOR cur_circ IN SELECT * FROM action.usr_visible_circs(cur_usr) LOOP
+
+ -- Find the last circ in the circ chain.
+ SELECT INTO last_circ *
+ FROM action.circ_chain(cur_circ.id)
+ ORDER BY xact_start DESC LIMIT 1;
+
+ -- Create the history row.
+ -- It's OK if last_circ = cur_circ
+ INSERT INTO action.usr_circ_history
+ (usr, xact_start, target_copy,
+ due_date, checkin_time, source_circ)
+ VALUES (
+ cur_circ.usr,
+ cur_circ.xact_start,
+ cur_circ.target_copy,
+ last_circ.due_date,
+ last_circ.checkin_time,
+ cur_circ.id
+ );
+
+ -- useful for alleviating administrator anxiety.
+ IF counter % 10000 = 0 THEN
+ RAISE NOTICE 'Migrated history for % total users', counter;
+ END IF;
+
+ counter := counter + 1;
+
+ END LOOP;
+ END LOOP;
+
+END $FUNK$;
+
+DROP FUNCTION IF EXISTS action.usr_visible_circs (INTEGER);
+DROP FUNCTION IF EXISTS action.usr_visible_circ_copies (INTEGER);
+
+-- remove user retention age checks
+CREATE OR REPLACE FUNCTION action.purge_circulations () RETURNS INT AS $func$
+DECLARE
+ org_keep_age INTERVAL;
+ org_use_last BOOL = false;
+ org_age_is_min BOOL = false;
+ org_keep_count INT;
+
+ keep_age INTERVAL;
+
+ target_acp RECORD;
+ circ_chain_head action.circulation%ROWTYPE;
+ circ_chain_tail action.circulation%ROWTYPE;
+
+ count_purged INT;
+ num_incomplete INT;
+
+ last_finished TIMESTAMP WITH TIME ZONE;
+BEGIN
+
+ count_purged := 0;
+
+ SELECT value::INTERVAL INTO org_keep_age FROM config.global_flag WHERE name = 'history.circ.retention_age' AND enabled;
+
+ SELECT value::INT INTO org_keep_count FROM config.global_flag WHERE name = 'history.circ.retention_count' AND enabled;
+ IF org_keep_count IS NULL THEN
+ RETURN count_purged; -- Gimme a count to keep, or I keep them all, forever
+ END IF;
+
+ SELECT enabled INTO org_use_last FROM config.global_flag WHERE name = 'history.circ.retention_uses_last_finished';
+ SELECT enabled INTO org_age_is_min FROM config.global_flag WHERE name = 'history.circ.retention_age_is_min';
+
+ -- First, find copies with more than keep_count non-renewal circs
+ FOR target_acp IN
+ SELECT target_copy,
+ COUNT(*) AS total_real_circs
+ FROM action.circulation
+ WHERE parent_circ IS NULL
+ AND xact_finish IS NOT NULL
+ GROUP BY target_copy
+ HAVING COUNT(*) > org_keep_count
+ LOOP
+ -- And, for those, select circs that are finished and older than keep_age
+ FOR circ_chain_head IN
+ -- For reference, the subquery uses a window function to order the circs newest to oldest and number them
+ -- The outer query then uses that information to skip the most recent set the library wants to keep
+ -- End result is we don't care what order they come out in, as they are all potentials for deletion.
+ SELECT ac.* FROM action.circulation ac JOIN (
+ SELECT rank() OVER (ORDER BY xact_start DESC), ac.id
+ FROM action.circulation ac
+ WHERE ac.target_copy = target_acp.target_copy
+ AND ac.parent_circ IS NULL
+ ORDER BY ac.xact_start ) ranked USING (id)
+ WHERE ranked.rank > org_keep_count
+ LOOP
+
+ SELECT * INTO circ_chain_tail FROM action.circ_chain(circ_chain_head.id) ORDER BY xact_start DESC LIMIT 1;
+ SELECT COUNT(CASE WHEN xact_finish IS NULL THEN 1 ELSE NULL END), MAX(xact_finish) INTO num_incomplete, last_finished FROM action.circ_chain(circ_chain_head.id);
+ CONTINUE WHEN circ_chain_tail.xact_finish IS NULL OR num_incomplete > 0;
+
+ IF NOT org_use_last THEN
+ last_finished := circ_chain_tail.xact_finish;
+ END IF;
+
+ keep_age := COALESCE( org_keep_age, '2000 years'::INTERVAL );
+
+ IF org_age_is_min THEN
+ keep_age := GREATEST( keep_age, org_keep_age );
+ END IF;
+
+ CONTINUE WHEN AGE(NOW(), last_finished) < keep_age;
+
+ -- We've passed the purging tests, purge the circ chain starting at the end
+ -- A trigger should auto-purge the rest of the chain.
+ DELETE FROM action.circulation WHERE id = circ_chain_tail.id;
+
+ count_purged := count_purged + 1;
+
+ END LOOP;
+ END LOOP;
+
+ return count_purged;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+-- delete circ history rows when a user is purged.
+CREATE OR REPLACE FUNCTION actor.usr_purge_data(
+ src_usr IN INTEGER,
+ specified_dest_usr IN INTEGER
+) RETURNS VOID AS $$
+DECLARE
+ suffix TEXT;
+ renamable_row RECORD;
+ dest_usr INTEGER;
+BEGIN
+
+ IF specified_dest_usr IS NULL THEN
+ dest_usr := 1; -- Admin user on stock installs
+ ELSE
+ dest_usr := specified_dest_usr;
+ END IF;
+
+ -- acq.*
+ UPDATE acq.fund_allocation SET allocator = dest_usr WHERE allocator = src_usr;
+ UPDATE acq.lineitem SET creator = dest_usr WHERE creator = src_usr;
+ UPDATE acq.lineitem SET editor = dest_usr WHERE editor = src_usr;
+ UPDATE acq.lineitem SET selector = dest_usr WHERE selector = src_usr;
+ UPDATE acq.lineitem_note SET creator = dest_usr WHERE creator = src_usr;
+ UPDATE acq.lineitem_note SET editor = dest_usr WHERE editor = src_usr;
+ DELETE FROM acq.lineitem_usr_attr_definition WHERE usr = src_usr;
+
+ -- Update with a rename to avoid collisions
+ FOR renamable_row in
+ SELECT id, name
+ FROM acq.picklist
+ WHERE owner = src_usr
+ LOOP
+ suffix := ' (' || src_usr || ')';
+ LOOP
+ BEGIN
+ UPDATE acq.picklist
+ SET owner = dest_usr, name = name || suffix
+ WHERE id = renamable_row.id;
+ EXCEPTION WHEN unique_violation THEN
+ suffix := suffix || ' ';
+ CONTINUE;
+ END;
+ EXIT;
+ END LOOP;
+ END LOOP;
+
+ UPDATE acq.picklist SET creator = dest_usr WHERE creator = src_usr;
+ UPDATE acq.picklist SET editor = dest_usr WHERE editor = src_usr;
+ UPDATE acq.po_note SET creator = dest_usr WHERE creator = src_usr;
+ UPDATE acq.po_note SET editor = dest_usr WHERE editor = src_usr;
+ UPDATE acq.purchase_order SET owner = dest_usr WHERE owner = src_usr;
+ UPDATE acq.purchase_order SET creator = dest_usr WHERE creator = src_usr;
+ UPDATE acq.purchase_order SET editor = dest_usr WHERE editor = src_usr;
+ UPDATE acq.claim_event SET creator = dest_usr WHERE creator = src_usr;
+
+ -- action.*
+ DELETE FROM action.circulation WHERE usr = src_usr;
+ UPDATE action.circulation SET circ_staff = dest_usr WHERE circ_staff = src_usr;
+ UPDATE action.circulation SET checkin_staff = dest_usr WHERE checkin_staff = src_usr;
+ UPDATE action.hold_notification SET notify_staff = dest_usr WHERE notify_staff = src_usr;
+ UPDATE action.hold_request SET fulfillment_staff = dest_usr WHERE fulfillment_staff = src_usr;
+ UPDATE action.hold_request SET requestor = dest_usr WHERE requestor = src_usr;
+ DELETE FROM action.hold_request WHERE usr = src_usr;
+ UPDATE action.in_house_use SET staff = dest_usr WHERE staff = src_usr;
+ UPDATE action.non_cat_in_house_use SET staff = dest_usr WHERE staff = src_usr;
+ DELETE FROM action.non_cataloged_circulation WHERE patron = src_usr;
+ UPDATE action.non_cataloged_circulation SET staff = dest_usr WHERE staff = src_usr;
+ DELETE FROM action.survey_response WHERE usr = src_usr;
+ UPDATE action.fieldset SET owner = dest_usr WHERE owner = src_usr;
+ DELETE FROM action.usr_circ_history WHERE usr = src_usr;
+
+ -- actor.*
+ DELETE FROM actor.card WHERE usr = src_usr;
+ DELETE FROM actor.stat_cat_entry_usr_map WHERE target_usr = src_usr;
+
+ -- The following update is intended to avoid transient violations of a foreign
+ -- key constraint, whereby actor.usr_address references itself. It may not be
+ -- necessary, but it does no harm.
+ UPDATE actor.usr_address SET replaces = NULL
+ WHERE usr = src_usr AND replaces IS NOT NULL;
+ DELETE FROM actor.usr_address WHERE usr = src_usr;
+ DELETE FROM actor.usr_note WHERE usr = src_usr;
+ UPDATE actor.usr_note SET creator = dest_usr WHERE creator = src_usr;
+ DELETE FROM actor.usr_org_unit_opt_in WHERE usr = src_usr;
+ UPDATE actor.usr_org_unit_opt_in SET staff = dest_usr WHERE staff = src_usr;
+ DELETE FROM actor.usr_setting WHERE usr = src_usr;
+ DELETE FROM actor.usr_standing_penalty WHERE usr = src_usr;
+ UPDATE actor.usr_standing_penalty SET staff = dest_usr WHERE staff = src_usr;
+
+ -- asset.*
+ UPDATE asset.call_number SET creator = dest_usr WHERE creator = src_usr;
+ UPDATE asset.call_number SET editor = dest_usr WHERE editor = src_usr;
+ UPDATE asset.call_number_note SET creator = dest_usr WHERE creator = src_usr;
+ UPDATE asset.copy SET creator = dest_usr WHERE creator = src_usr;
+ UPDATE asset.copy SET editor = dest_usr WHERE editor = src_usr;
+ UPDATE asset.copy_note SET creator = dest_usr WHERE creator = src_usr;
+
+ -- auditor.*
+ DELETE FROM auditor.actor_usr_address_history WHERE id = src_usr;
+ DELETE FROM auditor.actor_usr_history WHERE id = src_usr;
+ UPDATE auditor.asset_call_number_history SET creator = dest_usr WHERE creator = src_usr;
+ UPDATE auditor.asset_call_number_history SET editor = dest_usr WHERE editor = src_usr;
+ UPDATE auditor.asset_copy_history SET creator = dest_usr WHERE creator = src_usr;
+ UPDATE auditor.asset_copy_history SET editor = dest_usr WHERE editor = src_usr;
+ UPDATE auditor.biblio_record_entry_history SET creator = dest_usr WHERE creator = src_usr;
+ UPDATE auditor.biblio_record_entry_history SET editor = dest_usr WHERE editor = src_usr;
+
+ -- biblio.*
+ UPDATE biblio.record_entry SET creator = dest_usr WHERE creator = src_usr;
+ UPDATE biblio.record_entry SET editor = dest_usr WHERE editor = src_usr;
+ UPDATE biblio.record_note SET creator = dest_usr WHERE creator = src_usr;
+ UPDATE biblio.record_note SET editor = dest_usr WHERE editor = src_usr;
+
+ -- container.*
+ -- Update buckets with a rename to avoid collisions
+ FOR renamable_row in
+ SELECT id, name
+ FROM container.biblio_record_entry_bucket
+ WHERE owner = src_usr
+ LOOP
+ suffix := ' (' || src_usr || ')';
+ LOOP
+ BEGIN
+ UPDATE container.biblio_record_entry_bucket
+ SET owner = dest_usr, name = name || suffix
+ WHERE id = renamable_row.id;
+ EXCEPTION WHEN unique_violation THEN
+ suffix := suffix || ' ';
+ CONTINUE;
+ END;
+ EXIT;
+ END LOOP;
+ END LOOP;
+
+ FOR renamable_row in
+ SELECT id, name
+ FROM container.call_number_bucket
+ WHERE owner = src_usr
+ LOOP
+ suffix := ' (' || src_usr || ')';
+ LOOP
+ BEGIN
+ UPDATE container.call_number_bucket
+ SET owner = dest_usr, name = name || suffix
+ WHERE id = renamable_row.id;
+ EXCEPTION WHEN unique_violation THEN
+ suffix := suffix || ' ';
+ CONTINUE;
+ END;
+ EXIT;
+ END LOOP;
+ END LOOP;
+
+ FOR renamable_row in
+ SELECT id, name
+ FROM container.copy_bucket
+ WHERE owner = src_usr
+ LOOP
+ suffix := ' (' || src_usr || ')';
+ LOOP
+ BEGIN
+ UPDATE container.copy_bucket
+ SET owner = dest_usr, name = name || suffix
+ WHERE id = renamable_row.id;
+ EXCEPTION WHEN unique_violation THEN
+ suffix := suffix || ' ';
+ CONTINUE;
+ END;
+ EXIT;
+ END LOOP;
+ END LOOP;
+
+ FOR renamable_row in
+ SELECT id, name
+ FROM container.user_bucket
+ WHERE owner = src_usr
+ LOOP
+ suffix := ' (' || src_usr || ')';
+ LOOP
+ BEGIN
+ UPDATE container.user_bucket
+ SET owner = dest_usr, name = name || suffix
+ WHERE id = renamable_row.id;
+ EXCEPTION WHEN unique_violation THEN
+ suffix := suffix || ' ';
+ CONTINUE;
+ END;
+ EXIT;
+ END LOOP;
+ END LOOP;
+
+ DELETE FROM container.user_bucket_item WHERE target_user = src_usr;
+
+ -- money.*
+ DELETE FROM money.billable_xact WHERE usr = src_usr;
+ DELETE FROM money.collections_tracker WHERE usr = src_usr;
+ UPDATE money.collections_tracker SET collector = dest_usr WHERE collector = src_usr;
+
+ -- permission.*
+ DELETE FROM permission.usr_grp_map WHERE usr = src_usr;
+ DELETE FROM permission.usr_object_perm_map WHERE usr = src_usr;
+ DELETE FROM permission.usr_perm_map WHERE usr = src_usr;
+ DELETE FROM permission.usr_work_ou_map WHERE usr = src_usr;
+
+ -- reporter.*
+ -- Update with a rename to avoid collisions
+ BEGIN
+ FOR renamable_row in
+ SELECT id, name
+ FROM reporter.output_folder
+ WHERE owner = src_usr
+ LOOP
+ suffix := ' (' || src_usr || ')';
+ LOOP
+ BEGIN
+ UPDATE reporter.output_folder
+ SET owner = dest_usr, name = name || suffix
+ WHERE id = renamable_row.id;
+ EXCEPTION WHEN unique_violation THEN
+ suffix := suffix || ' ';
+ CONTINUE;
+ END;
+ EXIT;
+ END LOOP;
+ END LOOP;
+ EXCEPTION WHEN undefined_table THEN
+ -- do nothing
+ END;
+
+ BEGIN
+ UPDATE reporter.report SET owner = dest_usr WHERE owner = src_usr;
+ EXCEPTION WHEN undefined_table THEN
+ -- do nothing
+ END;
+
+ -- Update with a rename to avoid collisions
+ BEGIN
+ FOR renamable_row in
+ SELECT id, name
+ FROM reporter.report_folder
+ WHERE owner = src_usr
+ LOOP
+ suffix := ' (' || src_usr || ')';
+ LOOP
+ BEGIN
+ UPDATE reporter.report_folder
+ SET owner = dest_usr, name = name || suffix
+ WHERE id = renamable_row.id;
+ EXCEPTION WHEN unique_violation THEN
+ suffix := suffix || ' ';
+ CONTINUE;
+ END;
+ EXIT;
+ END LOOP;
+ END LOOP;
+ EXCEPTION WHEN undefined_table THEN
+ -- do nothing
+ END;
+
+ BEGIN
+ UPDATE reporter.schedule SET runner = dest_usr WHERE runner = src_usr;
+ EXCEPTION WHEN undefined_table THEN
+ -- do nothing
+ END;
+
+ BEGIN
+ UPDATE reporter.template SET owner = dest_usr WHERE owner = src_usr;
+ EXCEPTION WHEN undefined_table THEN
+ -- do nothing
+ END;
+
+ -- Update with a rename to avoid collisions
+ BEGIN
+ FOR renamable_row in
+ SELECT id, name
+ FROM reporter.template_folder
+ WHERE owner = src_usr
+ LOOP
+ suffix := ' (' || src_usr || ')';
+ LOOP
+ BEGIN
+ UPDATE reporter.template_folder
+ SET owner = dest_usr, name = name || suffix
+ WHERE id = renamable_row.id;
+ EXCEPTION WHEN unique_violation THEN
+ suffix := suffix || ' ';
+ CONTINUE;
+ END;
+ EXIT;
+ END LOOP;
+ END LOOP;
+ EXCEPTION WHEN undefined_table THEN
+ -- do nothing
+ END;
+
+ -- vandelay.*
+ -- Update with a rename to avoid collisions
+ FOR renamable_row in
+ SELECT id, name
+ FROM vandelay.queue
+ WHERE owner = src_usr
+ LOOP
+ suffix := ' (' || src_usr || ')';
+ LOOP
+ BEGIN
+ UPDATE vandelay.queue
+ SET owner = dest_usr, name = name || suffix
+ WHERE id = renamable_row.id;
+ EXCEPTION WHEN unique_violation THEN
+ suffix := suffix || ' ';
+ CONTINUE;
+ END;
+ EXIT;
+ END LOOP;
+ END LOOP;
+
+ -- NULL-ify addresses last so other cleanup (e.g. circ anonymization)
+ -- can access the information before deletion.
+ UPDATE actor.usr SET
+ active = FALSE,
+ card = NULL,
+ mailing_address = NULL,
+ billing_address = NULL
+ WHERE id = src_usr;
+
+END;
+$$ LANGUAGE plpgsql;
+
+SELECT evergreen.upgrade_deps_block_check('0961', :eg_version);
+
+CREATE EXTENSION IF NOT EXISTS pgcrypto;
+
+CREATE TABLE actor.passwd_type (
+ code TEXT PRIMARY KEY,
+ name TEXT UNIQUE NOT NULL,
+ login BOOLEAN NOT NULL DEFAULT FALSE,
+ regex TEXT, -- pending
+ crypt_algo TEXT, -- e.g. 'bf'
+
+ -- gen_salt() iter count used with each new salt.
+ -- A non-NULL value for iter_count is our indication the
+ -- password is salted and encrypted via crypt()
+ iter_count INTEGER CHECK (iter_count IS NULL OR iter_count > 0)
+);
+
+CREATE TABLE actor.passwd (
+ id SERIAL PRIMARY KEY,
+ usr INTEGER NOT NULL REFERENCES actor.usr(id)
+ ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ salt TEXT, -- will be NULL for non-crypt'ed passwords
+ passwd TEXT NOT NULL,
+ passwd_type TEXT NOT NULL REFERENCES actor.passwd_type(code)
+ DEFERRABLE INITIALLY DEFERRED,
+ create_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
+ edit_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
+ CONSTRAINT passwd_type_once_per_user UNIQUE (usr, passwd_type)
+);
+
+CREATE OR REPLACE FUNCTION actor.create_salt(pw_type TEXT)
+ RETURNS TEXT AS $$
+DECLARE
+ type_row actor.passwd_type%ROWTYPE;
+BEGIN
+ /* Returns a new salt based on the passwd_type encryption settings.
+ * Returns NULL If the password type is not crypt()'ed.
+ */
+
+ SELECT INTO type_row * FROM actor.passwd_type WHERE code = pw_type;
+
+ IF NOT FOUND THEN
+ RETURN EXCEPTION 'No such password type: %', pw_type;
+ END IF;
+
+ IF type_row.iter_count IS NULL THEN
+ -- This password type is unsalted. That's OK.
+ RETURN NULL;
+ END IF;
+
+ RETURN gen_salt(type_row.crypt_algo, type_row.iter_count);
+END;
+$$ LANGUAGE PLPGSQL;
+
+
+/*
+ TODO: when a user changes their password in the application, the
+ app layer has access to the bare password. At that point, we have
+ the opportunity to store the new password without the MD5(MD5())
+ intermediate hashing. Do we care? We would need a way to indicate
+ which passwords have the legacy intermediate hashing and which don't
+ so the app layer would know whether it should perform the intermediate
+ hashing. In either event, with the exception of migrate_passwd(), the
+ DB functions know or care nothing about intermediate hashing. Every
+ password is just a value that may or may not be internally crypt'ed.
+*/
+
+CREATE OR REPLACE FUNCTION actor.set_passwd(
+ pw_usr INTEGER, pw_type TEXT, new_pass TEXT, new_salt TEXT DEFAULT NULL)
+ RETURNS BOOLEAN AS $$
+DECLARE
+ pw_salt TEXT;
+ pw_text TEXT;
+BEGIN
+ /* Sets the password value, creating a new actor.passwd row if needed.
+ * If the password type supports it, the new_pass value is crypt()'ed.
+ * For crypt'ed passwords, the salt comes from one of 3 places in order:
+ * new_salt (if present), existing salt (if present), newly created
+ * salt.
+ */
+
+ IF new_salt IS NOT NULL THEN
+ pw_salt := new_salt;
+ ELSE
+ pw_salt := actor.get_salt(pw_usr, pw_type);
+
+ IF pw_salt IS NULL THEN
+ /* We have no salt for this user + type. Assume they want a
+ * new salt. If this type is unsalted, create_salt() will
+ * return NULL. */
+ pw_salt := actor.create_salt(pw_type);
+ END IF;
+ END IF;
+
+ IF pw_salt IS NULL THEN
+ pw_text := new_pass; -- unsalted, use as-is.
+ ELSE
+ pw_text := CRYPT(new_pass, pw_salt);
+ END IF;
+
+ UPDATE actor.passwd
+ SET passwd = pw_text, salt = pw_salt, edit_date = NOW()
+ WHERE usr = pw_usr AND passwd_type = pw_type;
+
+ IF NOT FOUND THEN
+ -- no password row exists for this user + type. Create one.
+ INSERT INTO actor.passwd (usr, passwd_type, salt, passwd)
+ VALUES (pw_usr, pw_type, pw_salt, pw_text);
+ END IF;
+
+ RETURN TRUE;
+END;
+$$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION actor.get_salt(pw_usr INTEGER, pw_type TEXT)
+ RETURNS TEXT AS $$
+DECLARE
+ pw_salt TEXT;
+ type_row actor.passwd_type%ROWTYPE;
+BEGIN
+ /* Returns the salt for the requested user + type. If the password
+ * type of "main" is requested and no password exists in actor.passwd,
+ * the user's existing password is migrated and the new salt is returned.
+ * Returns NULL if the password type is not crypt'ed (iter_count is NULL).
+ */
+
+ SELECT INTO pw_salt salt FROM actor.passwd
+ WHERE usr = pw_usr AND passwd_type = pw_type;
+
+ IF FOUND THEN
+ RETURN pw_salt;
+ END IF;
+
+ IF pw_type = 'main' THEN
+ -- Main password has not yet been migrated.
+ -- Do it now and return the newly created salt.
+ RETURN actor.migrate_passwd(pw_usr);
+ END IF;
+
+ -- We have no salt to return. actor.create_salt() needed.
+ RETURN NULL;
+END;
+$$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION
+ actor.migrate_passwd(pw_usr INTEGER) RETURNS TEXT AS $$
+DECLARE
+ pw_salt TEXT;
+ usr_row actor.usr%ROWTYPE;
+BEGIN
+ /* Migrates legacy actor.usr.passwd value to actor.passwd with
+ * a password type 'main' and returns the new salt. For backwards
+ * compatibility with existing CHAP-style API's, we perform a
+ * layer of intermediate MD5(MD5()) hashing. This is intermediate
+ * hashing is not required of other passwords.
+ */
+
+ -- Avoid calling get_salt() here, because it may result in a
+ -- migrate_passwd() call, creating a loop.
+ SELECT INTO pw_salt salt FROM actor.passwd
+ WHERE usr = pw_usr AND passwd_type = 'main';
+
+ -- Only migrate passwords that have not already been migrated.
+ IF FOUND THEN
+ RETURN pw_salt;
+ END IF;
+
+ SELECT INTO usr_row * FROM actor.usr WHERE id = pw_usr;
+
+ pw_salt := actor.create_salt('main');
+
+ PERFORM actor.set_passwd(
+ pw_usr, 'main', MD5(pw_salt || usr_row.passwd), pw_salt);
+
+ -- clear the existing password
+ UPDATE actor.usr SET passwd = '' WHERE id = usr_row.id;
+
+ RETURN pw_salt;
+END;
+$$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION
+ actor.verify_passwd(pw_usr INTEGER, pw_type TEXT, test_passwd TEXT)
+ RETURNS BOOLEAN AS $$
+DECLARE
+ pw_salt TEXT;
+BEGIN
+ /* Returns TRUE if the password provided matches the in-db password.
+ * If the password type is salted, we compare the output of CRYPT().
+ * NOTE: test_passwd is MD5(salt || MD5(password)) for legacy
+ * 'main' passwords.
+ */
+
+ SELECT INTO pw_salt salt FROM actor.passwd
+ WHERE usr = pw_usr AND passwd_type = pw_type;
+
+ IF NOT FOUND THEN
+ -- no such password
+ RETURN FALSE;
+ END IF;
+
+ IF pw_salt IS NULL THEN
+ -- Password is unsalted, compare the un-CRYPT'ed values.
+ RETURN EXISTS (
+ SELECT TRUE FROM actor.passwd WHERE
+ usr = pw_usr AND
+ passwd_type = pw_type AND
+ passwd = test_passwd
+ );
+ END IF;
+
+ RETURN EXISTS (
+ SELECT TRUE FROM actor.passwd WHERE
+ usr = pw_usr AND
+ passwd_type = pw_type AND
+ passwd = CRYPT(test_passwd, pw_salt)
+ );
+END;
+$$ STRICT LANGUAGE PLPGSQL;
+
+--- DATA ----------------------
+
+INSERT INTO actor.passwd_type
+ (code, name, login, crypt_algo, iter_count)
+ VALUES ('main', 'Main Login Password', TRUE, 'bf', 10);
+
+SELECT evergreen.upgrade_deps_block_check('0962', :eg_version);
+
+ALTER TABLE vandelay.import_item_attr_definition
+ ADD COLUMN parts_data TEXT;
+
+ALTER TABLE vandelay.import_item
+ ADD COLUMN parts_data TEXT;
+
+CREATE OR REPLACE FUNCTION vandelay.ingest_items ( import_id BIGINT, attr_def_id BIGINT ) RETURNS SETOF vandelay.import_item AS $$
+DECLARE
+
+ owning_lib TEXT;
+ circ_lib TEXT;
+ call_number TEXT;
+ copy_number TEXT;
+ status TEXT;
+ location TEXT;
+ circulate TEXT;
+ deposit TEXT;
+ deposit_amount TEXT;
+ ref TEXT;
+ holdable TEXT;
+ price TEXT;
+ barcode TEXT;
+ circ_modifier TEXT;
+ circ_as_type TEXT;
+ alert_message TEXT;
+ opac_visible TEXT;
+ pub_note TEXT;
+ priv_note TEXT;
+ internal_id TEXT;
+ stat_cat_data TEXT;
+ parts_data TEXT;
+
+ attr_def RECORD;
+ tmp_attr_set RECORD;
+ attr_set vandelay.import_item%ROWTYPE;
+
+ xpaths TEXT[];
+ tmp_str TEXT;
+
+BEGIN
+
+ SELECT * INTO attr_def FROM vandelay.import_item_attr_definition WHERE id = attr_def_id;
+
+ IF FOUND THEN
+
+ attr_set.definition := attr_def.id;
+
+ -- Build the combined XPath
+
+ owning_lib :=
+ CASE
+ WHEN attr_def.owning_lib IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.owning_lib ) = 1 THEN '*[@code="' || attr_def.owning_lib || '"]'
+ ELSE '*' || attr_def.owning_lib
+ END;
+
+ circ_lib :=
+ CASE
+ WHEN attr_def.circ_lib IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.circ_lib ) = 1 THEN '*[@code="' || attr_def.circ_lib || '"]'
+ ELSE '*' || attr_def.circ_lib
+ END;
+
+ call_number :=
+ CASE
+ WHEN attr_def.call_number IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.call_number ) = 1 THEN '*[@code="' || attr_def.call_number || '"]'
+ ELSE '*' || attr_def.call_number
+ END;
+
+ copy_number :=
+ CASE
+ WHEN attr_def.copy_number IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.copy_number ) = 1 THEN '*[@code="' || attr_def.copy_number || '"]'
+ ELSE '*' || attr_def.copy_number
+ END;
+
+ status :=
+ CASE
+ WHEN attr_def.status IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.status ) = 1 THEN '*[@code="' || attr_def.status || '"]'
+ ELSE '*' || attr_def.status
+ END;
+
+ location :=
+ CASE
+ WHEN attr_def.location IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.location ) = 1 THEN '*[@code="' || attr_def.location || '"]'
+ ELSE '*' || attr_def.location
+ END;
+
+ circulate :=
+ CASE
+ WHEN attr_def.circulate IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.circulate ) = 1 THEN '*[@code="' || attr_def.circulate || '"]'
+ ELSE '*' || attr_def.circulate
+ END;
+
+ deposit :=
+ CASE
+ WHEN attr_def.deposit IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.deposit ) = 1 THEN '*[@code="' || attr_def.deposit || '"]'
+ ELSE '*' || attr_def.deposit
+ END;
+
+ deposit_amount :=
+ CASE
+ WHEN attr_def.deposit_amount IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.deposit_amount ) = 1 THEN '*[@code="' || attr_def.deposit_amount || '"]'
+ ELSE '*' || attr_def.deposit_amount
+ END;
+
+ ref :=
+ CASE
+ WHEN attr_def.ref IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.ref ) = 1 THEN '*[@code="' || attr_def.ref || '"]'
+ ELSE '*' || attr_def.ref
+ END;
+
+ holdable :=
+ CASE
+ WHEN attr_def.holdable IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.holdable ) = 1 THEN '*[@code="' || attr_def.holdable || '"]'
+ ELSE '*' || attr_def.holdable
+ END;
+
+ price :=
+ CASE
+ WHEN attr_def.price IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.price ) = 1 THEN '*[@code="' || attr_def.price || '"]'
+ ELSE '*' || attr_def.price
+ END;
+
+ barcode :=
+ CASE
+ WHEN attr_def.barcode IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.barcode ) = 1 THEN '*[@code="' || attr_def.barcode || '"]'
+ ELSE '*' || attr_def.barcode
+ END;
+
+ circ_modifier :=
+ CASE
+ WHEN attr_def.circ_modifier IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.circ_modifier ) = 1 THEN '*[@code="' || attr_def.circ_modifier || '"]'
+ ELSE '*' || attr_def.circ_modifier
+ END;
+
+ circ_as_type :=
+ CASE
+ WHEN attr_def.circ_as_type IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.circ_as_type ) = 1 THEN '*[@code="' || attr_def.circ_as_type || '"]'
+ ELSE '*' || attr_def.circ_as_type
+ END;
+
+ alert_message :=
+ CASE
+ WHEN attr_def.alert_message IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.alert_message ) = 1 THEN '*[@code="' || attr_def.alert_message || '"]'
+ ELSE '*' || attr_def.alert_message
+ END;
+
+ opac_visible :=
+ CASE
+ WHEN attr_def.opac_visible IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.opac_visible ) = 1 THEN '*[@code="' || attr_def.opac_visible || '"]'
+ ELSE '*' || attr_def.opac_visible
+ END;
+
+ pub_note :=
+ CASE
+ WHEN attr_def.pub_note IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.pub_note ) = 1 THEN '*[@code="' || attr_def.pub_note || '"]'
+ ELSE '*' || attr_def.pub_note
+ END;
+ priv_note :=
+ CASE
+ WHEN attr_def.priv_note IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.priv_note ) = 1 THEN '*[@code="' || attr_def.priv_note || '"]'
+ ELSE '*' || attr_def.priv_note
+ END;
+
+ internal_id :=
+ CASE
+ WHEN attr_def.internal_id IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.internal_id ) = 1 THEN '*[@code="' || attr_def.internal_id || '"]'
+ ELSE '*' || attr_def.internal_id
+ END;
+
+ stat_cat_data :=
+ CASE
+ WHEN attr_def.stat_cat_data IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.stat_cat_data ) = 1 THEN '*[@code="' || attr_def.stat_cat_data || '"]'
+ ELSE '*' || attr_def.stat_cat_data
+ END;
+
+ parts_data :=
+ CASE
+ WHEN attr_def.parts_data IS NULL THEN 'null()'
+ WHEN LENGTH( attr_def.parts_data ) = 1 THEN '*[@code="' || attr
+ ELSE '*' || attr_def.parts_data
+ END;
+
+
+
+ xpaths := ARRAY[owning_lib, circ_lib, call_number, copy_number, status, location, circulate,
+ deposit, deposit_amount, ref, holdable, price, barcode, circ_modifier, circ_as_type,
+ alert_message, pub_note, priv_note, internal_id, stat_cat_data, parts_data, opac_visible];
+
+ FOR tmp_attr_set IN
+ SELECT *
+ FROM oils_xpath_tag_to_table( (SELECT marc FROM vandelay.queued_bib_record WHERE id = import_id), attr_def.tag, xpaths)
+ AS t( ol TEXT, clib TEXT, cn TEXT, cnum TEXT, cs TEXT, cl TEXT, circ TEXT,
+ dep TEXT, dep_amount TEXT, r TEXT, hold TEXT, pr TEXT, bc TEXT, circ_mod TEXT,
+ circ_as TEXT, amessage TEXT, note TEXT, pnote TEXT, internal_id TEXT,
+ stat_cat_data TEXT, parts_data TEXT, opac_vis TEXT )
+ LOOP
+
+ attr_set.import_error := NULL;
+ attr_set.error_detail := NULL;
+ attr_set.deposit_amount := NULL;
+ attr_set.copy_number := NULL;
+ attr_set.price := NULL;
+ attr_set.circ_modifier := NULL;
+ attr_set.location := NULL;
+ attr_set.barcode := NULL;
+ attr_set.call_number := NULL;
+
+ IF tmp_attr_set.pr != '' THEN
+ tmp_str = REGEXP_REPLACE(tmp_attr_set.pr, E'[^0-9\\.]', '', 'g');
+ IF tmp_str = '' THEN
+ attr_set.import_error := 'import.item.invalid.price';
+ attr_set.error_detail := tmp_attr_set.pr; -- original value
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ attr_set.price := tmp_str::NUMERIC(8,2);
+ END IF;
+
+ IF tmp_attr_set.dep_amount != '' THEN
+ tmp_str = REGEXP_REPLACE(tmp_attr_set.dep_amount, E'[^0-9\\.]', '', 'g');
+ IF tmp_str = '' THEN
+ attr_set.import_error := 'import.item.invalid.deposit_amount';
+ attr_set.error_detail := tmp_attr_set.dep_amount;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ attr_set.deposit_amount := tmp_str::NUMERIC(8,2);
+ END IF;
+
+ IF tmp_attr_set.cnum != '' THEN
+ tmp_str = REGEXP_REPLACE(tmp_attr_set.cnum, E'[^0-9]', '', 'g');
+ IF tmp_str = '' THEN
+ attr_set.import_error := 'import.item.invalid.copy_number';
+ attr_set.error_detail := tmp_attr_set.cnum;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ attr_set.copy_number := tmp_str::INT;
+ END IF;
+
+ IF tmp_attr_set.ol != '' THEN
+ SELECT id INTO attr_set.owning_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.ol); -- INT
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.owning_lib';
+ attr_set.error_detail := tmp_attr_set.ol;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ END IF;
+
+ IF tmp_attr_set.clib != '' THEN
+ SELECT id INTO attr_set.circ_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.clib); -- INT
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.circ_lib';
+ attr_set.error_detail := tmp_attr_set.clib;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ END IF;
+
+ IF tmp_attr_set.cs != '' THEN
+ SELECT id INTO attr_set.status FROM config.copy_status WHERE LOWER(name) = LOWER(tmp_attr_set.cs); -- INT
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.status';
+ attr_set.error_detail := tmp_attr_set.cs;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ END IF;
+
+ IF COALESCE(tmp_attr_set.circ_mod, '') = '' THEN
+
+ -- no circ mod defined, see if we should apply a default
+ SELECT INTO attr_set.circ_modifier TRIM(BOTH '"' FROM value)
+ FROM actor.org_unit_ancestor_setting(
+ 'vandelay.item.circ_modifier.default',
+ attr_set.owning_lib
+ );
+
+ -- make sure the value from the org setting is still valid
+ PERFORM 1 FROM config.circ_modifier WHERE code = attr_set.circ_modifier;
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.circ_modifier';
+ attr_set.error_detail := tmp_attr_set.circ_mod;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+
+ ELSE
+
+ SELECT code INTO attr_set.circ_modifier FROM config.circ_modifier WHERE code = tmp_attr_set.circ_mod;
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.circ_modifier';
+ attr_set.error_detail := tmp_attr_set.circ_mod;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ END IF;
+
+ IF tmp_attr_set.circ_as != '' THEN
+ SELECT code INTO attr_set.circ_as_type FROM config.coded_value_map WHERE ctype = 'item_type' AND code = tmp_attr_set.circ_as;
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.circ_as_type';
+ attr_set.error_detail := tmp_attr_set.circ_as;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ END IF;
+
+ IF COALESCE(tmp_attr_set.cl, '') = '' THEN
+ -- no location specified, see if we should apply a default
+
+ SELECT INTO attr_set.location TRIM(BOTH '"' FROM value)
+ FROM actor.org_unit_ancestor_setting(
+ 'vandelay.item.copy_location.default',
+ attr_set.owning_lib
+ );
+
+ -- make sure the value from the org setting is still valid
+ PERFORM 1 FROM asset.copy_location WHERE id = attr_set.location;
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.location';
+ attr_set.error_detail := tmp_attr_set.cs;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ ELSE
+
+ -- search up the org unit tree for a matching copy location
+ WITH RECURSIVE anscestor_depth AS (
+ SELECT ou.id,
+ out.depth AS depth,
+ ou.parent_ou
+ FROM actor.org_unit ou
+ JOIN actor.org_unit_type out ON (out.id = ou.ou_type)
+ WHERE ou.id = COALESCE(attr_set.owning_lib, attr_set.circ_lib)
+ UNION ALL
+ SELECT ou.id,
+ out.depth,
+ ou.parent_ou
+ FROM actor.org_unit ou
+ JOIN actor.org_unit_type out ON (out.id = ou.ou_type)
+ JOIN anscestor_depth ot ON (ot.parent_ou = ou.id)
+ ) SELECT cpl.id INTO attr_set.location
+ FROM anscestor_depth a
+ JOIN asset.copy_location cpl ON (cpl.owning_lib = a.id)
+ WHERE LOWER(cpl.name) = LOWER(tmp_attr_set.cl)
+ ORDER BY a.depth DESC
+ LIMIT 1;
+
+ IF NOT FOUND THEN
+ attr_set.import_error := 'import.item.invalid.location';
+ attr_set.error_detail := tmp_attr_set.cs;
+ RETURN NEXT attr_set; CONTINUE;
+ END IF;
+ END IF;
+
+ attr_set.circulate :=
+ LOWER( SUBSTRING( tmp_attr_set.circ, 1, 1)) IN ('t','y','1')
+ OR LOWER(tmp_attr_set.circ) = 'circulating'; -- BOOL
+
+ attr_set.deposit :=
+ LOWER( SUBSTRING( tmp_attr_set.dep, 1, 1 ) ) IN ('t','y','1')
+ OR LOWER(tmp_attr_set.dep) = 'deposit'; -- BOOL
+
+ attr_set.holdable :=
+ LOWER( SUBSTRING( tmp_attr_set.hold, 1, 1 ) ) IN ('t','y','1')
+ OR LOWER(tmp_attr_set.hold) = 'holdable'; -- BOOL
+
+ attr_set.opac_visible :=
+ LOWER( SUBSTRING( tmp_attr_set.opac_vis, 1, 1 ) ) IN ('t','y','1')
+ OR LOWER(tmp_attr_set.opac_vis) = 'visible'; -- BOOL
+
+ attr_set.ref :=
+ LOWER( SUBSTRING( tmp_attr_set.r, 1, 1 ) ) IN ('t','y','1')
+ OR LOWER(tmp_attr_set.r) = 'reference'; -- BOOL
+
+ attr_set.call_number := tmp_attr_set.cn; -- TEXT
+ attr_set.barcode := tmp_attr_set.bc; -- TEXT,
+ attr_set.alert_message := tmp_attr_set.amessage; -- TEXT,
+ attr_set.pub_note := tmp_attr_set.note; -- TEXT,
+ attr_set.priv_note := tmp_attr_set.pnote; -- TEXT,
+ attr_set.alert_message := tmp_attr_set.amessage; -- TEXT,
+ attr_set.internal_id := tmp_attr_set.internal_id::BIGINT;
+ attr_set.stat_cat_data := tmp_attr_set.stat_cat_data; -- TEXT,
+ attr_set.parts_data := tmp_attr_set.parts_data; -- TEXT,
+
+ RETURN NEXT attr_set;
+
+ END LOOP;
+
+ END IF;
+
+ RETURN;
+
+END;
+$$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION vandelay.ingest_bib_items ( ) RETURNS TRIGGER AS $func$
+DECLARE
+ attr_def BIGINT;
+ item_data vandelay.import_item%ROWTYPE;
+BEGIN
+
+ IF TG_OP IN ('INSERT','UPDATE') AND NEW.imported_as IS NOT NULL THEN
+ RETURN NEW;
+ END IF;
+
+ SELECT item_attr_def INTO attr_def FROM vandelay.bib_queue WHERE id = NEW.queue;
+
+ FOR item_data IN SELECT * FROM vandelay.ingest_items( NEW.id::BIGINT, attr_def ) LOOP
+ INSERT INTO vandelay.import_item (
+ record,
+ definition,
+ owning_lib,
+ circ_lib,
+ call_number,
+ copy_number,
+ status,
+ location,
+ circulate,
+ deposit,
+ deposit_amount,
+ ref,
+ holdable,
+ price,
+ barcode,
+ circ_modifier,
+ circ_as_type,
+ alert_message,
+ pub_note,
+ priv_note,
+ internal_id,
+ opac_visible,
+ stat_cat_data,
+ parts_data,
+ import_error,
+ error_detail
+ ) VALUES (
+ NEW.id,
+ item_data.definition,
+ item_data.owning_lib,
+ item_data.circ_lib,
+ item_data.call_number,
+ item_data.copy_number,
+ item_data.status,
+ item_data.location,
+ item_data.circulate,
+ item_data.deposit,
+ item_data.deposit_amount,
+ item_data.ref,
+ item_data.holdable,
+ item_data.price,
+ item_data.barcode,
+ item_data.circ_modifier,
+ item_data.circ_as_type,
+ item_data.alert_message,
+ item_data.pub_note,
+ item_data.priv_note,
+ item_data.internal_id,
+ item_data.opac_visible,
+ item_data.stat_cat_data,
+ item_data.parts_data,
+ item_data.import_error,
+ item_data.error_detail
+ );
+ END LOOP;
+
+ RETURN NULL;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+SELECT evergreen.upgrade_deps_block_check('0963', :eg_version);
+
+ALTER TABLE config.z3950_index_field_map DROP CONSTRAINT "valid_z3950_attr_type";
+
+DROP FUNCTION evergreen.z3950_attr_name_is_valid(text);
+
+CREATE OR REPLACE FUNCTION evergreen.z3950_attr_name_is_valid() RETURNS TRIGGER AS $func$
+BEGIN
+
+ PERFORM * FROM config.z3950_attr WHERE name = NEW.z3950_attr_type;
+
+ IF FOUND THEN
+ RETURN NULL;
+ END IF;
+
+ RAISE EXCEPTION '% is not a valid Z39.50 attribute type', NEW.z3950_attr_type;
+
+END;
+$func$ LANGUAGE PLPGSQL STABLE;
+
+COMMENT ON FUNCTION evergreen.z3950_attr_name_is_valid() IS $$
+Used by a config.z3950_index_field_map constraint trigger
+to verify z3950_attr_type maps.
+$$;
+
+CREATE CONSTRAINT TRIGGER valid_z3950_attr_type AFTER INSERT OR UPDATE ON config.z3950_index_field_map
+ DEFERRABLE INITIALLY DEFERRED FOR EACH ROW WHEN (NEW.z3950_attr_type IS NOT NULL)
+ EXECUTE PROCEDURE evergreen.z3950_attr_name_is_valid();
+
+SELECT evergreen.upgrade_deps_block_check('0964', :eg_version);
+
+INSERT INTO config.coded_value_map
+ (id, ctype, code, opac_visible, value, search_label) VALUES
+(712, 'search_format', 'electronic', FALSE,
+ oils_i18n_gettext(712, 'Electronic', 'ccvm', 'value'),
+ oils_i18n_gettext(712, 'Electronic', 'ccvm', 'search_label'));
+
+INSERT INTO config.composite_attr_entry_definition
+ (coded_value, definition) VALUES
+(712, '[{"_attr":"item_form","_val":"s"},{"_attr":"item_form","_val":"o"}]');
+
+
+SELECT evergreen.upgrade_deps_block_check('0965', :eg_version);
+
+UPDATE action_trigger.event_definition SET template =
+$$
+[%- USE date -%]
+[%- SET user = target.0.usr -%]
+[%- SET lib = target.0.circ_lib -%]
+[%- SET lib_addr = target.0.circ_lib.billing_address -%]
+[%- SET hours = lib.hours_of_operation -%]
+<div>
+ <style> li { padding: 8px; margin 5px; }</style>
+ <div>[% date.format %]</div>
+ <div>[% lib.name %]</div>
+ <div>[% lib_addr.street1 %] [% lib_addr.street2 %]</div>
+ <div>[% lib_addr.city %], [% lib_addr.state %] [% lib_addr.post_code %]</div>
+ <div>[% lib.phone %]</div>
+ <br/>
+
+ [% user.family_name %], [% user.first_given_name %]
+ <ol>
+ [% FOR circ IN target %]
+ [%-
+ SET idx = loop.count - 1;
+ SET udata = user_data.$idx
+ -%]
+ <li>
+ <div>[% helpers.get_copy_bib_basics(circ.target_copy.id).title %]</div>
+ <div>Barcode: [% circ.target_copy.barcode %]</div>
+ [% IF user_data.renewal_failure %]
+ <div style='color:red;'>Renewal Failed</div>
+ [% ELSE %]
+ <div>Due Date: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]</div>
+ [% END %]
+ </li>
+ [% END %]
+ </ol>
+
+ <div>
+ Library Hours
+ [%- BLOCK format_time; date.format(time _ ' 1/1/1000', format='%I:%M %p'); END -%]
+ <div>
+ Monday
+ [% PROCESS format_time time = hours.dow_0_open %]
+ [% PROCESS format_time time = hours.dow_0_close %]
+ </div>
+ <div>
+ Tuesday
+ [% PROCESS format_time time = hours.dow_1_open %]
+ [% PROCESS format_time time = hours.dow_1_close %]
+ </div>
+ <div>
+ Wednesday
+ [% PROCESS format_time time = hours.dow_2_open %]
+ [% PROCESS format_time time = hours.dow_2_close %]
+ </div>
+ <div>
+ Thursday
+ [% PROCESS format_time time = hours.dow_3_open %]
+ [% PROCESS format_time time = hours.dow_3_close %]
+ </div>
+ <div>
+ Friday
+ [% PROCESS format_time time = hours.dow_4_open %]
+ [% PROCESS format_time time = hours.dow_4_close %]
+ </div>
+ <div>
+ Saturday
+ [% PROCESS format_time time = hours.dow_5_open %]
+ [% PROCESS format_time time = hours.dow_5_close %]
+ </div>
+ <div>
+ Sunday
+ [% PROCESS format_time time = hours.dow_6_open %]
+ [% PROCESS format_time time = hours.dow_6_close %]
+ </div>
+ </div>
+</div>
+$$
+WHERE id = 10 AND template =
+$$
+[%- USE date -%]
+[%- SET user = target.0.usr -%]
+[%- SET lib = target.0.circ_lib -%]
+[%- SET lib_addr = target.0.circ_lib.billing_address -%]
+[%- SET hours = lib.hours_of_operation -%]
+<div>
+ <style> li { padding: 8px; margin 5px; }</style>
+ <div>[% date.format %]</div>
+ <div>[% lib.name %]</div>
+ <div>[% lib_addr.street1 %] [% lib_addr.street2 %]</div>
+ <div>[% lib_addr.city %], [% lib_addr.state %] [% lb_addr.post_code %]</div>
+ <div>[% lib.phone %]</div>
+ <br/>
+
+ [% user.family_name %], [% user.first_given_name %]
+ <ol>
+ [% FOR circ IN target %]
+ [%-
+ SET idx = loop.count - 1;
+ SET udata = user_data.$idx
+ -%]
+ <li>
+ <div>[% helpers.get_copy_bib_basics(circ.target_copy.id).title %]</div>
+ <div>Barcode: [% circ.target_copy.barcode %]</div>
+ [% IF user_data.renewal_failure %]
+ <div style='color:red;'>Renewal Failed</div>
+ [% ELSE %]
+ <div>Due Date: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]</div>
+ [% END %]
+ </li>
+ [% END %]
+ </ol>
+
+ <div>
+ Library Hours
+ [%- BLOCK format_time; date.format(time _ ' 1/1/1000', format='%I:%M %p'); END -%]
+ <div>
+ Monday
+ [% PROCESS format_time time = hours.dow_0_open %]
+ [% PROCESS format_time time = hours.dow_0_close %]
+ </div>
+ <div>
+ Tuesday
+ [% PROCESS format_time time = hours.dow_1_open %]
+ [% PROCESS format_time time = hours.dow_1_close %]
+ </div>
+ <div>
+ Wednesday
+ [% PROCESS format_time time = hours.dow_2_open %]
+ [% PROCESS format_time time = hours.dow_2_close %]
+ </div>
+ <div>
+ Thursday
+ [% PROCESS format_time time = hours.dow_3_open %]
+ [% PROCESS format_time time = hours.dow_3_close %]
+ </div>
+ <div>
+ Friday
+ [% PROCESS format_time time = hours.dow_4_open %]
+ [% PROCESS format_time time = hours.dow_4_close %]
+ </div>
+ <div>
+ Saturday
+ [% PROCESS format_time time = hours.dow_5_open %]
+ [% PROCESS format_time time = hours.dow_5_close %]
+ </div>
+ <div>
+ Sunday
+ [% PROCESS format_time time = hours.dow_6_open %]
+ [% PROCESS format_time time = hours.dow_6_close %]
+ </div>
+ </div>
+</div>
+$$;
+
+SELECT evergreen.upgrade_deps_block_check('0966', :eg_version); -- miker/jpringle/gmcharlt
+
+-- Allow NULL post-normalization sorters
+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 UNNEST(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 tmp_val <> '' THEN
+ -- note that a string that contains only blanks
+ -- is a valid value for some attributes
+ 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 THEN
+ DELETE FROM metabib.record_sorter WHERE source = rid AND attr = attr_def.name;
+ IF norm_attr_value[1] IS NOT NULL THEN
+ INSERT INTO metabib.record_sorter (source, attr, value) VALUES (rid, attr_def.name, norm_attr_value[1]);
+ END IF;
+ 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;
+
+-- Correct SER and COM records, add most other subfields and make them usable as CCVMs
+
+SELECT evergreen.upgrade_deps_block_check('0967', :eg_version);
+
+-- Fix SER
+DELETE FROM config.marc21_ff_pos_map WHERE fixed_field = 'Audn' AND rec_type = 'SER';
+
+
+-- Map Fields to Record Types
+-- Form was already defined but missing from COM
+INSERT INTO config.marc21_ff_pos_map (fixed_field, tag, rec_type,start_pos, length, default_val) VALUES
+ ('Form', '006', 'COM', 6, 1, ' '),
+ ('Form', '008', 'COM', 23, 1, ' '),
+
+ ('Relf', '006', 'MAP', 1, 4, ' '),
+ ('Relf', '008', 'MAP', 18, 4, ' '),
+ ('Proj', '006', 'MAP', 5, 2, ' '),
+ ('Proj', '008', 'MAP', 22, 2, ' '),
+ ('CrTp', '006', 'MAP', 8, 1, 'a'),
+ ('CrTp', '008', 'MAP', 25, 1, 'a'),
+ ('SpFm', '006', 'MAP', 16, 2, ' '),
+ ('SpFm', '008', 'MAP', 33, 2, ' '),
+ ('Relf1', '006', 'MAP', 1, 1, ' '),
+ ('Relf1', '008', 'MAP', 18, 1, ' '),
+ ('Relf2', '006', 'MAP', 2, 1, ' '),
+ ('Relf2', '008', 'MAP', 19, 1, ' '),
+ ('Relf3', '006', 'MAP', 3, 1, ' '),
+ ('Relf3', '008', 'MAP', 20, 1, ' '),
+ ('Relf4', '006', 'MAP', 4, 1, ' '),
+ ('Relf4', '008', 'MAP', 21, 1, ' '),
+ ('SpFm1', '006', 'MAP', 16, 1, ' '),
+ ('SpFm1', '008', 'MAP', 33, 1, ' '),
+ ('SpFm2', '006', 'MAP', 17, 1, ' '),
+ ('SpFm2', '008', 'MAP', 34, 1, ' '),
+
+ ('Comp', '006', 'REC', 1, 2, 'uu'),
+ ('Comp', '008', 'REC', 18, 2, 'uu'),
+ ('FMus', '006', 'REC', 3, 1, 'n'),
+ ('FMus', '008', 'REC', 20, 1, 'n'),
+ ('Part', '006', 'REC', 4, 1, 'n'),
+ ('Part', '008', 'REC', 21, 1, 'n'),
+ ('AccM', '006', 'REC', 7, 6, ' '),
+ ('AccM', '008', 'REC', 24, 6, ' '),
+ ('LTxt', '006', 'REC', 13, 2, ' '),
+ ('LTxt', '008', 'REC', 30, 2, ' '),
+ ('TrAr', '006', 'REC', 16, 1, 'n'),
+ ('TrAr', '008', 'REC', 33, 1, 'n'),
+ ('AccM1', '006', 'REC', 7, 1, ' '),
+ ('AccM1', '008', 'REC', 24, 1, ' '),
+ ('AccM2', '006', 'REC', 8, 1, ' '),
+ ('AccM2', '008', 'REC', 25, 1, ' '),
+ ('AccM3', '006', 'REC', 9, 1, ' '),
+ ('AccM3', '008', 'REC', 26, 1, ' '),
+ ('AccM4', '006', 'REC', 10, 1, ' '),
+ ('AccM4', '008', 'REC', 27, 1, ' '),
+ ('AccM5', '006', 'REC', 11, 1, ' '),
+ ('AccM5', '008', 'REC', 28, 1, ' '),
+ ('AccM6', '006', 'REC', 12, 1, ' '),
+ ('AccM6', '008', 'REC', 29, 1, ' '),
+ ('LTxt1', '006', 'REC', 13, 1, ' '),
+ ('LTxt1', '008', 'REC', 30, 1, ' '),
+ ('LTxt2', '006', 'REC', 14, 1, ' '),
+ ('LTxt2', '008', 'REC', 31, 1, ' '),
+
+ ('Comp', '006', 'SCO', 1, 2, 'uu'),
+ ('Comp', '008', 'SCO', 18, 2, 'uu'),
+ ('FMus', '006', 'SCO', 3, 1, 'u'),
+ ('FMus', '008', 'SCO', 20, 1, 'u'),
+ ('Part', '006', 'SCO', 4, 1, ' '),
+ ('Part', '008', 'SCO', 21, 1, ' '),
+ ('AccM', '006', 'SCO', 7, 6, ' '),
+ ('AccM', '008', 'SCO', 24, 6, ' '),
+ ('LTxt', '006', 'SCO', 13, 2, 'n '),
+ ('LTxt', '008', 'SCO', 30, 2, 'n '),
+ ('TrAr', '006', 'SCO', 16, 1, ' '),
+ ('TrAr', '008', 'SCO', 33, 1, ' '),
+ ('AccM1', '006', 'SCO', 7, 1, ' '),
+ ('AccM1', '008', 'SCO', 24, 1, ' '),
+ ('AccM2', '006', 'SCO', 8, 1, ' '),
+ ('AccM2', '008', 'SCO', 25, 1, ' '),
+ ('AccM3', '006', 'SCO', 9, 1, ' '),
+ ('AccM3', '008', 'SCO', 26, 1, ' '),
+ ('AccM4', '006', 'SCO', 10, 1, ' '),
+ ('AccM4', '008', 'SCO', 27, 1, ' '),
+ ('AccM5', '006', 'SCO', 11, 1, ' '),
+ ('AccM5', '008', 'SCO', 28, 1, ' '),
+ ('AccM6', '006', 'SCO', 12, 1, ' '),
+ ('AccM6', '008', 'SCO', 29, 1, ' '),
+ ('LTxt1', '006', 'SCO', 13, 1, 'n'),
+ ('LTxt1', '008', 'SCO', 30, 1, 'n'),
+ ('LTxt2', '006', 'SCO', 14, 1, 'n'),
+ ('LTxt2', '008', 'SCO', 31, 1, 'n'),
+
+ ('SrTp', '006', 'SER', 4, 1, ' '),
+ ('SrTp', '008', 'SER', 21, 1, ' '),
+ ('Orig', '006', 'SER', 5, 1, ' '),
+ ('Orig', '008', 'SER', 22, 1, ' '),
+ ('EntW', '006', 'SER', 7, 1, ' '),
+ ('EntW', '008', 'SER', 24, 1, ' '),
+
+ ('Time', '006', 'VIS', 1, 3, ' '),
+ ('Time', '008', 'VIS', 18, 3, ' '),
+ ('Tech', '006', 'VIS', 17, 1, 'n'),
+ ('Tech', '008', 'VIS', 34, 1, 'n'),
+
+ ('Ills1', '006', 'BKS', 1, 1, ' '),
+ ('Ills1', '008', 'BKS', 18, 1, ' '),
+ ('Ills2', '006', 'BKS', 2, 1, ' '),
+ ('Ills2', '008', 'BKS', 19, 1, ' '),
+ ('Ills3', '006', 'BKS', 3, 1, ' '),
+ ('Ills3', '008', 'BKS', 20, 1, ' '),
+ ('Ills4', '006', 'BKS', 4, 1, ' '),
+ ('Ills4', '008', 'BKS', 21, 1, ' '),
+ ('Cont1', '006', 'BKS', 7, 1, ' '),
+ ('Cont1', '008', 'BKS', 24, 1, ' '),
+ ('Cont2', '006', 'BKS', 8, 1, ' '),
+ ('Cont2', '008', 'BKS', 25, 1, ' '),
+ ('Cont3', '006', 'BKS', 9, 1, ' '),
+ ('Cont3', '008', 'BKS', 26, 1, ' '),
+ ('Cont4', '006', 'BKS', 10, 1, ' '),
+ ('Cont4', '008', 'BKS', 27, 1, ' '),
+
+ ('Cont1', '006', 'SER', 8, 1, ' '),
+ ('Cont1', '008', 'SER', 25, 1, ' '),
+ ('Cont2', '006', 'SER', 9, 1, ' '),
+ ('Cont2', '008', 'SER', 26, 1, ' '),
+ ('Cont3', '006', 'SER', 10, 1, ' '),
+ ('Cont3', '008', 'SER', 27, 1, ' ');
+
+
+-- Add record_attr_definitions
+-- The xxx1,2,etc. are for multi-position single character code fields.
+INSERT INTO config.record_attr_definition (name,label,fixed_field) VALUES
+ ('accm','AccM','AccM'),
+ ('comp','Comp','Comp'),
+ ('crtp','CrTp','CrTp'),
+ ('entw','EntW','EntW'),
+ ('cont','Cont','Cont'),
+ ('fmus','FMus','FMus'),
+ ('ltxt','LTxt','LTxt'),
+ ('orig','Orig','Orig'),
+ ('part','Part','Part'),
+ ('proj','Proj','Proj'),
+ ('relf','Relf','Relf'),
+ ('spfm','SpFm','SpFm'),
+ ('srtp','SrTp','SrTp'),
+ ('tech','Tech','Tech'),
+ ('trar','TrAr','TrAr'),
+ ('accm1','AccM(1)','AccM1'),
+ ('accm2','AccM(2)','AccM2'),
+ ('accm3','AccM(3)','AccM3'),
+ ('accm4','AccM(4)','AccM4'),
+ ('accm5','AccM(5)','AccM5'),
+ ('accm6','AccM(6)','AccM6'),
+ ('cont1','Cont(1)','Cont1'),
+ ('cont2','Cont(2)','Cont2'),
+ ('cont3','Cont(3)','Cont3'),
+ ('cont4','Cont(4)','Cont4'),
+ ('ills1','Ills(1)','Ills1'),
+ ('ills2','Ills(2)','Ills2'),
+ ('ills3','Ills(3)','Ills3'),
+ ('ills4','Ills(4)','Ills4'),
+ ('ltxt1','LTxt(1)','LTxt1'),
+ ('ltxt2','LTxt(2)','LTxt2'),
+ ('relf1','Relf(1)','Relf1'),
+ ('relf2','Relf(2)','Relf2'),
+ ('relf3','Relf(3)','Relf3'),
+ ('relf4','Relf(4)','Relf4'),
+ ('spfm1','SpFm(1)','SpFm1'),
+ ('spfm2','SpFm(2)','SpFm2');
+
+UPDATE config.record_attr_definition SET composite = TRUE WHERE name IN ('accm', 'cont', 'ills', 'ltxt', 'relf', 'spfm');
+
+-- "Next" id for stock config.coded_value_map is 634 as of 7/16/15, but there's an incoming patch that takes 634-711
+INSERT INTO config.coded_value_map (id, ctype, code, value) VALUES
+ (1735, 'accm', ' ', oils_i18n_gettext('1735', 'No accompanying matter', 'ccvm', 'value')),
+ (713, 'accm', 'a', oils_i18n_gettext('713', 'Discography', 'ccvm', 'value')),
+ (714, 'accm', 'b', oils_i18n_gettext('714', 'Bibliography', 'ccvm', 'value')),
+ (715, 'accm', 'c', oils_i18n_gettext('715', 'Thematic index', 'ccvm', 'value')),
+ (716, 'accm', 'd', oils_i18n_gettext('716', 'Libretto or text', 'ccvm', 'value')),
+ (717, 'accm', 'e', oils_i18n_gettext('717', 'Biography of composer or author', 'ccvm', 'value')),
+ (718, 'accm', 'f', oils_i18n_gettext('718', 'Biography or performer or history of ensemble', 'ccvm', 'value')),
+ (719, 'accm', 'g', oils_i18n_gettext('719', 'Technical and/or historical information on instruments', 'ccvm', 'value')),
+ (720, 'accm', 'h', oils_i18n_gettext('720', 'Technical information on music', 'ccvm', 'value')),
+ (721, 'accm', 'i', oils_i18n_gettext('721', 'Historical information', 'ccvm', 'value')),
+ (722, 'accm', 'k', oils_i18n_gettext('722', 'Ethnological information', 'ccvm', 'value')),
+ (723, 'accm', 'r', oils_i18n_gettext('723', 'Instructional materials', 'ccvm', 'value')),
+ (724, 'accm', 's', oils_i18n_gettext('724', 'Music', 'ccvm', 'value')),
+ (725, 'accm', 'z', oils_i18n_gettext('725', 'Other accompanying matter', 'ccvm', 'value')),
+
+ (726, 'comp', ' ', oils_i18n_gettext('726', 'No information supplied', 'ccvm', 'value')),
+ (727, 'comp', 'an', oils_i18n_gettext('727', 'Anthems', 'ccvm', 'value')),
+ (728, 'comp', 'bd', oils_i18n_gettext('728', 'Ballads', 'ccvm', 'value')),
+ (729, 'comp', 'bt', oils_i18n_gettext('729', 'Ballets', 'ccvm', 'value')),
+ (730, 'comp', 'bg', oils_i18n_gettext('730', 'Bluegrass music', 'ccvm', 'value')),
+ (731, 'comp', 'bl', oils_i18n_gettext('731', 'Blues', 'ccvm', 'value')),
+ (732, 'comp', 'cn', oils_i18n_gettext('732', 'Canons and rounds', 'ccvm', 'value')),
+ (733, 'comp', 'ct', oils_i18n_gettext('733', 'Cantatas', 'ccvm', 'value')),
+ (734, 'comp', 'cz', oils_i18n_gettext('734', 'Canzonas', 'ccvm', 'value')),
+ (735, 'comp', 'cr', oils_i18n_gettext('735', 'Carols', 'ccvm', 'value')),
+ (736, 'comp', 'ca', oils_i18n_gettext('736', 'Chaconnes', 'ccvm', 'value')),
+ (737, 'comp', 'cs', oils_i18n_gettext('737', 'Chance compositions', 'ccvm', 'value')),
+ (738, 'comp', 'cp', oils_i18n_gettext('738', 'Chansons, Polyphonic', 'ccvm', 'value')),
+ (739, 'comp', 'cc', oils_i18n_gettext('739', 'Chant, Christian', 'ccvm', 'value')),
+ (740, 'comp', 'cb', oils_i18n_gettext('740', 'Chants, other', 'ccvm', 'value')),
+ (741, 'comp', 'cl', oils_i18n_gettext('741', 'Chorale preludes', 'ccvm', 'value')),
+ (742, 'comp', 'ch', oils_i18n_gettext('742', 'Chorales', 'ccvm', 'value')),
+ (743, 'comp', 'cg', oils_i18n_gettext('743', 'Concerti grossi', 'ccvm', 'value')),
+ (744, 'comp', 'co', oils_i18n_gettext('744', 'Concertos', 'ccvm', 'value')),
+ (745, 'comp', 'cy', oils_i18n_gettext('745', 'Country music', 'ccvm', 'value')),
+ (746, 'comp', 'df', oils_i18n_gettext('746', 'Dance forms', 'ccvm', 'value')),
+ (747, 'comp', 'dv', oils_i18n_gettext('747', 'Divertimentos, serenades, cassations, divertissements, and notturni', 'ccvm', 'value')),
+ (748, 'comp', 'ft', oils_i18n_gettext('748', 'Fantasias', 'ccvm', 'value')),
+ (749, 'comp', 'fl', oils_i18n_gettext('749', 'Flamenco', 'ccvm', 'value')),
+ (750, 'comp', 'fm', oils_i18n_gettext('750', 'Folk music', 'ccvm', 'value')),
+ (751, 'comp', 'fg', oils_i18n_gettext('751', 'Fugues', 'ccvm', 'value')),
+ (752, 'comp', 'gm', oils_i18n_gettext('752', 'Gospel music', 'ccvm', 'value')),
+ (753, 'comp', 'hy', oils_i18n_gettext('753', 'Hymns', 'ccvm', 'value')),
+ (754, 'comp', 'jz', oils_i18n_gettext('754', 'Jazz', 'ccvm', 'value')),
+ (755, 'comp', 'md', oils_i18n_gettext('755', 'Madrigals', 'ccvm', 'value')),
+ (756, 'comp', 'mr', oils_i18n_gettext('756', 'Marches', 'ccvm', 'value')),
+ (757, 'comp', 'ms', oils_i18n_gettext('757', 'Masses', 'ccvm', 'value')),
+ (758, 'comp', 'mz', oils_i18n_gettext('758', 'Mazurkas', 'ccvm', 'value')),
+ (759, 'comp', 'mi', oils_i18n_gettext('759', 'Minuets', 'ccvm', 'value')),
+ (760, 'comp', 'mo', oils_i18n_gettext('760', 'Motets', 'ccvm', 'value')),
+ (761, 'comp', 'mp', oils_i18n_gettext('761', 'Motion picture music', 'ccvm', 'value')),
+ (762, 'comp', 'mu', oils_i18n_gettext('762', 'Multiple forms', 'ccvm', 'value')),
+ (763, 'comp', 'mc', oils_i18n_gettext('763', 'Musical reviews and comedies', 'ccvm', 'value')),
+ (764, 'comp', 'nc', oils_i18n_gettext('764', 'Nocturnes', 'ccvm', 'value')),
+ (765, 'comp', 'nn', oils_i18n_gettext('765', 'Not applicable', 'ccvm', 'value')),
+ (766, 'comp', 'op', oils_i18n_gettext('766', 'Operas', 'ccvm', 'value')),
+ (767, 'comp', 'or', oils_i18n_gettext('767', 'Oratorios', 'ccvm', 'value')),
+ (768, 'comp', 'ov', oils_i18n_gettext('768', 'Overtures', 'ccvm', 'value')),
+ (769, 'comp', 'pt', oils_i18n_gettext('769', 'Part-songs', 'ccvm', 'value')),
+ (770, 'comp', 'ps', oils_i18n_gettext('770', 'Passacaglias', 'ccvm', 'value')),
+ (771, 'comp', 'pm', oils_i18n_gettext('771', 'Passion music', 'ccvm', 'value')),
+ (772, 'comp', 'pv', oils_i18n_gettext('772', 'Pavans', 'ccvm', 'value')),
+ (773, 'comp', 'po', oils_i18n_gettext('773', 'Polonaises', 'ccvm', 'value')),
+ (774, 'comp', 'pp', oils_i18n_gettext('774', 'Popular music', 'ccvm', 'value')),
+ (775, 'comp', 'pr', oils_i18n_gettext('775', 'Preludes', 'ccvm', 'value')),
+ (776, 'comp', 'pg', oils_i18n_gettext('776', 'Program music', 'ccvm', 'value')),
+ (777, 'comp', 'rg', oils_i18n_gettext('777', 'Ragtime music', 'ccvm', 'value')),
+ (778, 'comp', 'rq', oils_i18n_gettext('778', 'Requiems', 'ccvm', 'value')),
+ (779, 'comp', 'rp', oils_i18n_gettext('779', 'Rhapsodies', 'ccvm', 'value')),
+ (780, 'comp', 'ri', oils_i18n_gettext('780', 'Ricercars', 'ccvm', 'value')),
+ (781, 'comp', 'rc', oils_i18n_gettext('781', 'Rock music', 'ccvm', 'value')),
+ (782, 'comp', 'rd', oils_i18n_gettext('782', 'Rondos', 'ccvm', 'value')),
+ (783, 'comp', 'sn', oils_i18n_gettext('783', 'Sonatas', 'ccvm', 'value')),
+ (784, 'comp', 'sg', oils_i18n_gettext('784', 'Songs', 'ccvm', 'value')),
+ (785, 'comp', 'sd', oils_i18n_gettext('785', 'Square dance music', 'ccvm', 'value')),
+ (786, 'comp', 'st', oils_i18n_gettext('786', 'Studies and exercises', 'ccvm', 'value')),
+ (787, 'comp', 'su', oils_i18n_gettext('787', 'Suites', 'ccvm', 'value')),
+ (788, 'comp', 'sp', oils_i18n_gettext('788', 'Symphonic poems', 'ccvm', 'value')),
+ (789, 'comp', 'sy', oils_i18n_gettext('789', 'Symphonies', 'ccvm', 'value')),
+ (790, 'comp', 'tl', oils_i18n_gettext('790', 'Teatro lirico', 'ccvm', 'value')),
+ (791, 'comp', 'tc', oils_i18n_gettext('791', 'Toccatas', 'ccvm', 'value')),
+ (792, 'comp', 'ts', oils_i18n_gettext('792', 'Trio-sonatas', 'ccvm', 'value')),
+ (793, 'comp', 'uu', oils_i18n_gettext('793', 'Unknown', 'ccvm', 'value')),
+ (794, 'comp', 'vi', oils_i18n_gettext('794', 'Villancicos', 'ccvm', 'value')),
+ (795, 'comp', 'vr', oils_i18n_gettext('795', 'Variations', 'ccvm', 'value')),
+ (796, 'comp', 'wz', oils_i18n_gettext('796', 'Waltzes', 'ccvm', 'value')),
+ (797, 'comp', 'za', oils_i18n_gettext('797', 'Zarzuelas', 'ccvm', 'value')),
+ (798, 'comp', 'zz', oils_i18n_gettext('798', 'Other forms', 'ccvm', 'value')),
+
+ (799, 'crtp', 'a', oils_i18n_gettext('799', 'Single map', 'ccvm', 'value')),
+ (800, 'crtp', 'b', oils_i18n_gettext('800', 'Map series', 'ccvm', 'value')),
+ (801, 'crtp', 'c', oils_i18n_gettext('801', 'Map serial', 'ccvm', 'value')),
+ (802, 'crtp', 'd', oils_i18n_gettext('802', 'Globe', 'ccvm', 'value')),
+ (803, 'crtp', 'e', oils_i18n_gettext('803', 'Atlas', 'ccvm', 'value')),
+ (804, 'crtp', 'f', oils_i18n_gettext('804', 'Separate supplement to another work', 'ccvm', 'value')),
+ (805, 'crtp', 'g', oils_i18n_gettext('805', 'Bound as part of another work', 'ccvm', 'value')),
+ (806, 'crtp', 'u', oils_i18n_gettext('806', 'Unknown', 'ccvm', 'value')),
+ (807, 'crtp', 'z', oils_i18n_gettext('807', 'Other', 'ccvm', 'value')),
+
+ (808, 'entw', ' ', oils_i18n_gettext('808', 'Not specified', 'ccvm', 'value')),
+ (809, 'entw', 'a', oils_i18n_gettext('809', 'Abstracts/summaries', 'ccvm', 'value')),
+ (810, 'entw', 'b', oils_i18n_gettext('810', 'Bibliographies', 'ccvm', 'value')),
+ (811, 'entw', 'c', oils_i18n_gettext('811', 'Catalogs', 'ccvm', 'value')),
+ (812, 'entw', 'd', oils_i18n_gettext('812', 'Dictionaries', 'ccvm', 'value')),
+ (813, 'entw', 'e', oils_i18n_gettext('813', 'Encyclopedias', 'ccvm', 'value')),
+ (814, 'entw', 'f', oils_i18n_gettext('814', 'Handbooks', 'ccvm', 'value')),
+ (815, 'entw', 'g', oils_i18n_gettext('815', 'Legal articles', 'ccvm', 'value')),
+ (816, 'entw', 'h', oils_i18n_gettext('816', 'Biography', 'ccvm', 'value')),
+ (817, 'entw', 'i', oils_i18n_gettext('817', 'Indexes', 'ccvm', 'value')),
+ (818, 'entw', 'k', oils_i18n_gettext('818', 'Discographies', 'ccvm', 'value')),
+ (819, 'entw', 'l', oils_i18n_gettext('819', 'Legislation', 'ccvm', 'value')),
+ (820, 'entw', 'm', oils_i18n_gettext('820', 'Theses', 'ccvm', 'value')),
+ (821, 'entw', 'n', oils_i18n_gettext('821', 'Surveys of the literature in a subject area', 'ccvm', 'value')),
+ (822, 'entw', 'o', oils_i18n_gettext('822', 'Reviews', 'ccvm', 'value')),
+ (823, 'entw', 'p', oils_i18n_gettext('823', 'Programmed texts', 'ccvm', 'value')),
+ (824, 'entw', 'q', oils_i18n_gettext('824', 'Filmographies', 'ccvm', 'value')),
+ (825, 'entw', 'r', oils_i18n_gettext('825', 'Directories', 'ccvm', 'value')),
+ (826, 'entw', 's', oils_i18n_gettext('826', 'Statistics', 'ccvm', 'value')),
+ (827, 'entw', 't', oils_i18n_gettext('827', 'Technical reports', 'ccvm', 'value')),
+ (828, 'entw', 'u', oils_i18n_gettext('828', 'Standards/specifications', 'ccvm', 'value')),
+ (829, 'entw', 'v', oils_i18n_gettext('829', 'Legal cases and case notes', 'ccvm', 'value')),
+ (830, 'entw', 'w', oils_i18n_gettext('830', 'Law reports and digests', 'ccvm', 'value')),
+ (831, 'entw', 'y', oils_i18n_gettext('831', 'Yearbooks', 'ccvm', 'value')),
+ (832, 'entw', 'z', oils_i18n_gettext('832', 'Treaties', 'ccvm', 'value')),
+ (833, 'entw', '5', oils_i18n_gettext('833', 'Calendars', 'ccvm', 'value')),
+ (834, 'entw', '6', oils_i18n_gettext('834', 'Comics/graphic novels', 'ccvm', 'value')),
+
+ (835, 'cont', ' ', oils_i18n_gettext('835', 'Not specified', 'ccvm', 'value')),
+ (836, 'cont', 'a', oils_i18n_gettext('836', 'Abstracts/summaries', 'ccvm', 'value')),
+ (837, 'cont', 'b', oils_i18n_gettext('837', 'Bibliographies', 'ccvm', 'value')),
+ (838, 'cont', 'c', oils_i18n_gettext('838', 'Catalogs', 'ccvm', 'value')),
+ (839, 'cont', 'd', oils_i18n_gettext('839', 'Dictionaries', 'ccvm', 'value')),
+ (840, 'cont', 'e', oils_i18n_gettext('840', 'Encyclopedias', 'ccvm', 'value')),
+ (841, 'cont', 'f', oils_i18n_gettext('841', 'Handbooks', 'ccvm', 'value')),
+ (842, 'cont', 'g', oils_i18n_gettext('842', 'Legal articles', 'ccvm', 'value')),
+ (843, 'cont', 'h', oils_i18n_gettext('843', 'Biography', 'ccvm', 'value')),
+ (844, 'cont', 'i', oils_i18n_gettext('844', 'Indexes', 'ccvm', 'value')),
+ (845, 'cont', 'j', oils_i18n_gettext('845', 'Patent document', 'ccvm', 'value')),
+ (846, 'cont', 'k', oils_i18n_gettext('846', 'Discographies', 'ccvm', 'value')),
+ (847, 'cont', 'l', oils_i18n_gettext('847', 'Legislation', 'ccvm', 'value')),
+ (848, 'cont', 'm', oils_i18n_gettext('848', 'Theses', 'ccvm', 'value')),
+ (849, 'cont', 'n', oils_i18n_gettext('849', 'Surveys of the literature in a subject area', 'ccvm', 'value')),
+ (850, 'cont', 'o', oils_i18n_gettext('850', 'Reviews', 'ccvm', 'value')),
+ (851, 'cont', 'p', oils_i18n_gettext('851', 'Programmed texts', 'ccvm', 'value')),
+ (852, 'cont', 'q', oils_i18n_gettext('852', 'Filmographies', 'ccvm', 'value')),
+ (853, 'cont', 'r', oils_i18n_gettext('853', 'Directories', 'ccvm', 'value')),
+ (854, 'cont', 's', oils_i18n_gettext('854', 'Statistics', 'ccvm', 'value')),
+ (855, 'cont', 't', oils_i18n_gettext('855', 'Technical reports', 'ccvm', 'value')),
+ (856, 'cont', 'u', oils_i18n_gettext('856', 'Standards/specifications', 'ccvm', 'value')),
+ (857, 'cont', 'v', oils_i18n_gettext('857', 'Legal cases and case notes', 'ccvm', 'value')),
+ (858, 'cont', 'w', oils_i18n_gettext('858', 'Law reports and digests', 'ccvm', 'value')),
+ (859, 'cont', 'x', oils_i18n_gettext('859', 'Other reports', 'ccvm', 'value')),
+ (860, 'cont', 'y', oils_i18n_gettext('860', 'Yearbooks', 'ccvm', 'value')),
+ (861, 'cont', 'z', oils_i18n_gettext('861', 'Treaties', 'ccvm', 'value')),
+ (862, 'cont', '2', oils_i18n_gettext('862', 'Offprints', 'ccvm', 'value')),
+ (863, 'cont', '5', oils_i18n_gettext('863', 'Calendars', 'ccvm', 'value')),
+ (864, 'cont', '6', oils_i18n_gettext('864', 'Comics/graphic novels', 'ccvm', 'value')),
+
+ (865, 'fmus', ' ', oils_i18n_gettext('865', 'Information not supplied', 'ccvm', 'value')),
+ (866, 'fmus', 'a', oils_i18n_gettext('866', 'Full score', 'ccvm', 'value')),
+ (867, 'fmus', 'b', oils_i18n_gettext('867', 'Full score, miniature or study size', 'ccvm', 'value')),
+ (868, 'fmus', 'c', oils_i18n_gettext('868', 'Accompaniment reduced for keyboard', 'ccvm', 'value')),
+ (869, 'fmus', 'd', oils_i18n_gettext('869', 'Voice score with accompaniment omitted', 'ccvm', 'value')),
+ (870, 'fmus', 'e', oils_i18n_gettext('870', 'Condensed score or piano-conductor score', 'ccvm', 'value')),
+ (871, 'fmus', 'g', oils_i18n_gettext('871', 'Close score', 'ccvm', 'value')),
+ (872, 'fmus', 'h', oils_i18n_gettext('872', 'Chorus score', 'ccvm', 'value')),
+ (873, 'fmus', 'i', oils_i18n_gettext('873', 'Condensed score', 'ccvm', 'value')),
+ (874, 'fmus', 'j', oils_i18n_gettext('874', 'Performer-conductor part', 'ccvm', 'value')),
+ (875, 'fmus', 'k', oils_i18n_gettext('875', 'Vocal score', 'ccvm', 'value')),
+ (876, 'fmus', 'l', oils_i18n_gettext('876', 'Score', 'ccvm', 'value')),
+ (877, 'fmus', 'm', oils_i18n_gettext('877', 'Multiple score formats', 'ccvm', 'value')),
+ (878, 'fmus', 'n', oils_i18n_gettext('878', 'Not applicable', 'ccvm', 'value')),
+ (879, 'fmus', 'u', oils_i18n_gettext('879', 'Unknown', 'ccvm', 'value')),
+ (880, 'fmus', 'z', oils_i18n_gettext('880', 'Other', 'ccvm', 'value')),
+
+ (881, 'ltxt', ' ', oils_i18n_gettext('881', 'Item is a music sound recording', 'ccvm', 'value')),
+ (882, 'ltxt', 'a', oils_i18n_gettext('882', 'Autobiography', 'ccvm', 'value')),
+ (883, 'ltxt', 'b', oils_i18n_gettext('883', 'Biography', 'ccvm', 'value')),
+ (884, 'ltxt', 'c', oils_i18n_gettext('884', 'Conference proceedings', 'ccvm', 'value')),
+ (885, 'ltxt', 'd', oils_i18n_gettext('885', 'Drama', 'ccvm', 'value')),
+ (886, 'ltxt', 'e', oils_i18n_gettext('886', 'Essays', 'ccvm', 'value')),
+ (887, 'ltxt', 'f', oils_i18n_gettext('887', 'Fiction', 'ccvm', 'value')),
+ (888, 'ltxt', 'g', oils_i18n_gettext('888', 'Reporting', 'ccvm', 'value')),
+ (889, 'ltxt', 'h', oils_i18n_gettext('889', 'History', 'ccvm', 'value')),
+ (890, 'ltxt', 'i', oils_i18n_gettext('890', 'Instruction', 'ccvm', 'value')),
+ (891, 'ltxt', 'j', oils_i18n_gettext('891', 'Language instruction', 'ccvm', 'value')),
+ (892, 'ltxt', 'k', oils_i18n_gettext('892', 'Comedy', 'ccvm', 'value')),
+ (893, 'ltxt', 'l', oils_i18n_gettext('893', 'Lectures, speeches', 'ccvm', 'value')),
+ (894, 'ltxt', 'm', oils_i18n_gettext('894', 'Memoirs', 'ccvm', 'value')),
+ (895, 'ltxt', 'n', oils_i18n_gettext('895', 'Not applicable', 'ccvm', 'value')),
+ (896, 'ltxt', 'o', oils_i18n_gettext('896', 'Folktales', 'ccvm', 'value')),
+ (897, 'ltxt', 'p', oils_i18n_gettext('897', 'Poetry', 'ccvm', 'value')),
+ (898, 'ltxt', 'r', oils_i18n_gettext('898', 'Rehearsals', 'ccvm', 'value')),
+ (899, 'ltxt', 's', oils_i18n_gettext('899', 'Sounds', 'ccvm', 'value')),
+ (900, 'ltxt', 't', oils_i18n_gettext('900', 'Interviews', 'ccvm', 'value')),
+ (901, 'ltxt', 'z', oils_i18n_gettext('901', 'Other', 'ccvm', 'value')),
+
+ (902, 'orig', ' ', oils_i18n_gettext('902', 'None of the following', 'ccvm', 'value')),
+ (903, 'orig', 'a', oils_i18n_gettext('903', 'Microfilm', 'ccvm', 'value')),
+ (904, 'orig', 'b', oils_i18n_gettext('904', 'Microfiche', 'ccvm', 'value')),
+ (905, 'orig', 'c', oils_i18n_gettext('905', 'Microopaque', 'ccvm', 'value')),
+ (906, 'orig', 'd', oils_i18n_gettext('906', 'Large print', 'ccvm', 'value')),
+ (907, 'orig', 'e', oils_i18n_gettext('907', 'Newspaper format', 'ccvm', 'value')),
+ (908, 'orig', 'f', oils_i18n_gettext('908', 'Braille', 'ccvm', 'value')),
+ (909, 'orig', 'o', oils_i18n_gettext('909', 'Online', 'ccvm', 'value')),
+ (910, 'orig', 'q', oils_i18n_gettext('910', 'Direct electronic', 'ccvm', 'value')),
+ (911, 'orig', 's', oils_i18n_gettext('911', 'Electronic', 'ccvm', 'value')),
+
+ (912, 'part', ' ', oils_i18n_gettext('912', 'No parts in hand or not specified', 'ccvm', 'value')),
+ (913, 'part', 'd', oils_i18n_gettext('913', 'Instrumental and vocal parts', 'ccvm', 'value')),
+ (914, 'part', 'e', oils_i18n_gettext('914', 'Instrumental parts', 'ccvm', 'value')),
+ (915, 'part', 'f', oils_i18n_gettext('915', 'Vocal parts', 'ccvm', 'value')),
+ (916, 'part', 'n', oils_i18n_gettext('916', 'Not Applicable', 'ccvm', 'value')),
+ (917, 'part', 'u', oils_i18n_gettext('917', 'Unknown', 'ccvm', 'value')),
+
+ (918, 'proj', ' ', oils_i18n_gettext('918', 'Project not specified', 'ccvm', 'value')),
+ (919, 'proj', 'aa', oils_i18n_gettext('919', 'Aitoff', 'ccvm', 'value')),
+ (920, 'proj', 'ab', oils_i18n_gettext('920', 'Gnomic', 'ccvm', 'value')),
+ (921, 'proj', 'ac', oils_i18n_gettext('921', 'Lambert''s azimuthal equal area', 'ccvm', 'value')),
+ (922, 'proj', 'ad', oils_i18n_gettext('922', 'Orthographic', 'ccvm', 'value')),
+ (923, 'proj', 'ae', oils_i18n_gettext('923', 'Azimuthal equidistant', 'ccvm', 'value')),
+ (924, 'proj', 'af', oils_i18n_gettext('924', 'Stereographic', 'ccvm', 'value')),
+ (925, 'proj', 'ag', oils_i18n_gettext('925', 'General vertical near-sided', 'ccvm', 'value')),
+ (926, 'proj', 'am', oils_i18n_gettext('926', 'Modified stereographic for Alaska', 'ccvm', 'value')),
+ (927, 'proj', 'an', oils_i18n_gettext('927', 'Chamberlin trimetric', 'ccvm', 'value')),
+ (928, 'proj', 'ap', oils_i18n_gettext('928', 'Polar stereographic', 'ccvm', 'value')),
+ (929, 'proj', 'au', oils_i18n_gettext('929', 'Azimuthal, specific type unknown', 'ccvm', 'value')),
+ (930, 'proj', 'az', oils_i18n_gettext('930', 'Azimuthal, other', 'ccvm', 'value')),
+ (931, 'proj', 'ba', oils_i18n_gettext('931', 'Gall', 'ccvm', 'value')),
+ (932, 'proj', 'bb', oils_i18n_gettext('932', 'Goode''s homolographic', 'ccvm', 'value')),
+ (933, 'proj', 'bc', oils_i18n_gettext('933', 'Lambert''s cylindrical equal area', 'ccvm', 'value')),
+ (934, 'proj', 'bd', oils_i18n_gettext('934', 'Mercator', 'ccvm', 'value')),
+ (935, 'proj', 'be', oils_i18n_gettext('935', 'Miller', 'ccvm', 'value')),
+ (936, 'proj', 'bf', oils_i18n_gettext('936', 'Mollweide', 'ccvm', 'value')),
+ (937, 'proj', 'bg', oils_i18n_gettext('937', 'Sinusoidal', 'ccvm', 'value')),
+ (938, 'proj', 'bh', oils_i18n_gettext('938', 'Transverse Mercator', 'ccvm', 'value')),
+ (939, 'proj', 'bi', oils_i18n_gettext('939', 'Gauss-Kruger', 'ccvm', 'value')),
+ (940, 'proj', 'bj', oils_i18n_gettext('940', 'Equirectangular', 'ccvm', 'value')),
+ (941, 'proj', 'bk', oils_i18n_gettext('941', 'Krovak', 'ccvm', 'value')),
+ (942, 'proj', 'bl', oils_i18n_gettext('942', 'Cassini-Soldner', 'ccvm', 'value')),
+ (943, 'proj', 'bo', oils_i18n_gettext('943', 'Oblique Mercator', 'ccvm', 'value')),
+ (944, 'proj', 'br', oils_i18n_gettext('944', 'Robinson', 'ccvm', 'value')),
+ (945, 'proj', 'bs', oils_i18n_gettext('945', 'Space oblique Mercator', 'ccvm', 'value')),
+ (946, 'proj', 'bu', oils_i18n_gettext('946', 'Cylindrical, specific type unknown', 'ccvm', 'value')),
+ (947, 'proj', 'bz', oils_i18n_gettext('947', 'Cylindrical, other', 'ccvm', 'value')),
+ (948, 'proj', 'ca', oils_i18n_gettext('948', 'Alber''s equal area', 'ccvm', 'value')),
+ (949, 'proj', 'cb', oils_i18n_gettext('949', 'Bonne', 'ccvm', 'value')),
+ (950, 'proj', 'cc', oils_i18n_gettext('950', 'Lambert''s conformal conic', 'ccvm', 'value')),
+ (951, 'proj', 'ce', oils_i18n_gettext('951', 'Equidistant conic', 'ccvm', 'value')),
+ (952, 'proj', 'cp', oils_i18n_gettext('952', 'Polyconic', 'ccvm', 'value')),
+ (953, 'proj', 'cu', oils_i18n_gettext('953', 'Conic, specific type unknown', 'ccvm', 'value')),
+ (954, 'proj', 'cz', oils_i18n_gettext('954', 'Conic, other', 'ccvm', 'value')),
+ (955, 'proj', 'da', oils_i18n_gettext('955', 'Armadillo', 'ccvm', 'value')),
+ (956, 'proj', 'db', oils_i18n_gettext('956', 'Butterfly', 'ccvm', 'value')),
+ (957, 'proj', 'dc', oils_i18n_gettext('957', 'Eckert', 'ccvm', 'value')),
+ (958, 'proj', 'dd', oils_i18n_gettext('958', 'Goode''s homolosine', 'ccvm', 'value')),
+ (959, 'proj', 'de', oils_i18n_gettext('959', 'Miller''s bipolar oblique conformal conic', 'ccvm', 'value')),
+ (960, 'proj', 'df', oils_i18n_gettext('960', 'Van Der Grinten', 'ccvm', 'value')),
+ (961, 'proj', 'dg', oils_i18n_gettext('961', 'Dymaxion', 'ccvm', 'value')),
+ (962, 'proj', 'dh', oils_i18n_gettext('962', 'Cordiform', 'ccvm', 'value')),
+ (963, 'proj', 'dl', oils_i18n_gettext('963', 'Lambert conformal', 'ccvm', 'value')),
+ (964, 'proj', 'zz', oils_i18n_gettext('964', 'Other', 'ccvm', 'value')),
+
+ (965, 'relf', ' ', oils_i18n_gettext('965', 'No relief shown', 'ccvm', 'value')),
+ (966, 'relf', 'a', oils_i18n_gettext('966', 'Contours', 'ccvm', 'value')),
+ (967, 'relf', 'b', oils_i18n_gettext('967', 'Shading', 'ccvm', 'value')),
+ (968, 'relf', 'c', oils_i18n_gettext('968', 'Gradient and bathymetric tints', 'ccvm', 'value')),
+ (969, 'relf', 'd', oils_i18n_gettext('969', 'Hachures', 'ccvm', 'value')),
+ (970, 'relf', 'e', oils_i18n_gettext('970', 'Bathymetry, soundings', 'ccvm', 'value')),
+ (971, 'relf', 'f', oils_i18n_gettext('971', 'Form lines', 'ccvm', 'value')),
+ (972, 'relf', 'g', oils_i18n_gettext('972', 'Spot heights', 'ccvm', 'value')),
+ (973, 'relf', 'i', oils_i18n_gettext('973', 'Pictorially', 'ccvm', 'value')),
+ (974, 'relf', 'j', oils_i18n_gettext('974', 'Land forms', 'ccvm', 'value')),
+ (975, 'relf', 'k', oils_i18n_gettext('975', 'Bathymetry, isolines', 'ccvm', 'value')),
+ (976, 'relf', 'm', oils_i18n_gettext('976', 'Rock drawings', 'ccvm', 'value')),
+ (977, 'relf', 'z', oils_i18n_gettext('977', 'Other', 'ccvm', 'value')),
+
+ (978, 'spfm', ' ', oils_i18n_gettext('978', 'No specified special format characteristics', 'ccvm', 'value')),
+ (979, 'spfm', 'e', oils_i18n_gettext('979', 'Manuscript', 'ccvm', 'value')),
+ (980, 'spfm', 'j', oils_i18n_gettext('980', 'Picture card, post card', 'ccvm', 'value')),
+ (981, 'spfm', 'k', oils_i18n_gettext('981', 'Calendar', 'ccvm', 'value')),
+ (982, 'spfm', 'l', oils_i18n_gettext('982', 'Puzzle', 'ccvm', 'value')),
+ (983, 'spfm', 'n', oils_i18n_gettext('983', 'Game', 'ccvm', 'value')),
+ (984, 'spfm', 'o', oils_i18n_gettext('984', 'Wall map', 'ccvm', 'value')),
+ (985, 'spfm', 'p', oils_i18n_gettext('985', 'Playing cards', 'ccvm', 'value')),
+ (986, 'spfm', 'r', oils_i18n_gettext('986', 'Loose-leaf', 'ccvm', 'value')),
+ (987, 'spfm', 'z', oils_i18n_gettext('987', 'Other', 'ccvm', 'value')),
+
+ (988, 'srtp', ' ', oils_i18n_gettext('988', 'None of the following', 'ccvm', 'value')),
+ (989, 'srtp', 'd', oils_i18n_gettext('989', 'Updating database', 'ccvm', 'value')),
+ (990, 'srtp', 'l', oils_i18n_gettext('990', 'Updating loose-leaf', 'ccvm', 'value')),
+ (991, 'srtp', 'm', oils_i18n_gettext('991', 'Monographic series', 'ccvm', 'value')),
+ (992, 'srtp', 'n', oils_i18n_gettext('992', 'Newspaper', 'ccvm', 'value')),
+ (993, 'srtp', 'p', oils_i18n_gettext('993', 'Periodical', 'ccvm', 'value')),
+ (994, 'srtp', 'w', oils_i18n_gettext('994', 'Updating Web site', 'ccvm', 'value')),
+
+ (995, 'tech', 'a', oils_i18n_gettext('995', 'Animation', 'ccvm', 'value')),
+ (996, 'tech', 'c', oils_i18n_gettext('996', 'Animation and live action', 'ccvm', 'value')),
+ (997, 'tech', 'l', oils_i18n_gettext('997', 'Live action', 'ccvm', 'value')),
+ (998, 'tech', 'n', oils_i18n_gettext('998', 'Not applicable', 'ccvm', 'value')),
+ (999, 'tech', 'u', oils_i18n_gettext('999', 'Unknown', 'ccvm', 'value')),
+ (1000, 'tech', 'z', oils_i18n_gettext('1000', 'Other', 'ccvm', 'value')),
+
+ (1001, 'trar', ' ', oils_i18n_gettext('1001', 'Not arrangement or transposition or not specified', 'ccvm', 'value')),
+ (1002, 'trar', 'a', oils_i18n_gettext('1002', 'Transposition', 'ccvm', 'value')),
+ (1003, 'trar', 'b', oils_i18n_gettext('1003', 'Arrangement', 'ccvm', 'value')),
+ (1004, 'trar', 'c', oils_i18n_gettext('1004', 'Both transposed and arranged', 'ccvm', 'value')),
+ (1005, 'trar', 'n', oils_i18n_gettext('1005', 'Not applicable', 'ccvm', 'value')),
+ (1006, 'trar', 'u', oils_i18n_gettext('1006', 'Unknown', 'ccvm', 'value')),
+
+ (1007, 'ctry', 'aa ', oils_i18n_gettext('1007', 'Albania ', 'ccvm', 'value')),
+ (1008, 'ctry', 'abc', oils_i18n_gettext('1008', 'Alberta ', 'ccvm', 'value')),
+ (1009, 'ctry', 'aca', oils_i18n_gettext('1009', 'Australian Capital Territory ', 'ccvm', 'value')),
+ (1010, 'ctry', 'ae ', oils_i18n_gettext('1010', 'Algeria ', 'ccvm', 'value')),
+ (1011, 'ctry', 'af ', oils_i18n_gettext('1011', 'Afghanistan ', 'ccvm', 'value')),
+ (1012, 'ctry', 'ag ', oils_i18n_gettext('1012', 'Argentina ', 'ccvm', 'value')),
+ (1013, 'ctry', 'ai ', oils_i18n_gettext('1013', 'Armenia (Republic) ', 'ccvm', 'value')),
+ (1014, 'ctry', 'aj ', oils_i18n_gettext('1014', 'Azerbaijan ', 'ccvm', 'value')),
+ (1015, 'ctry', 'aku', oils_i18n_gettext('1015', 'Alaska ', 'ccvm', 'value')),
+ (1016, 'ctry', 'alu', oils_i18n_gettext('1016', 'Alabama ', 'ccvm', 'value')),
+ (1017, 'ctry', 'am ', oils_i18n_gettext('1017', 'Anguilla ', 'ccvm', 'value')),
+ (1018, 'ctry', 'an ', oils_i18n_gettext('1018', 'Andorra ', 'ccvm', 'value')),
+ (1019, 'ctry', 'ao ', oils_i18n_gettext('1019', 'Angola ', 'ccvm', 'value')),
+ (1020, 'ctry', 'aq ', oils_i18n_gettext('1020', 'Antigua and Barbuda ', 'ccvm', 'value')),
+ (1021, 'ctry', 'aru', oils_i18n_gettext('1021', 'Arkansas ', 'ccvm', 'value')),
+ (1022, 'ctry', 'as ', oils_i18n_gettext('1022', 'American Samoa ', 'ccvm', 'value')),
+ (1023, 'ctry', 'at ', oils_i18n_gettext('1023', 'Australia ', 'ccvm', 'value')),
+ (1024, 'ctry', 'au ', oils_i18n_gettext('1024', 'Austria ', 'ccvm', 'value')),
+ (1025, 'ctry', 'aw ', oils_i18n_gettext('1025', 'Aruba ', 'ccvm', 'value')),
+ (1026, 'ctry', 'ay ', oils_i18n_gettext('1026', 'Antarctica ', 'ccvm', 'value')),
+ (1027, 'ctry', 'azu', oils_i18n_gettext('1027', 'Arizona ', 'ccvm', 'value')),
+ (1028, 'ctry', 'ba ', oils_i18n_gettext('1028', 'Bahrain ', 'ccvm', 'value')),
+ (1029, 'ctry', 'bb ', oils_i18n_gettext('1029', 'Barbados ', 'ccvm', 'value')),
+ (1030, 'ctry', 'bcc', oils_i18n_gettext('1030', 'British Columbia ', 'ccvm', 'value')),
+ (1031, 'ctry', 'bd ', oils_i18n_gettext('1031', 'Burundi ', 'ccvm', 'value')),
+ (1032, 'ctry', 'be ', oils_i18n_gettext('1032', 'Belgium ', 'ccvm', 'value')),
+ (1033, 'ctry', 'bf ', oils_i18n_gettext('1033', 'Bahamas ', 'ccvm', 'value')),
+ (1034, 'ctry', 'bg ', oils_i18n_gettext('1034', 'Bangladesh ', 'ccvm', 'value')),
+ (1035, 'ctry', 'bh ', oils_i18n_gettext('1035', 'Belize ', 'ccvm', 'value')),
+ (1036, 'ctry', 'bi ', oils_i18n_gettext('1036', 'British Indian Ocean Territory ', 'ccvm', 'value')),
+ (1037, 'ctry', 'bl ', oils_i18n_gettext('1037', 'Brazil ', 'ccvm', 'value')),
+ (1038, 'ctry', 'bm ', oils_i18n_gettext('1038', 'Bermuda Islands ', 'ccvm', 'value')),
+ (1039, 'ctry', 'bn ', oils_i18n_gettext('1039', 'Bosnia and Herzegovina ', 'ccvm', 'value')),
+ (1040, 'ctry', 'bo ', oils_i18n_gettext('1040', 'Bolivia ', 'ccvm', 'value')),
+ (1041, 'ctry', 'bp ', oils_i18n_gettext('1041', 'Solomon Islands ', 'ccvm', 'value')),
+ (1042, 'ctry', 'br ', oils_i18n_gettext('1042', 'Burma ', 'ccvm', 'value')),
+ (1043, 'ctry', 'bs ', oils_i18n_gettext('1043', 'Botswana ', 'ccvm', 'value')),
+ (1044, 'ctry', 'bt ', oils_i18n_gettext('1044', 'Bhutan ', 'ccvm', 'value')),
+ (1045, 'ctry', 'bu ', oils_i18n_gettext('1045', 'Bulgaria ', 'ccvm', 'value')),
+ (1046, 'ctry', 'bv ', oils_i18n_gettext('1046', 'Bouvet Island ', 'ccvm', 'value')),
+ (1047, 'ctry', 'bw ', oils_i18n_gettext('1047', 'Belarus ', 'ccvm', 'value')),
+ (1048, 'ctry', 'bx ', oils_i18n_gettext('1048', 'Brunei ', 'ccvm', 'value')),
+ (1049, 'ctry', 'ca ', oils_i18n_gettext('1049', 'Caribbean Netherlands ', 'ccvm', 'value')),
+ (1050, 'ctry', 'cau', oils_i18n_gettext('1050', 'California ', 'ccvm', 'value')),
+ (1051, 'ctry', 'cb ', oils_i18n_gettext('1051', 'Cambodia ', 'ccvm', 'value')),
+ (1052, 'ctry', 'cc ', oils_i18n_gettext('1052', 'China ', 'ccvm', 'value')),
+ (1053, 'ctry', 'cd ', oils_i18n_gettext('1053', 'Chad ', 'ccvm', 'value')),
+ (1054, 'ctry', 'ce ', oils_i18n_gettext('1054', 'Sri Lanka ', 'ccvm', 'value')),
+ (1055, 'ctry', 'cf ', oils_i18n_gettext('1055', 'Congo (Brazzaville) ', 'ccvm', 'value')),
+ (1056, 'ctry', 'cg ', oils_i18n_gettext('1056', 'Congo (Democratic Republic) ', 'ccvm', 'value')),
+ (1057, 'ctry', 'ch ', oils_i18n_gettext('1057', 'China (Republic : 1949', 'ccvm', 'value')),
+ (1058, 'ctry', 'ci ', oils_i18n_gettext('1058', 'Croatia ', 'ccvm', 'value')),
+ (1059, 'ctry', 'cj ', oils_i18n_gettext('1059', 'Cayman Islands ', 'ccvm', 'value')),
+ (1060, 'ctry', 'ck ', oils_i18n_gettext('1060', 'Colombia ', 'ccvm', 'value')),
+ (1061, 'ctry', 'cl ', oils_i18n_gettext('1061', 'Chile ', 'ccvm', 'value')),
+ (1062, 'ctry', 'cm ', oils_i18n_gettext('1062', 'Cameroon ', 'ccvm', 'value')),
+ (1063, 'ctry', 'co ', oils_i18n_gettext('1063', 'Curaçao ', 'ccvm', 'value')),
+ (1064, 'ctry', 'cou', oils_i18n_gettext('1064', 'Colorado ', 'ccvm', 'value')),
+ (1065, 'ctry', 'cq ', oils_i18n_gettext('1065', 'Comoros ', 'ccvm', 'value')),
+ (1066, 'ctry', 'cr ', oils_i18n_gettext('1066', 'Costa Rica ', 'ccvm', 'value')),
+ (1067, 'ctry', 'ctu', oils_i18n_gettext('1067', 'Connecticut ', 'ccvm', 'value')),
+ (1068, 'ctry', 'cu ', oils_i18n_gettext('1068', 'Cuba ', 'ccvm', 'value')),
+ (1069, 'ctry', 'cv ', oils_i18n_gettext('1069', 'Cabo Verde ', 'ccvm', 'value')),
+ (1070, 'ctry', 'cw ', oils_i18n_gettext('1070', 'Cook Islands ', 'ccvm', 'value')),
+ (1071, 'ctry', 'cx ', oils_i18n_gettext('1071', 'Central African Republic ', 'ccvm', 'value')),
+ (1072, 'ctry', 'cy ', oils_i18n_gettext('1072', 'Cyprus ', 'ccvm', 'value')),
+ (1073, 'ctry', 'dcu', oils_i18n_gettext('1073', 'District of Columbia ', 'ccvm', 'value')),
+ (1074, 'ctry', 'deu', oils_i18n_gettext('1074', 'Delaware ', 'ccvm', 'value')),
+ (1075, 'ctry', 'dk ', oils_i18n_gettext('1075', 'Denmark ', 'ccvm', 'value')),
+ (1076, 'ctry', 'dm ', oils_i18n_gettext('1076', 'Benin ', 'ccvm', 'value')),
+ (1077, 'ctry', 'dq ', oils_i18n_gettext('1077', 'Dominica ', 'ccvm', 'value')),
+ (1078, 'ctry', 'dr ', oils_i18n_gettext('1078', 'Dominican Republic ', 'ccvm', 'value')),
+ (1079, 'ctry', 'ea ', oils_i18n_gettext('1079', 'Eritrea ', 'ccvm', 'value')),
+ (1080, 'ctry', 'ec ', oils_i18n_gettext('1080', 'Ecuador ', 'ccvm', 'value')),
+ (1081, 'ctry', 'eg ', oils_i18n_gettext('1081', 'Equatorial Guinea ', 'ccvm', 'value')),
+ (1082, 'ctry', 'em ', oils_i18n_gettext('1082', 'Timor', 'ccvm', 'value')),
+ (1083, 'ctry', 'enk', oils_i18n_gettext('1083', 'England ', 'ccvm', 'value')),
+ (1084, 'ctry', 'er ', oils_i18n_gettext('1084', 'Estonia ', 'ccvm', 'value')),
+ (1085, 'ctry', 'es ', oils_i18n_gettext('1085', 'El Salvador ', 'ccvm', 'value')),
+ (1086, 'ctry', 'et ', oils_i18n_gettext('1086', 'Ethiopia ', 'ccvm', 'value')),
+ (1087, 'ctry', 'fa ', oils_i18n_gettext('1087', 'Faroe Islands ', 'ccvm', 'value')),
+ (1088, 'ctry', 'fg ', oils_i18n_gettext('1088', 'French Guiana ', 'ccvm', 'value')),
+ (1089, 'ctry', 'fi ', oils_i18n_gettext('1089', 'Finland ', 'ccvm', 'value')),
+ (1090, 'ctry', 'fj ', oils_i18n_gettext('1090', 'Fiji ', 'ccvm', 'value')),
+ (1091, 'ctry', 'fk ', oils_i18n_gettext('1091', 'Falkland Islands ', 'ccvm', 'value')),
+ (1092, 'ctry', 'flu', oils_i18n_gettext('1092', 'Florida ', 'ccvm', 'value')),
+ (1093, 'ctry', 'fm ', oils_i18n_gettext('1093', 'Micronesia (Federated States) ', 'ccvm', 'value')),
+ (1094, 'ctry', 'fp ', oils_i18n_gettext('1094', 'French Polynesia ', 'ccvm', 'value')),
+ (1095, 'ctry', 'fr ', oils_i18n_gettext('1095', 'France ', 'ccvm', 'value')),
+ (1096, 'ctry', 'fs ', oils_i18n_gettext('1096', 'Terres australes et antarctiques françaises ', 'ccvm', 'value')),
+ (1097, 'ctry', 'ft ', oils_i18n_gettext('1097', 'Djibouti ', 'ccvm', 'value')),
+ (1098, 'ctry', 'gau', oils_i18n_gettext('1098', 'Georgia ', 'ccvm', 'value')),
+ (1099, 'ctry', 'gb ', oils_i18n_gettext('1099', 'Kiribati ', 'ccvm', 'value')),
+ (1100, 'ctry', 'gd ', oils_i18n_gettext('1100', 'Grenada ', 'ccvm', 'value')),
+ (1101, 'ctry', 'gh ', oils_i18n_gettext('1101', 'Ghana ', 'ccvm', 'value')),
+ (1102, 'ctry', 'gi ', oils_i18n_gettext('1102', 'Gibraltar ', 'ccvm', 'value')),
+ (1103, 'ctry', 'gl ', oils_i18n_gettext('1103', 'Greenland ', 'ccvm', 'value')),
+ (1104, 'ctry', 'gm ', oils_i18n_gettext('1104', 'Gambia ', 'ccvm', 'value')),
+ (1105, 'ctry', 'go ', oils_i18n_gettext('1105', 'Gabon ', 'ccvm', 'value')),
+ (1106, 'ctry', 'gp ', oils_i18n_gettext('1106', 'Guadeloupe ', 'ccvm', 'value')),
+ (1107, 'ctry', 'gr ', oils_i18n_gettext('1107', 'Greece ', 'ccvm', 'value')),
+ (1108, 'ctry', 'gs ', oils_i18n_gettext('1108', 'Georgia (Republic) ', 'ccvm', 'value')),
+ (1109, 'ctry', 'gt ', oils_i18n_gettext('1109', 'Guatemala ', 'ccvm', 'value')),
+ (1110, 'ctry', 'gu ', oils_i18n_gettext('1110', 'Guam ', 'ccvm', 'value')),
+ (1111, 'ctry', 'gv ', oils_i18n_gettext('1111', 'Guinea ', 'ccvm', 'value')),
+ (1112, 'ctry', 'gw ', oils_i18n_gettext('1112', 'Germany ', 'ccvm', 'value')),
+ (1113, 'ctry', 'gy ', oils_i18n_gettext('1113', 'Guyana ', 'ccvm', 'value')),
+ (1114, 'ctry', 'gz ', oils_i18n_gettext('1114', 'Gaza Strip ', 'ccvm', 'value')),
+ (1115, 'ctry', 'hiu', oils_i18n_gettext('1115', 'Hawaii ', 'ccvm', 'value')),
+ (1116, 'ctry', 'hm ', oils_i18n_gettext('1116', 'Heard and McDonald Islands ', 'ccvm', 'value')),
+ (1117, 'ctry', 'ho ', oils_i18n_gettext('1117', 'Honduras ', 'ccvm', 'value')),
+ (1118, 'ctry', 'ht ', oils_i18n_gettext('1118', 'Haiti ', 'ccvm', 'value')),
+ (1119, 'ctry', 'hu ', oils_i18n_gettext('1119', 'Hungary ', 'ccvm', 'value')),
+ (1120, 'ctry', 'iau', oils_i18n_gettext('1120', 'Iowa ', 'ccvm', 'value')),
+ (1121, 'ctry', 'ic ', oils_i18n_gettext('1121', 'Iceland ', 'ccvm', 'value')),
+ (1122, 'ctry', 'idu', oils_i18n_gettext('1122', 'Idaho ', 'ccvm', 'value')),
+ (1123, 'ctry', 'ie ', oils_i18n_gettext('1123', 'Ireland ', 'ccvm', 'value')),
+ (1124, 'ctry', 'ii ', oils_i18n_gettext('1124', 'India ', 'ccvm', 'value')),
+ (1125, 'ctry', 'ilu', oils_i18n_gettext('1125', 'Illinois ', 'ccvm', 'value')),
+ (1126, 'ctry', 'inu', oils_i18n_gettext('1126', 'Indiana ', 'ccvm', 'value')),
+ (1127, 'ctry', 'io ', oils_i18n_gettext('1127', 'Indonesia ', 'ccvm', 'value')),
+ (1128, 'ctry', 'iq ', oils_i18n_gettext('1128', 'Iraq ', 'ccvm', 'value')),
+ (1129, 'ctry', 'ir ', oils_i18n_gettext('1129', 'Iran ', 'ccvm', 'value')),
+ (1130, 'ctry', 'is ', oils_i18n_gettext('1130', 'Israel ', 'ccvm', 'value')),
+ (1131, 'ctry', 'it ', oils_i18n_gettext('1131', 'Italy ', 'ccvm', 'value')),
+ (1132, 'ctry', 'iv ', oils_i18n_gettext('1132', 'Côte d''Ivoire ', 'ccvm', 'value')),
+ (1133, 'ctry', 'iy ', oils_i18n_gettext('1133', 'Iraq', 'ccvm', 'value')),
+ (1134, 'ctry', 'ja ', oils_i18n_gettext('1134', 'Japan ', 'ccvm', 'value')),
+ (1135, 'ctry', 'ji ', oils_i18n_gettext('1135', 'Johnston Atoll ', 'ccvm', 'value')),
+ (1136, 'ctry', 'jm ', oils_i18n_gettext('1136', 'Jamaica ', 'ccvm', 'value')),
+ (1137, 'ctry', 'jo ', oils_i18n_gettext('1137', 'Jordan ', 'ccvm', 'value')),
+ (1138, 'ctry', 'ke ', oils_i18n_gettext('1138', 'Kenya ', 'ccvm', 'value')),
+ (1139, 'ctry', 'kg ', oils_i18n_gettext('1139', 'Kyrgyzstan ', 'ccvm', 'value')),
+ (1140, 'ctry', 'kn ', oils_i18n_gettext('1140', 'Korea (North) ', 'ccvm', 'value')),
+ (1141, 'ctry', 'ko ', oils_i18n_gettext('1141', 'Korea (South) ', 'ccvm', 'value')),
+ (1142, 'ctry', 'ksu', oils_i18n_gettext('1142', 'Kansas ', 'ccvm', 'value')),
+ (1143, 'ctry', 'ku ', oils_i18n_gettext('1143', 'Kuwait ', 'ccvm', 'value')),
+ (1144, 'ctry', 'kv ', oils_i18n_gettext('1144', 'Kosovo ', 'ccvm', 'value')),
+ (1145, 'ctry', 'kyu', oils_i18n_gettext('1145', 'Kentucky ', 'ccvm', 'value')),
+ (1146, 'ctry', 'kz ', oils_i18n_gettext('1146', 'Kazakhstan ', 'ccvm', 'value')),
+ (1147, 'ctry', 'lau', oils_i18n_gettext('1147', 'Louisiana ', 'ccvm', 'value')),
+ (1148, 'ctry', 'lb ', oils_i18n_gettext('1148', 'Liberia ', 'ccvm', 'value')),
+ (1149, 'ctry', 'le ', oils_i18n_gettext('1149', 'Lebanon ', 'ccvm', 'value')),
+ (1150, 'ctry', 'lh ', oils_i18n_gettext('1150', 'Liechtenstein ', 'ccvm', 'value')),
+ (1151, 'ctry', 'li ', oils_i18n_gettext('1151', 'Lithuania ', 'ccvm', 'value')),
+ (1152, 'ctry', 'lo ', oils_i18n_gettext('1152', 'Lesotho ', 'ccvm', 'value')),
+ (1153, 'ctry', 'ls ', oils_i18n_gettext('1153', 'Laos ', 'ccvm', 'value')),
+ (1154, 'ctry', 'lu ', oils_i18n_gettext('1154', 'Luxembourg ', 'ccvm', 'value')),
+ (1155, 'ctry', 'lv ', oils_i18n_gettext('1155', 'Latvia ', 'ccvm', 'value')),
+ (1156, 'ctry', 'ly ', oils_i18n_gettext('1156', 'Libya ', 'ccvm', 'value')),
+ (1157, 'ctry', 'mau', oils_i18n_gettext('1157', 'Massachusetts ', 'ccvm', 'value')),
+ (1158, 'ctry', 'mbc', oils_i18n_gettext('1158', 'Manitoba ', 'ccvm', 'value')),
+ (1159, 'ctry', 'mc ', oils_i18n_gettext('1159', 'Monaco ', 'ccvm', 'value')),
+ (1160, 'ctry', 'mdu', oils_i18n_gettext('1160', 'Maryland ', 'ccvm', 'value')),
+ (1161, 'ctry', 'meu', oils_i18n_gettext('1161', 'Maine ', 'ccvm', 'value')),
+ (1162, 'ctry', 'mf ', oils_i18n_gettext('1162', 'Mauritius ', 'ccvm', 'value')),
+ (1163, 'ctry', 'mg ', oils_i18n_gettext('1163', 'Madagascar ', 'ccvm', 'value')),
+ (1164, 'ctry', 'miu', oils_i18n_gettext('1164', 'Michigan ', 'ccvm', 'value')),
+ (1165, 'ctry', 'mj ', oils_i18n_gettext('1165', 'Montserrat ', 'ccvm', 'value')),
+ (1166, 'ctry', 'mk ', oils_i18n_gettext('1166', 'Oman ', 'ccvm', 'value')),
+ (1167, 'ctry', 'ml ', oils_i18n_gettext('1167', 'Mali ', 'ccvm', 'value')),
+ (1168, 'ctry', 'mm ', oils_i18n_gettext('1168', 'Malta ', 'ccvm', 'value')),
+ (1169, 'ctry', 'mnu', oils_i18n_gettext('1169', 'Minnesota ', 'ccvm', 'value')),
+ (1170, 'ctry', 'mo ', oils_i18n_gettext('1170', 'Montenegro ', 'ccvm', 'value')),
+ (1171, 'ctry', 'mou', oils_i18n_gettext('1171', 'Missouri ', 'ccvm', 'value')),
+ (1172, 'ctry', 'mp ', oils_i18n_gettext('1172', 'Mongolia ', 'ccvm', 'value')),
+ (1173, 'ctry', 'mq ', oils_i18n_gettext('1173', 'Martinique ', 'ccvm', 'value')),
+ (1174, 'ctry', 'mr ', oils_i18n_gettext('1174', 'Morocco ', 'ccvm', 'value')),
+ (1175, 'ctry', 'msu', oils_i18n_gettext('1175', 'Mississippi ', 'ccvm', 'value')),
+ (1176, 'ctry', 'mtu', oils_i18n_gettext('1176', 'Montana ', 'ccvm', 'value')),
+ (1177, 'ctry', 'mu ', oils_i18n_gettext('1177', 'Mauritania ', 'ccvm', 'value')),
+ (1178, 'ctry', 'mv ', oils_i18n_gettext('1178', 'Moldova ', 'ccvm', 'value')),
+ (1179, 'ctry', 'mw ', oils_i18n_gettext('1179', 'Malawi ', 'ccvm', 'value')),
+ (1180, 'ctry', 'mx ', oils_i18n_gettext('1180', 'Mexico ', 'ccvm', 'value')),
+ (1181, 'ctry', 'my ', oils_i18n_gettext('1181', 'Malaysia ', 'ccvm', 'value')),
+ (1182, 'ctry', 'mz ', oils_i18n_gettext('1182', 'Mozambique ', 'ccvm', 'value')),
+ (1183, 'ctry', 'nbu', oils_i18n_gettext('1183', 'Nebraska ', 'ccvm', 'value')),
+ (1184, 'ctry', 'ncu', oils_i18n_gettext('1184', 'North Carolina ', 'ccvm', 'value')),
+ (1185, 'ctry', 'ndu', oils_i18n_gettext('1185', 'North Dakota ', 'ccvm', 'value')),
+ (1186, 'ctry', 'ne ', oils_i18n_gettext('1186', 'Netherlands ', 'ccvm', 'value')),
+ (1187, 'ctry', 'nfc', oils_i18n_gettext('1187', 'Newfoundland and Labrador ', 'ccvm', 'value')),
+ (1188, 'ctry', 'ng ', oils_i18n_gettext('1188', 'Niger ', 'ccvm', 'value')),
+ (1189, 'ctry', 'nhu', oils_i18n_gettext('1189', 'New Hampshire ', 'ccvm', 'value')),
+ (1190, 'ctry', 'nik', oils_i18n_gettext('1190', 'Northern Ireland ', 'ccvm', 'value')),
+ (1191, 'ctry', 'nju', oils_i18n_gettext('1191', 'New Jersey ', 'ccvm', 'value')),
+ (1192, 'ctry', 'nkc', oils_i18n_gettext('1192', 'New Brunswick ', 'ccvm', 'value')),
+ (1193, 'ctry', 'nl ', oils_i18n_gettext('1193', 'New Caledonia ', 'ccvm', 'value')),
+ (1194, 'ctry', 'nmu', oils_i18n_gettext('1194', 'New Mexico ', 'ccvm', 'value')),
+ (1195, 'ctry', 'nn ', oils_i18n_gettext('1195', 'Vanuatu ', 'ccvm', 'value')),
+ (1196, 'ctry', 'no ', oils_i18n_gettext('1196', 'Norway ', 'ccvm', 'value')),
+ (1197, 'ctry', 'np ', oils_i18n_gettext('1197', 'Nepal ', 'ccvm', 'value')),
+ (1198, 'ctry', 'nq ', oils_i18n_gettext('1198', 'Nicaragua ', 'ccvm', 'value')),
+ (1199, 'ctry', 'nr ', oils_i18n_gettext('1199', 'Nigeria ', 'ccvm', 'value')),
+ (1200, 'ctry', 'nsc', oils_i18n_gettext('1200', 'Nova Scotia ', 'ccvm', 'value')),
+ (1201, 'ctry', 'ntc', oils_i18n_gettext('1201', 'Northwest Territories ', 'ccvm', 'value')),
+ (1202, 'ctry', 'nu ', oils_i18n_gettext('1202', 'Nauru ', 'ccvm', 'value')),
+ (1203, 'ctry', 'nuc', oils_i18n_gettext('1203', 'Nunavut ', 'ccvm', 'value')),
+ (1204, 'ctry', 'nvu', oils_i18n_gettext('1204', 'Nevada ', 'ccvm', 'value')),
+ (1205, 'ctry', 'nw ', oils_i18n_gettext('1205', 'Northern Mariana Islands ', 'ccvm', 'value')),
+ (1206, 'ctry', 'nx ', oils_i18n_gettext('1206', 'Norfolk Island ', 'ccvm', 'value')),
+ (1207, 'ctry', 'nyu', oils_i18n_gettext('1207', 'New York (State) ', 'ccvm', 'value')),
+ (1208, 'ctry', 'nz ', oils_i18n_gettext('1208', 'New Zealand ', 'ccvm', 'value')),
+ (1209, 'ctry', 'ohu', oils_i18n_gettext('1209', 'Ohio ', 'ccvm', 'value')),
+ (1210, 'ctry', 'oku', oils_i18n_gettext('1210', 'Oklahoma ', 'ccvm', 'value')),
+ (1211, 'ctry', 'onc', oils_i18n_gettext('1211', 'Ontario ', 'ccvm', 'value')),
+ (1212, 'ctry', 'oru', oils_i18n_gettext('1212', 'Oregon ', 'ccvm', 'value')),
+ (1213, 'ctry', 'ot ', oils_i18n_gettext('1213', 'Mayotte ', 'ccvm', 'value')),
+ (1214, 'ctry', 'pau', oils_i18n_gettext('1214', 'Pennsylvania ', 'ccvm', 'value')),
+ (1215, 'ctry', 'pc ', oils_i18n_gettext('1215', 'Pitcairn Island ', 'ccvm', 'value')),
+ (1216, 'ctry', 'pe ', oils_i18n_gettext('1216', 'Peru ', 'ccvm', 'value')),
+ (1217, 'ctry', 'pf ', oils_i18n_gettext('1217', 'Paracel Islands ', 'ccvm', 'value')),
+ (1218, 'ctry', 'pg ', oils_i18n_gettext('1218', 'Guinea', 'ccvm', 'value')),
+ (1219, 'ctry', 'ph ', oils_i18n_gettext('1219', 'Philippines ', 'ccvm', 'value')),
+ (1220, 'ctry', 'pic', oils_i18n_gettext('1220', 'Prince Edward Island ', 'ccvm', 'value')),
+ (1221, 'ctry', 'pk ', oils_i18n_gettext('1221', 'Pakistan ', 'ccvm', 'value')),
+ (1222, 'ctry', 'pl ', oils_i18n_gettext('1222', 'Poland ', 'ccvm', 'value')),
+ (1223, 'ctry', 'pn ', oils_i18n_gettext('1223', 'Panama ', 'ccvm', 'value')),
+ (1224, 'ctry', 'po ', oils_i18n_gettext('1224', 'Portugal ', 'ccvm', 'value')),
+ (1225, 'ctry', 'pp ', oils_i18n_gettext('1225', 'Papua New Guinea ', 'ccvm', 'value')),
+ (1226, 'ctry', 'pr ', oils_i18n_gettext('1226', 'Puerto Rico ', 'ccvm', 'value')),
+ (1227, 'ctry', 'pw ', oils_i18n_gettext('1227', 'Palau ', 'ccvm', 'value')),
+ (1228, 'ctry', 'py ', oils_i18n_gettext('1228', 'Paraguay ', 'ccvm', 'value')),
+ (1229, 'ctry', 'qa ', oils_i18n_gettext('1229', 'Qatar ', 'ccvm', 'value')),
+ (1230, 'ctry', 'qea', oils_i18n_gettext('1230', 'Queensland ', 'ccvm', 'value')),
+ (1231, 'ctry', 'quc', oils_i18n_gettext('1231', 'Québec (Province) ', 'ccvm', 'value')),
+ (1232, 'ctry', 'rb ', oils_i18n_gettext('1232', 'Serbia ', 'ccvm', 'value')),
+ (1233, 'ctry', 're ', oils_i18n_gettext('1233', 'Réunion ', 'ccvm', 'value')),
+ (1234, 'ctry', 'rh ', oils_i18n_gettext('1234', 'Zimbabwe ', 'ccvm', 'value')),
+ (1235, 'ctry', 'riu', oils_i18n_gettext('1235', 'Rhode Island ', 'ccvm', 'value')),
+ (1236, 'ctry', 'rm ', oils_i18n_gettext('1236', 'Romania ', 'ccvm', 'value')),
+ (1237, 'ctry', 'ru ', oils_i18n_gettext('1237', 'Russia (Federation) ', 'ccvm', 'value')),
+ (1238, 'ctry', 'rw ', oils_i18n_gettext('1238', 'Rwanda ', 'ccvm', 'value')),
+ (1239, 'ctry', 'sa ', oils_i18n_gettext('1239', 'South Africa ', 'ccvm', 'value')),
+ (1240, 'ctry', 'sc ', oils_i18n_gettext('1240', 'Saint', 'ccvm', 'value')),
+ (1241, 'ctry', 'scu', oils_i18n_gettext('1241', 'South Carolina ', 'ccvm', 'value')),
+ (1242, 'ctry', 'sd ', oils_i18n_gettext('1242', 'South Sudan ', 'ccvm', 'value')),
+ (1243, 'ctry', 'sdu', oils_i18n_gettext('1243', 'South Dakota ', 'ccvm', 'value')),
+ (1244, 'ctry', 'se ', oils_i18n_gettext('1244', 'Seychelles ', 'ccvm', 'value')),
+ (1245, 'ctry', 'sf ', oils_i18n_gettext('1245', 'Sao Tome and Principe ', 'ccvm', 'value')),
+ (1246, 'ctry', 'sg ', oils_i18n_gettext('1246', 'Senegal ', 'ccvm', 'value')),
+ (1247, 'ctry', 'sh ', oils_i18n_gettext('1247', 'Spanish North Africa ', 'ccvm', 'value')),
+ (1248, 'ctry', 'si ', oils_i18n_gettext('1248', 'Singapore ', 'ccvm', 'value')),
+ (1249, 'ctry', 'sj ', oils_i18n_gettext('1249', 'Sudan ', 'ccvm', 'value')),
+ (1250, 'ctry', 'sl ', oils_i18n_gettext('1250', 'Sierra Leone ', 'ccvm', 'value')),
+ (1251, 'ctry', 'sm ', oils_i18n_gettext('1251', 'San Marino ', 'ccvm', 'value')),
+ (1252, 'ctry', 'sn ', oils_i18n_gettext('1252', 'Sint Maarten ', 'ccvm', 'value')),
+ (1253, 'ctry', 'snc', oils_i18n_gettext('1253', 'Saskatchewan ', 'ccvm', 'value')),
+ (1254, 'ctry', 'so ', oils_i18n_gettext('1254', 'Somalia ', 'ccvm', 'value')),
+ (1255, 'ctry', 'sp ', oils_i18n_gettext('1255', 'Spain ', 'ccvm', 'value')),
+ (1256, 'ctry', 'sq ', oils_i18n_gettext('1256', 'Swaziland ', 'ccvm', 'value')),
+ (1257, 'ctry', 'sr ', oils_i18n_gettext('1257', 'Surinam ', 'ccvm', 'value')),
+ (1258, 'ctry', 'ss ', oils_i18n_gettext('1258', 'Western Sahara ', 'ccvm', 'value')),
+ (1259, 'ctry', 'st ', oils_i18n_gettext('1259', 'Saint', 'ccvm', 'value')),
+ (1260, 'ctry', 'stk', oils_i18n_gettext('1260', 'Scotland ', 'ccvm', 'value')),
+ (1261, 'ctry', 'su ', oils_i18n_gettext('1261', 'Saudi Arabia ', 'ccvm', 'value')),
+ (1262, 'ctry', 'sw ', oils_i18n_gettext('1262', 'Sweden ', 'ccvm', 'value')),
+ (1263, 'ctry', 'sx ', oils_i18n_gettext('1263', 'Namibia ', 'ccvm', 'value')),
+ (1264, 'ctry', 'sy ', oils_i18n_gettext('1264', 'Syria ', 'ccvm', 'value')),
+ (1265, 'ctry', 'sz ', oils_i18n_gettext('1265', 'Switzerland ', 'ccvm', 'value')),
+ (1266, 'ctry', 'ta ', oils_i18n_gettext('1266', 'Tajikistan ', 'ccvm', 'value')),
+ (1267, 'ctry', 'tc ', oils_i18n_gettext('1267', 'Turks and Caicos Islands ', 'ccvm', 'value')),
+ (1268, 'ctry', 'tg ', oils_i18n_gettext('1268', 'Togo ', 'ccvm', 'value')),
+ (1269, 'ctry', 'th ', oils_i18n_gettext('1269', 'Thailand ', 'ccvm', 'value')),
+ (1270, 'ctry', 'ti ', oils_i18n_gettext('1270', 'Tunisia ', 'ccvm', 'value')),
+ (1271, 'ctry', 'tk ', oils_i18n_gettext('1271', 'Turkmenistan ', 'ccvm', 'value')),
+ (1272, 'ctry', 'tl ', oils_i18n_gettext('1272', 'Tokelau ', 'ccvm', 'value')),
+ (1273, 'ctry', 'tma', oils_i18n_gettext('1273', 'Tasmania ', 'ccvm', 'value')),
+ (1274, 'ctry', 'tnu', oils_i18n_gettext('1274', 'Tennessee ', 'ccvm', 'value')),
+ (1275, 'ctry', 'to ', oils_i18n_gettext('1275', 'Tonga ', 'ccvm', 'value')),
+ (1276, 'ctry', 'tr ', oils_i18n_gettext('1276', 'Trinidad and Tobago ', 'ccvm', 'value')),
+ (1277, 'ctry', 'ts ', oils_i18n_gettext('1277', 'United Arab Emirates ', 'ccvm', 'value')),
+ (1278, 'ctry', 'tu ', oils_i18n_gettext('1278', 'Turkey ', 'ccvm', 'value')),
+ (1279, 'ctry', 'tv ', oils_i18n_gettext('1279', 'Tuvalu ', 'ccvm', 'value')),
+ (1280, 'ctry', 'txu', oils_i18n_gettext('1280', 'Texas ', 'ccvm', 'value')),
+ (1281, 'ctry', 'tz ', oils_i18n_gettext('1281', 'Tanzania ', 'ccvm', 'value')),
+ (1282, 'ctry', 'ua ', oils_i18n_gettext('1282', 'Egypt ', 'ccvm', 'value')),
+ (1283, 'ctry', 'uc ', oils_i18n_gettext('1283', 'United States Misc. Caribbean Islands ', 'ccvm', 'value')),
+ (1284, 'ctry', 'ug ', oils_i18n_gettext('1284', 'Uganda ', 'ccvm', 'value')),
+ (1285, 'ctry', 'uik', oils_i18n_gettext('1285', 'United Kingdom Misc. Islands ', 'ccvm', 'value')),
+ (1286, 'ctry', 'un ', oils_i18n_gettext('1286', 'Ukraine ', 'ccvm', 'value')),
+ (1287, 'ctry', 'up ', oils_i18n_gettext('1287', 'United States Misc. Pacific Islands ', 'ccvm', 'value')),
+ (1288, 'ctry', 'utu', oils_i18n_gettext('1288', 'Utah ', 'ccvm', 'value')),
+ (1289, 'ctry', 'uv ', oils_i18n_gettext('1289', 'Burkina Faso ', 'ccvm', 'value')),
+ (1290, 'ctry', 'uy ', oils_i18n_gettext('1290', 'Uruguay ', 'ccvm', 'value')),
+ (1291, 'ctry', 'uz ', oils_i18n_gettext('1291', 'Uzbekistan ', 'ccvm', 'value')),
+ (1292, 'ctry', 'vau', oils_i18n_gettext('1292', 'Virginia ', 'ccvm', 'value')),
+ (1293, 'ctry', 'vb ', oils_i18n_gettext('1293', 'British Virgin Islands ', 'ccvm', 'value')),
+ (1294, 'ctry', 'vc ', oils_i18n_gettext('1294', 'Vatican City ', 'ccvm', 'value')),
+ (1295, 'ctry', 've ', oils_i18n_gettext('1295', 'Venezuela ', 'ccvm', 'value')),
+ (1296, 'ctry', 'vi ', oils_i18n_gettext('1296', 'Virgin Islands of the United States ', 'ccvm', 'value')),
+ (1297, 'ctry', 'vm ', oils_i18n_gettext('1297', 'Vietnam ', 'ccvm', 'value')),
+ (1298, 'ctry', 'vp ', oils_i18n_gettext('1298', 'Various places ', 'ccvm', 'value')),
+ (1299, 'ctry', 'vra', oils_i18n_gettext('1299', 'Victoria ', 'ccvm', 'value')),
+ (1300, 'ctry', 'vtu', oils_i18n_gettext('1300', 'Vermont ', 'ccvm', 'value')),
+ (1301, 'ctry', 'wau', oils_i18n_gettext('1301', 'Washington (State) ', 'ccvm', 'value')),
+ (1302, 'ctry', 'wea', oils_i18n_gettext('1302', 'Western Australia ', 'ccvm', 'value')),
+ (1303, 'ctry', 'wf ', oils_i18n_gettext('1303', 'Wallis and Futuna ', 'ccvm', 'value')),
+ (1304, 'ctry', 'wiu', oils_i18n_gettext('1304', 'Wisconsin ', 'ccvm', 'value')),
+ (1305, 'ctry', 'wj ', oils_i18n_gettext('1305', 'West Bank of the Jordan River ', 'ccvm', 'value')),
+ (1306, 'ctry', 'wk ', oils_i18n_gettext('1306', 'Wake Island ', 'ccvm', 'value')),
+ (1307, 'ctry', 'wlk', oils_i18n_gettext('1307', 'Wales ', 'ccvm', 'value')),
+ (1308, 'ctry', 'ws ', oils_i18n_gettext('1308', 'Samoa ', 'ccvm', 'value')),
+ (1309, 'ctry', 'wvu', oils_i18n_gettext('1309', 'West Virginia ', 'ccvm', 'value')),
+ (1310, 'ctry', 'wyu', oils_i18n_gettext('1310', 'Wyoming ', 'ccvm', 'value')),
+ (1311, 'ctry', 'xa ', oils_i18n_gettext('1311', 'Christmas Island (Indian Ocean) ', 'ccvm', 'value')),
+ (1312, 'ctry', 'xb ', oils_i18n_gettext('1312', 'Cocos (Keeling) Islands ', 'ccvm', 'value')),
+ (1313, 'ctry', 'xc ', oils_i18n_gettext('1313', 'Maldives ', 'ccvm', 'value')),
+ (1314, 'ctry', 'xd ', oils_i18n_gettext('1314', 'Saint Kitts', 'ccvm', 'value')),
+ (1315, 'ctry', 'xe ', oils_i18n_gettext('1315', 'Marshall Islands ', 'ccvm', 'value')),
+ (1316, 'ctry', 'xf ', oils_i18n_gettext('1316', 'Midway Islands ', 'ccvm', 'value')),
+ (1317, 'ctry', 'xga', oils_i18n_gettext('1317', 'Coral Sea Islands Territory ', 'ccvm', 'value')),
+ (1318, 'ctry', 'xh ', oils_i18n_gettext('1318', 'Niue ', 'ccvm', 'value')),
+ (1319, 'ctry', 'xj ', oils_i18n_gettext('1319', 'Saint Helena ', 'ccvm', 'value')),
+ (1320, 'ctry', 'xk ', oils_i18n_gettext('1320', 'Saint Lucia ', 'ccvm', 'value')),
+ (1321, 'ctry', 'xl ', oils_i18n_gettext('1321', 'Saint Pierre and Miquelon ', 'ccvm', 'value')),
+ (1322, 'ctry', 'xm ', oils_i18n_gettext('1322', 'Saint Vincent and the Grenadines ', 'ccvm', 'value')),
+ (1323, 'ctry', 'xn ', oils_i18n_gettext('1323', 'Macedonia ', 'ccvm', 'value')),
+ (1324, 'ctry', 'xna', oils_i18n_gettext('1324', 'New South Wales ', 'ccvm', 'value')),
+ (1325, 'ctry', 'xo ', oils_i18n_gettext('1325', 'Slovakia ', 'ccvm', 'value')),
+ (1326, 'ctry', 'xoa', oils_i18n_gettext('1326', 'Northern Territory ', 'ccvm', 'value')),
+ (1327, 'ctry', 'xp ', oils_i18n_gettext('1327', 'Spratly Island ', 'ccvm', 'value')),
+ (1328, 'ctry', 'xr ', oils_i18n_gettext('1328', 'Czech Republic ', 'ccvm', 'value')),
+ (1329, 'ctry', 'xra', oils_i18n_gettext('1329', 'South Australia ', 'ccvm', 'value')),
+ (1330, 'ctry', 'xs ', oils_i18n_gettext('1330', 'South Georgia and the South Sandwich Islands ', 'ccvm', 'value')),
+ (1331, 'ctry', 'xv ', oils_i18n_gettext('1331', 'Slovenia ', 'ccvm', 'value')),
+ (1332, 'ctry', 'xx ', oils_i18n_gettext('1332', 'No place, unknown, or undetermined ', 'ccvm', 'value')),
+ (1333, 'ctry', 'xxc', oils_i18n_gettext('1333', 'Canada ', 'ccvm', 'value')),
+ (1334, 'ctry', 'xxk', oils_i18n_gettext('1334', 'United Kingdom ', 'ccvm', 'value')),
+ (1335, 'ctry', 'xxu', oils_i18n_gettext('1335', 'United States ', 'ccvm', 'value')),
+ (1336, 'ctry', 'ye ', oils_i18n_gettext('1336', 'Yemen ', 'ccvm', 'value')),
+ (1337, 'ctry', 'ykc', oils_i18n_gettext('1337', 'Yukon Territory ', 'ccvm', 'value')),
+ (1338, 'ctry', 'za ', oils_i18n_gettext('1338', 'Zambia ', 'ccvm', 'value')),
+
+ (1339, 'pub_status', 'b', oils_i18n_gettext('1339', 'No dates given; B.C. date involved', 'ccvm', 'value')),
+ (1340, 'pub_status', 'c', oils_i18n_gettext('1340', 'Continuing resource currently published', 'ccvm', 'value')),
+ (1341, 'pub_status', 'd', oils_i18n_gettext('1341', 'Continuing resource ceased publication', 'ccvm', 'value')),
+ (1342, 'pub_status', 'e', oils_i18n_gettext('1342', 'Detailed date', 'ccvm', 'value')),
+ (1343, 'pub_status', 'i', oils_i18n_gettext('1343', 'Inclusive dates of collection', 'ccvm', 'value')),
+ (1344, 'pub_status', 'k', oils_i18n_gettext('1344', 'Range of years of bulk of collection', 'ccvm', 'value')),
+ (1345, 'pub_status', 'm', oils_i18n_gettext('1345', 'Multiple dates', 'ccvm', 'value')),
+ (1346, 'pub_status', 'n', oils_i18n_gettext('1346', 'Dates unknown', 'ccvm', 'value')),
+ (1347, 'pub_status', 'p', oils_i18n_gettext('1347', 'Date of distribution/release/issue and production/recording session when different', 'ccvm', 'value')),
+ (1348, 'pub_status', 'q', oils_i18n_gettext('1348', 'Questionable date', 'ccvm', 'value')),
+ (1349, 'pub_status', 'r', oils_i18n_gettext('1349', 'Reprint/reissue date and original date', 'ccvm', 'value')),
+ (1350, 'pub_status', 's', oils_i18n_gettext('1350', 'Single known date/probable date', 'ccvm', 'value')),
+ (1351, 'pub_status', 't', oils_i18n_gettext('1351', 'Publication date and copyright date', 'ccvm', 'value')),
+ (1352, 'pub_status', 'u', oils_i18n_gettext('1352', 'Continuing resource status unknown', 'ccvm', 'value'));
+
+
+-- These are fixed fields that are made up of multiple single-character codes. These are the actual fields that are used to define relevent attributes,
+-- the "unnumbered" version of these fields are used for the MARC editor and as composite attributes for use in the OPAC if desired.
+-- i18n ids are left as-is because there's no need to have multiple translations for the same value.
+-- The ' ' codes only apply to the first position because if there's anything in pos 1 then the rest of the spaces are just filler.
+-- There's also no need for them to be opac visible because there will be composite attributes that OR these numbered attributes together.
+INSERT INTO config.coded_value_map (id, ctype, code, value, opac_visible) VALUES
+ (1353, 'accm1', ' ', oils_i18n_gettext('1735', 'No accompanying matter', 'ccvm', 'value'), FALSE),
+ (1354, 'accm1', 'a', oils_i18n_gettext('713', 'Discography', 'ccvm', 'value'), FALSE),
+ (1355, 'accm1', 'b', oils_i18n_gettext('714', 'Bibliography', 'ccvm', 'value'), FALSE),
+ (1356, 'accm1', 'c', oils_i18n_gettext('715', 'Thematic index', 'ccvm', 'value'), FALSE),
+ (1357, 'accm1', 'd', oils_i18n_gettext('716', 'Libretto or text', 'ccvm', 'value'), FALSE),
+ (1358, 'accm1', 'e', oils_i18n_gettext('717', 'Biography of composer or author', 'ccvm', 'value'), FALSE),
+ (1359, 'accm1', 'f', oils_i18n_gettext('718', 'Biography or performer or history of ensemble', 'ccvm', 'value'), FALSE),
+ (1360, 'accm1', 'g', oils_i18n_gettext('719', 'Technical and/or historical information on instruments', 'ccvm', 'value'), FALSE),
+ (1361, 'accm1', 'h', oils_i18n_gettext('720', 'Technical information on music', 'ccvm', 'value'), FALSE),
+ (1362, 'accm1', 'i', oils_i18n_gettext('721', 'Historical information', 'ccvm', 'value'), FALSE),
+ (1363, 'accm1', 'k', oils_i18n_gettext('722', 'Ethnological information', 'ccvm', 'value'), FALSE),
+ (1364, 'accm1', 'r', oils_i18n_gettext('723', 'Instructional materials', 'ccvm', 'value'), FALSE),
+ (1365, 'accm1', 's', oils_i18n_gettext('724', 'Music', 'ccvm', 'value'), FALSE),
+ (1366, 'accm1', 'z', oils_i18n_gettext('725', 'Other accompanying matter', 'ccvm', 'value'), FALSE),
+
+ (1367, 'accm2', 'a', oils_i18n_gettext('713', 'Discography', 'ccvm', 'value'), FALSE),
+ (1368, 'accm2', 'b', oils_i18n_gettext('714', 'Bibliography', 'ccvm', 'value'), FALSE),
+ (1369, 'accm2', 'c', oils_i18n_gettext('715', 'Thematic index', 'ccvm', 'value'), FALSE),
+ (1370, 'accm2', 'd', oils_i18n_gettext('716', 'Libretto or text', 'ccvm', 'value'), FALSE),
+ (1371, 'accm2', 'e', oils_i18n_gettext('717', 'Biography of composer or author', 'ccvm', 'value'), FALSE),
+ (1372, 'accm2', 'f', oils_i18n_gettext('718', 'Biography or performer or history of ensemble', 'ccvm', 'value'), FALSE),
+ (1373, 'accm2', 'g', oils_i18n_gettext('719', 'Technical and/or historical information on instruments', 'ccvm', 'value'), FALSE),
+ (1374, 'accm2', 'h', oils_i18n_gettext('720', 'Technical information on music', 'ccvm', 'value'), FALSE),
+ (1375, 'accm2', 'i', oils_i18n_gettext('721', 'Historical information', 'ccvm', 'value'), FALSE),
+ (1376, 'accm2', 'k', oils_i18n_gettext('722', 'Ethnological information', 'ccvm', 'value'), FALSE),
+ (1377, 'accm2', 'r', oils_i18n_gettext('723', 'Instructional materials', 'ccvm', 'value'), FALSE),
+ (1378, 'accm2', 's', oils_i18n_gettext('724', 'Music', 'ccvm', 'value'), FALSE),
+ (1379, 'accm2', 'z', oils_i18n_gettext('725', 'Other accompanying matter', 'ccvm', 'value'), FALSE),
+
+ (1380, 'accm3', 'a', oils_i18n_gettext('713', 'Discography', 'ccvm', 'value'), FALSE),
+ (1381, 'accm3', 'b', oils_i18n_gettext('714', 'Bibliography', 'ccvm', 'value'), FALSE),
+ (1382, 'accm3', 'c', oils_i18n_gettext('715', 'Thematic index', 'ccvm', 'value'), FALSE),
+ (1383, 'accm3', 'd', oils_i18n_gettext('716', 'Libretto or text', 'ccvm', 'value'), FALSE),
+ (1384, 'accm3', 'e', oils_i18n_gettext('717', 'Biography of composer or author', 'ccvm', 'value'), FALSE),
+ (1385, 'accm3', 'f', oils_i18n_gettext('718', 'Biography or performer or history of ensemble', 'ccvm', 'value'), FALSE),
+ (1386, 'accm3', 'g', oils_i18n_gettext('719', 'Technical and/or historical information on instruments', 'ccvm', 'value'), FALSE),
+ (1387, 'accm3', 'h', oils_i18n_gettext('720', 'Technical information on music', 'ccvm', 'value'), FALSE),
+ (1388, 'accm3', 'i', oils_i18n_gettext('721', 'Historical information', 'ccvm', 'value'), FALSE),
+ (1389, 'accm3', 'k', oils_i18n_gettext('722', 'Ethnological information', 'ccvm', 'value'), FALSE),
+ (1390, 'accm3', 'r', oils_i18n_gettext('723', 'Instructional materials', 'ccvm', 'value'), FALSE),
+ (1391, 'accm3', 's', oils_i18n_gettext('724', 'Music', 'ccvm', 'value'), FALSE),
+ (1392, 'accm3', 'z', oils_i18n_gettext('725', 'Other accompanying matter', 'ccvm', 'value'), FALSE),
+
+ (1393, 'accm4', 'a', oils_i18n_gettext('713', 'Discography', 'ccvm', 'value'), FALSE),
+ (1394, 'accm4', 'b', oils_i18n_gettext('714', 'Bibliography', 'ccvm', 'value'), FALSE),
+ (1395, 'accm4', 'c', oils_i18n_gettext('715', 'Thematic index', 'ccvm', 'value'), FALSE),
+ (1396, 'accm4', 'd', oils_i18n_gettext('716', 'Libretto or text', 'ccvm', 'value'), FALSE),
+ (1397, 'accm4', 'e', oils_i18n_gettext('717', 'Biography of composer or author', 'ccvm', 'value'), FALSE),
+ (1398, 'accm4', 'f', oils_i18n_gettext('718', 'Biography or performer or history of ensemble', 'ccvm', 'value'), FALSE),
+ (1399, 'accm4', 'g', oils_i18n_gettext('719', 'Technical and/or historical information on instruments', 'ccvm', 'value'), FALSE),
+ (1400, 'accm4', 'h', oils_i18n_gettext('720', 'Technical information on music', 'ccvm', 'value'), FALSE),
+ (1401, 'accm4', 'i', oils_i18n_gettext('721', 'Historical information', 'ccvm', 'value'), FALSE),
+ (1402, 'accm4', 'k', oils_i18n_gettext('722', 'Ethnological information', 'ccvm', 'value'), FALSE),
+ (1403, 'accm4', 'r', oils_i18n_gettext('723', 'Instructional materials', 'ccvm', 'value'), FALSE),
+ (1404, 'accm4', 's', oils_i18n_gettext('724', 'Music', 'ccvm', 'value'), FALSE),
+ (1405, 'accm4', 'z', oils_i18n_gettext('725', 'Other accompanying matter', 'ccvm', 'value'), FALSE),
+
+ (1406, 'accm5', 'a', oils_i18n_gettext('713', 'Discography', 'ccvm', 'value'), FALSE),
+ (1407, 'accm5', 'b', oils_i18n_gettext('714', 'Bibliography', 'ccvm', 'value'), FALSE),
+ (1408, 'accm5', 'c', oils_i18n_gettext('715', 'Thematic index', 'ccvm', 'value'), FALSE),
+ (1409, 'accm5', 'd', oils_i18n_gettext('716', 'Libretto or text', 'ccvm', 'value'), FALSE),
+ (1410, 'accm5', 'e', oils_i18n_gettext('717', 'Biography of composer or author', 'ccvm', 'value'), FALSE),
+ (1411, 'accm5', 'f', oils_i18n_gettext('718', 'Biography or performer or history of ensemble', 'ccvm', 'value'), FALSE),
+ (1412, 'accm5', 'g', oils_i18n_gettext('719', 'Technical and/or historical information on instruments', 'ccvm', 'value'), FALSE),
+ (1413, 'accm5', 'h', oils_i18n_gettext('720', 'Technical information on music', 'ccvm', 'value'), FALSE),
+ (1414, 'accm5', 'i', oils_i18n_gettext('721', 'Historical information', 'ccvm', 'value'), FALSE),
+ (1415, 'accm5', 'k', oils_i18n_gettext('722', 'Ethnological information', 'ccvm', 'value'), FALSE),
+ (1416, 'accm5', 'r', oils_i18n_gettext('723', 'Instructional materials', 'ccvm', 'value'), FALSE),
+ (1417, 'accm5', 's', oils_i18n_gettext('724', 'Music', 'ccvm', 'value'), FALSE),
+ (1418, 'accm5', 'z', oils_i18n_gettext('725', 'Other accompanying matter', 'ccvm', 'value'), FALSE),
+
+ (1419, 'accm6', 'a', oils_i18n_gettext('713', 'Discography', 'ccvm', 'value'), FALSE),
+ (1420, 'accm6', 'b', oils_i18n_gettext('714', 'Bibliography', 'ccvm', 'value'), FALSE),
+ (1421, 'accm6', 'c', oils_i18n_gettext('715', 'Thematic index', 'ccvm', 'value'), FALSE),
+ (1422, 'accm6', 'd', oils_i18n_gettext('716', 'Libretto or text', 'ccvm', 'value'), FALSE),
+ (1423, 'accm6', 'e', oils_i18n_gettext('717', 'Biography of composer or author', 'ccvm', 'value'), FALSE),
+ (1424, 'accm6', 'f', oils_i18n_gettext('718', 'Biography or performer or history of ensemble', 'ccvm', 'value'), FALSE),
+ (1425, 'accm6', 'g', oils_i18n_gettext('719', 'Technical and/or historical information on instruments', 'ccvm', 'value'), FALSE),
+ (1426, 'accm6', 'h', oils_i18n_gettext('720', 'Technical information on music', 'ccvm', 'value'), FALSE),
+ (1427, 'accm6', 'i', oils_i18n_gettext('721', 'Historical information', 'ccvm', 'value'), FALSE),
+ (1428, 'accm6', 'k', oils_i18n_gettext('722', 'Ethnological information', 'ccvm', 'value'), FALSE),
+ (1429, 'accm6', 'r', oils_i18n_gettext('723', 'Instructional materials', 'ccvm', 'value'), FALSE),
+ (1430, 'accm6', 's', oils_i18n_gettext('724', 'Music', 'ccvm', 'value'), FALSE),
+ (1431, 'accm6', 'z', oils_i18n_gettext('725', 'Other accompanying matter', 'ccvm', 'value'), FALSE),
+
+ (1432, 'cont1', ' ', oils_i18n_gettext('835', 'Not specified', 'ccvm', 'value'), FALSE),
+ (1433, 'cont1', 'a', oils_i18n_gettext('836', 'Abstracts/summaries', 'ccvm', 'value'), FALSE),
+ (1434, 'cont1', 'b', oils_i18n_gettext('837', 'Bibliographies', 'ccvm', 'value'), FALSE),
+ (1435, 'cont1', 'c', oils_i18n_gettext('838', 'Catalogs', 'ccvm', 'value'), FALSE),
+ (1436, 'cont1', 'd', oils_i18n_gettext('839', 'Dictionaries', 'ccvm', 'value'), FALSE),
+ (1437, 'cont1', 'e', oils_i18n_gettext('840', 'Encyclopedias', 'ccvm', 'value'), FALSE),
+ (1438, 'cont1', 'f', oils_i18n_gettext('841', 'Handbooks', 'ccvm', 'value'), FALSE),
+ (1439, 'cont1', 'g', oils_i18n_gettext('842', 'Legal articles', 'ccvm', 'value'), FALSE),
+ (1440, 'cont1', 'h', oils_i18n_gettext('843', 'Biography', 'ccvm', 'value'), FALSE),
+ (1441, 'cont1', 'i', oils_i18n_gettext('844', 'Indexes', 'ccvm', 'value'), FALSE),
+ (1442, 'cont1', 'j', oils_i18n_gettext('845', 'Patent document', 'ccvm', 'value'), FALSE),
+ (1443, 'cont1', 'k', oils_i18n_gettext('846', 'Discographies', 'ccvm', 'value'), FALSE),
+ (1444, 'cont1', 'l', oils_i18n_gettext('847', 'Legislation', 'ccvm', 'value'), FALSE),
+ (1445, 'cont1', 'm', oils_i18n_gettext('848', 'Theses', 'ccvm', 'value'), FALSE),
+ (1446, 'cont1', 'n', oils_i18n_gettext('849', 'Surveys of the literature in a subject area', 'ccvm', 'value'), FALSE),
+ (1447, 'cont1', 'o', oils_i18n_gettext('850', 'Reviews', 'ccvm', 'value'), FALSE),
+ (1448, 'cont1', 'p', oils_i18n_gettext('851', 'Programmed texts', 'ccvm', 'value'), FALSE),
+ (1449, 'cont1', 'q', oils_i18n_gettext('852', 'Filmographies', 'ccvm', 'value'), FALSE),
+ (1450, 'cont1', 'r', oils_i18n_gettext('853', 'Directories', 'ccvm', 'value'), FALSE),
+ (1451, 'cont1', 's', oils_i18n_gettext('854', 'Statistics', 'ccvm', 'value'), FALSE),
+ (1452, 'cont1', 't', oils_i18n_gettext('855', 'Technical reports', 'ccvm', 'value'), FALSE),
+ (1453, 'cont1', 'u', oils_i18n_gettext('856', 'Standards/specifications', 'ccvm', 'value'), FALSE),
+ (1454, 'cont1', 'v', oils_i18n_gettext('857', 'Legal cases and case notes', 'ccvm', 'value'), FALSE),
+ (1455, 'cont1', 'w', oils_i18n_gettext('858', 'Law reports and digests', 'ccvm', 'value'), FALSE),
+ (1456, 'cont1', 'x', oils_i18n_gettext('859', 'Other reports', 'ccvm', 'value'), FALSE),
+ (1457, 'cont1', 'y', oils_i18n_gettext('860', 'Yearbooks', 'ccvm', 'value'), FALSE),
+ (1458, 'cont1', 'z', oils_i18n_gettext('861', 'Treaties', 'ccvm', 'value'), FALSE),
+ (1459, 'cont1', '2', oils_i18n_gettext('862', 'Offprints', 'ccvm', 'value'), FALSE),
+ (1460, 'cont1', '5', oils_i18n_gettext('863', 'Calendars', 'ccvm', 'value'), FALSE),
+ (1461, 'cont1', '6', oils_i18n_gettext('864', 'Comics/graphic novels', 'ccvm', 'value'), FALSE),
+
+ (1462, 'cont2', 'a', oils_i18n_gettext('836', 'Abstracts/summaries', 'ccvm', 'value'), FALSE),
+ (1463, 'cont2', 'b', oils_i18n_gettext('837', 'Bibliographies', 'ccvm', 'value'), FALSE),
+ (1464, 'cont2', 'c', oils_i18n_gettext('838', 'Catalogs', 'ccvm', 'value'), FALSE),
+ (1465, 'cont2', 'd', oils_i18n_gettext('839', 'Dictionaries', 'ccvm', 'value'), FALSE),
+ (1466, 'cont2', 'e', oils_i18n_gettext('840', 'Encyclopedias', 'ccvm', 'value'), FALSE),
+ (1467, 'cont2', 'f', oils_i18n_gettext('841', 'Handbooks', 'ccvm', 'value'), FALSE),
+ (1468, 'cont2', 'g', oils_i18n_gettext('842', 'Legal articles', 'ccvm', 'value'), FALSE),
+ (1469, 'cont2', 'h', oils_i18n_gettext('843', 'Biography', 'ccvm', 'value'), FALSE),
+ (1470, 'cont2', 'i', oils_i18n_gettext('844', 'Indexes', 'ccvm', 'value'), FALSE),
+ (1471, 'cont2', 'j', oils_i18n_gettext('845', 'Patent document', 'ccvm', 'value'), FALSE),
+ (1472, 'cont2', 'k', oils_i18n_gettext('846', 'Discographies', 'ccvm', 'value'), FALSE),
+ (1473, 'cont2', 'l', oils_i18n_gettext('847', 'Legislation', 'ccvm', 'value'), FALSE),
+ (1474, 'cont2', 'm', oils_i18n_gettext('848', 'Theses', 'ccvm', 'value'), FALSE),
+ (1475, 'cont2', 'n', oils_i18n_gettext('849', 'Surveys of the literature in a subject area', 'ccvm', 'value'), FALSE),
+ (1476, 'cont2', 'o', oils_i18n_gettext('850', 'Reviews', 'ccvm', 'value'), FALSE),
+ (1477, 'cont2', 'p', oils_i18n_gettext('851', 'Programmed texts', 'ccvm', 'value'), FALSE),
+ (1478, 'cont2', 'q', oils_i18n_gettext('852', 'Filmographies', 'ccvm', 'value'), FALSE),
+ (1479, 'cont2', 'r', oils_i18n_gettext('853', 'Directories', 'ccvm', 'value'), FALSE),
+ (1480, 'cont2', 's', oils_i18n_gettext('854', 'Statistics', 'ccvm', 'value'), FALSE),
+ (1481, 'cont2', 't', oils_i18n_gettext('855', 'Technical reports', 'ccvm', 'value'), FALSE),
+ (1482, 'cont2', 'u', oils_i18n_gettext('856', 'Standards/specifications', 'ccvm', 'value'), FALSE),
+ (1483, 'cont2', 'v', oils_i18n_gettext('857', 'Legal cases and case notes', 'ccvm', 'value'), FALSE),
+ (1484, 'cont2', 'w', oils_i18n_gettext('858', 'Law reports and digests', 'ccvm', 'value'), FALSE),
+ (1485, 'cont2', 'x', oils_i18n_gettext('859', 'Other reports', 'ccvm', 'value'), FALSE),
+ (1486, 'cont2', 'y', oils_i18n_gettext('860', 'Yearbooks', 'ccvm', 'value'), FALSE),
+ (1487, 'cont2', 'z', oils_i18n_gettext('861', 'Treaties', 'ccvm', 'value'), FALSE),
+ (1488, 'cont2', '2', oils_i18n_gettext('862', 'Offprints', 'ccvm', 'value'), FALSE),
+ (1489, 'cont2', '5', oils_i18n_gettext('863', 'Calendars', 'ccvm', 'value'), FALSE),
+ (1490, 'cont2', '6', oils_i18n_gettext('864', 'Comics/graphic novels', 'ccvm', 'value'), FALSE),
+
+ (1491, 'cont3', 'a', oils_i18n_gettext('836', 'Abstracts/summaries', 'ccvm', 'value'), FALSE),
+ (1492, 'cont3', 'b', oils_i18n_gettext('837', 'Bibliographies', 'ccvm', 'value'), FALSE),
+ (1493, 'cont3', 'c', oils_i18n_gettext('838', 'Catalogs', 'ccvm', 'value'), FALSE),
+ (1494, 'cont3', 'd', oils_i18n_gettext('839', 'Dictionaries', 'ccvm', 'value'), FALSE),
+ (1495, 'cont3', 'e', oils_i18n_gettext('840', 'Encyclopedias', 'ccvm', 'value'), FALSE),
+ (1496, 'cont3', 'f', oils_i18n_gettext('841', 'Handbooks', 'ccvm', 'value'), FALSE),
+ (1497, 'cont3', 'g', oils_i18n_gettext('842', 'Legal articles', 'ccvm', 'value'), FALSE),
+ (1498, 'cont3', 'h', oils_i18n_gettext('843', 'Biography', 'ccvm', 'value'), FALSE),
+ (1499, 'cont3', 'i', oils_i18n_gettext('844', 'Indexes', 'ccvm', 'value'), FALSE),
+ (1500, 'cont3', 'j', oils_i18n_gettext('845', 'Patent document', 'ccvm', 'value'), FALSE),
+ (1501, 'cont3', 'k', oils_i18n_gettext('846', 'Discographies', 'ccvm', 'value'), FALSE),
+ (1502, 'cont3', 'l', oils_i18n_gettext('847', 'Legislation', 'ccvm', 'value'), FALSE),
+ (1503, 'cont3', 'm', oils_i18n_gettext('848', 'Theses', 'ccvm', 'value'), FALSE),
+ (1504, 'cont3', 'n', oils_i18n_gettext('849', 'Surveys of the literature in a subject area', 'ccvm', 'value'), FALSE),
+ (1505, 'cont3', 'o', oils_i18n_gettext('850', 'Reviews', 'ccvm', 'value'), FALSE),
+ (1506, 'cont3', 'p', oils_i18n_gettext('851', 'Programmed texts', 'ccvm', 'value'), FALSE),
+ (1507, 'cont3', 'q', oils_i18n_gettext('852', 'Filmographies', 'ccvm', 'value'), FALSE),
+ (1508, 'cont3', 'r', oils_i18n_gettext('853', 'Directories', 'ccvm', 'value'), FALSE),
+ (1509, 'cont3', 's', oils_i18n_gettext('854', 'Statistics', 'ccvm', 'value'), FALSE),
+ (1510, 'cont3', 't', oils_i18n_gettext('855', 'Technical reports', 'ccvm', 'value'), FALSE),
+ (1511, 'cont3', 'u', oils_i18n_gettext('856', 'Standards/specifications', 'ccvm', 'value'), FALSE),
+ (1512, 'cont3', 'v', oils_i18n_gettext('857', 'Legal cases and case notes', 'ccvm', 'value'), FALSE),
+ (1513, 'cont3', 'w', oils_i18n_gettext('858', 'Law reports and digests', 'ccvm', 'value'), FALSE),
+ (1514, 'cont3', 'x', oils_i18n_gettext('859', 'Other reports', 'ccvm', 'value'), FALSE),
+ (1515, 'cont3', 'y', oils_i18n_gettext('860', 'Yearbooks', 'ccvm', 'value'), FALSE),
+ (1516, 'cont3', 'z', oils_i18n_gettext('861', 'Treaties', 'ccvm', 'value'), FALSE),
+ (1517, 'cont3', '2', oils_i18n_gettext('862', 'Offprints', 'ccvm', 'value'), FALSE),
+ (1518, 'cont3', '5', oils_i18n_gettext('863', 'Calendars', 'ccvm', 'value'), FALSE),
+ (1519, 'cont3', '6', oils_i18n_gettext('864', 'Comics/graphic novels', 'ccvm', 'value'), FALSE),
+
+ (1520, 'cont4', 'a', oils_i18n_gettext('836', 'Abstracts/summaries', 'ccvm', 'value'), FALSE),
+ (1521, 'cont4', 'b', oils_i18n_gettext('837', 'Bibliographies', 'ccvm', 'value'), FALSE),
+ (1522, 'cont4', 'c', oils_i18n_gettext('838', 'Catalogs', 'ccvm', 'value'), FALSE),
+ (1523, 'cont4', 'd', oils_i18n_gettext('839', 'Dictionaries', 'ccvm', 'value'), FALSE),
+ (1524, 'cont4', 'e', oils_i18n_gettext('840', 'Encyclopedias', 'ccvm', 'value'), FALSE),
+ (1525, 'cont4', 'f', oils_i18n_gettext('841', 'Handbooks', 'ccvm', 'value'), FALSE),
+ (1526, 'cont4', 'g', oils_i18n_gettext('842', 'Legal articles', 'ccvm', 'value'), FALSE),
+ (1527, 'cont4', 'h', oils_i18n_gettext('843', 'Biography', 'ccvm', 'value'), FALSE),
+ (1528, 'cont4', 'i', oils_i18n_gettext('844', 'Indexes', 'ccvm', 'value'), FALSE),
+ (1529, 'cont4', 'j', oils_i18n_gettext('845', 'Patent document', 'ccvm', 'value'), FALSE),
+ (1530, 'cont4', 'k', oils_i18n_gettext('846', 'Discographies', 'ccvm', 'value'), FALSE),
+ (1531, 'cont4', 'l', oils_i18n_gettext('847', 'Legislation', 'ccvm', 'value'), FALSE),
+ (1532, 'cont4', 'm', oils_i18n_gettext('848', 'Theses', 'ccvm', 'value'), FALSE),
+ (1533, 'cont4', 'n', oils_i18n_gettext('849', 'Surveys of the literature in a subject area', 'ccvm', 'value'), FALSE),
+ (1534, 'cont4', 'o', oils_i18n_gettext('850', 'Reviews', 'ccvm', 'value'), FALSE),
+ (1535, 'cont4', 'p', oils_i18n_gettext('851', 'Programmed texts', 'ccvm', 'value'), FALSE),
+ (1536, 'cont4', 'q', oils_i18n_gettext('852', 'Filmographies', 'ccvm', 'value'), FALSE),
+ (1537, 'cont4', 'r', oils_i18n_gettext('853', 'Directories', 'ccvm', 'value'), FALSE),
+ (1538, 'cont4', 's', oils_i18n_gettext('854', 'Statistics', 'ccvm', 'value'), FALSE),
+ (1539, 'cont4', 't', oils_i18n_gettext('855', 'Technical reports', 'ccvm', 'value'), FALSE),
+ (1540, 'cont4', 'u', oils_i18n_gettext('856', 'Standards/specifications', 'ccvm', 'value'), FALSE),
+ (1541, 'cont4', 'v', oils_i18n_gettext('857', 'Legal cases and case notes', 'ccvm', 'value'), FALSE),
+ (1542, 'cont4', 'w', oils_i18n_gettext('858', 'Law reports and digests', 'ccvm', 'value'), FALSE),
+ (1543, 'cont4', 'x', oils_i18n_gettext('859', 'Other reports', 'ccvm', 'value'), FALSE),
+ (1544, 'cont4', 'y', oils_i18n_gettext('860', 'Yearbooks', 'ccvm', 'value'), FALSE),
+ (1545, 'cont4', 'z', oils_i18n_gettext('861', 'Treaties', 'ccvm', 'value'), FALSE),
+ (1546, 'cont4', '2', oils_i18n_gettext('862', 'Offprints', 'ccvm', 'value'), FALSE),
+ (1547, 'cont4', '5', oils_i18n_gettext('863', 'Calendars', 'ccvm', 'value'), FALSE),
+ (1548, 'cont4', '6', oils_i18n_gettext('864', 'Comics/graphic novels', 'ccvm', 'value'), FALSE),
+
+ (1549, 'ltxt1', ' ', oils_i18n_gettext('881', 'Item is a music sound recording', 'ccvm', 'value'), FALSE),
+ (1550, 'ltxt1', 'a', oils_i18n_gettext('882', 'Autobiography', 'ccvm', 'value'), FALSE),
+ (1551, 'ltxt1', 'b', oils_i18n_gettext('883', 'Biography', 'ccvm', 'value'), FALSE),
+ (1552, 'ltxt1', 'c', oils_i18n_gettext('884', 'Conference proceedings', 'ccvm', 'value'), FALSE),
+ (1553, 'ltxt1', 'd', oils_i18n_gettext('885', 'Drama', 'ccvm', 'value'), FALSE),
+ (1554, 'ltxt1', 'e', oils_i18n_gettext('886', 'Essays', 'ccvm', 'value'), FALSE),
+ (1555, 'ltxt1', 'f', oils_i18n_gettext('887', 'Fiction', 'ccvm', 'value'), FALSE),
+ (1556, 'ltxt1', 'g', oils_i18n_gettext('888', 'Reporting', 'ccvm', 'value'), FALSE),
+ (1557, 'ltxt1', 'h', oils_i18n_gettext('889', 'History', 'ccvm', 'value'), FALSE),
+ (1558, 'ltxt1', 'i', oils_i18n_gettext('890', 'Instruction', 'ccvm', 'value'), FALSE),
+ (1559, 'ltxt1', 'j', oils_i18n_gettext('891', 'Language instruction', 'ccvm', 'value'), FALSE),
+ (1560, 'ltxt1', 'k', oils_i18n_gettext('892', 'Comedy', 'ccvm', 'value'), FALSE),
+ (1561, 'ltxt1', 'l', oils_i18n_gettext('893', 'Lectures, speeches', 'ccvm', 'value'), FALSE),
+ (1562, 'ltxt1', 'm', oils_i18n_gettext('894', 'Memoirs', 'ccvm', 'value'), FALSE),
+ (1563, 'ltxt1', 'n', oils_i18n_gettext('895', 'Not applicable', 'ccvm', 'value'), FALSE),
+ (1564, 'ltxt1', 'o', oils_i18n_gettext('896', 'Folktales', 'ccvm', 'value'), FALSE),
+ (1565, 'ltxt1', 'p', oils_i18n_gettext('897', 'Poetry', 'ccvm', 'value'), FALSE),
+ (1566, 'ltxt1', 'r', oils_i18n_gettext('898', 'Rehearsals', 'ccvm', 'value'), FALSE),
+ (1567, 'ltxt1', 's', oils_i18n_gettext('899', 'Sounds', 'ccvm', 'value'), FALSE),
+ (1568, 'ltxt1', 't', oils_i18n_gettext('900', 'Interviews', 'ccvm', 'value'), FALSE),
+ (1569, 'ltxt1', 'z', oils_i18n_gettext('901', 'Other', 'ccvm', 'value'), FALSE),
+
+ (1570, 'ltxt2', 'a', oils_i18n_gettext('882', 'Autobiography', 'ccvm', 'value'), FALSE),
+ (1571, 'ltxt2', 'b', oils_i18n_gettext('883', 'Biography', 'ccvm', 'value'), FALSE),
+ (1572, 'ltxt2', 'c', oils_i18n_gettext('884', 'Conference proceedings', 'ccvm', 'value'), FALSE),
+ (1573, 'ltxt2', 'd', oils_i18n_gettext('885', 'Drama', 'ccvm', 'value'), FALSE),
+ (1574, 'ltxt2', 'e', oils_i18n_gettext('886', 'Essays', 'ccvm', 'value'), FALSE),
+ (1575, 'ltxt2', 'f', oils_i18n_gettext('887', 'Fiction', 'ccvm', 'value'), FALSE),
+ (1576, 'ltxt2', 'g', oils_i18n_gettext('888', 'Reporting', 'ccvm', 'value'), FALSE),
+ (1577, 'ltxt2', 'h', oils_i18n_gettext('889', 'History', 'ccvm', 'value'), FALSE),
+ (1578, 'ltxt2', 'i', oils_i18n_gettext('890', 'Instruction', 'ccvm', 'value'), FALSE),
+ (1579, 'ltxt2', 'j', oils_i18n_gettext('891', 'Language instruction', 'ccvm', 'value'), FALSE),
+ (1580, 'ltxt2', 'k', oils_i18n_gettext('892', 'Comedy', 'ccvm', 'value'), FALSE),
+ (1581, 'ltxt2', 'l', oils_i18n_gettext('893', 'Lectures, speeches', 'ccvm', 'value'), FALSE),
+ (1582, 'ltxt2', 'm', oils_i18n_gettext('894', 'Memoirs', 'ccvm', 'value'), FALSE),
+ (1583, 'ltxt2', 'n', oils_i18n_gettext('895', 'Not applicable', 'ccvm', 'value'), FALSE),
+ (1584, 'ltxt2', 'o', oils_i18n_gettext('896', 'Folktales', 'ccvm', 'value'), FALSE),
+ (1585, 'ltxt2', 'p', oils_i18n_gettext('897', 'Poetry', 'ccvm', 'value'), FALSE),
+ (1586, 'ltxt2', 'r', oils_i18n_gettext('898', 'Rehearsals', 'ccvm', 'value'), FALSE),
+ (1587, 'ltxt2', 's', oils_i18n_gettext('899', 'Sounds', 'ccvm', 'value'), FALSE),
+ (1588, 'ltxt2', 't', oils_i18n_gettext('900', 'Interviews', 'ccvm', 'value'), FALSE),
+ (1589, 'ltxt2', 'z', oils_i18n_gettext('901', 'Other', 'ccvm', 'value'), FALSE),
+
+ (1590, 'relf1', ' ', oils_i18n_gettext('965', 'No relief shown', 'ccvm', 'value'), FALSE),
+ (1591, 'relf1', 'a', oils_i18n_gettext('966', 'Contours', 'ccvm', 'value'), FALSE),
+ (1592, 'relf1', 'b', oils_i18n_gettext('967', 'Shading', 'ccvm', 'value'), FALSE),
+ (1593, 'relf1', 'c', oils_i18n_gettext('968', 'Gradient and bathymetric tints', 'ccvm', 'value'), FALSE),
+ (1594, 'relf1', 'd', oils_i18n_gettext('969', 'Hachures', 'ccvm', 'value'), FALSE),
+ (1595, 'relf1', 'e', oils_i18n_gettext('970', 'Bathymetry, soundings', 'ccvm', 'value'), FALSE),
+ (1596, 'relf1', 'f', oils_i18n_gettext('971', 'Form lines', 'ccvm', 'value'), FALSE),
+ (1597, 'relf1', 'g', oils_i18n_gettext('972', 'Spot heights', 'ccvm', 'value'), FALSE),
+ (1598, 'relf1', 'i', oils_i18n_gettext('973', 'Pictorially', 'ccvm', 'value'), FALSE),
+ (1599, 'relf1', 'j', oils_i18n_gettext('974', 'Land forms', 'ccvm', 'value'), FALSE),
+ (1600, 'relf1', 'k', oils_i18n_gettext('975', 'Bathymetry, isolines', 'ccvm', 'value'), FALSE),
+ (1601, 'relf1', 'm', oils_i18n_gettext('976', 'Rock drawings', 'ccvm', 'value'), FALSE),
+ (1602, 'relf1', 'z', oils_i18n_gettext('977', 'Other', 'ccvm', 'value'), FALSE),
+
+ (1603, 'relf2', 'a', oils_i18n_gettext('966', 'Contours', 'ccvm', 'value'), FALSE),
+ (1604, 'relf2', 'b', oils_i18n_gettext('967', 'Shading', 'ccvm', 'value'), FALSE),
+ (1605, 'relf2', 'c', oils_i18n_gettext('968', 'Gradient and bathymetric tints', 'ccvm', 'value'), FALSE),
+ (1606, 'relf2', 'd', oils_i18n_gettext('969', 'Hachures', 'ccvm', 'value'), FALSE),
+ (1607, 'relf2', 'e', oils_i18n_gettext('970', 'Bathymetry, soundings', 'ccvm', 'value'), FALSE),
+ (1608, 'relf2', 'f', oils_i18n_gettext('971', 'Form lines', 'ccvm', 'value'), FALSE),
+ (1609, 'relf2', 'g', oils_i18n_gettext('972', 'Spot heights', 'ccvm', 'value'), FALSE),
+ (1610, 'relf2', 'i', oils_i18n_gettext('973', 'Pictorially', 'ccvm', 'value'), FALSE),
+ (1611, 'relf2', 'j', oils_i18n_gettext('974', 'Land forms', 'ccvm', 'value'), FALSE),
+ (1612, 'relf2', 'k', oils_i18n_gettext('975', 'Bathymetry, isolines', 'ccvm', 'value'), FALSE),
+ (1613, 'relf2', 'm', oils_i18n_gettext('976', 'Rock drawings', 'ccvm', 'value'), FALSE),
+ (1614, 'relf2', 'z', oils_i18n_gettext('977', 'Other', 'ccvm', 'value'), FALSE),
+
+ (1615, 'relf3', 'a', oils_i18n_gettext('966', 'Contours', 'ccvm', 'value'), FALSE),
+ (1616, 'relf3', 'b', oils_i18n_gettext('967', 'Shading', 'ccvm', 'value'), FALSE),
+ (1617, 'relf3', 'c', oils_i18n_gettext('968', 'Gradient and bathymetric tints', 'ccvm', 'value'), FALSE),
+ (1618, 'relf3', 'd', oils_i18n_gettext('969', 'Hachures', 'ccvm', 'value'), FALSE),
+ (1619, 'relf3', 'e', oils_i18n_gettext('970', 'Bathymetry, soundings', 'ccvm', 'value'), FALSE),
+ (1620, 'relf3', 'f', oils_i18n_gettext('971', 'Form lines', 'ccvm', 'value'), FALSE),
+ (1621, 'relf3', 'g', oils_i18n_gettext('972', 'Spot heights', 'ccvm', 'value'), FALSE),
+ (1622, 'relf3', 'i', oils_i18n_gettext('973', 'Pictorially', 'ccvm', 'value'), FALSE),
+ (1623, 'relf3', 'j', oils_i18n_gettext('974', 'Land forms', 'ccvm', 'value'), FALSE),
+ (1624, 'relf3', 'k', oils_i18n_gettext('975', 'Bathymetry, isolines', 'ccvm', 'value'), FALSE),
+ (1625, 'relf3', 'm', oils_i18n_gettext('976', 'Rock drawings', 'ccvm', 'value'), FALSE),
+ (1626, 'relf3', 'z', oils_i18n_gettext('977', 'Other', 'ccvm', 'value'), FALSE),
+
+ (1627, 'relf4', 'a', oils_i18n_gettext('966', 'Contours', 'ccvm', 'value'), FALSE),
+ (1628, 'relf4', 'b', oils_i18n_gettext('967', 'Shading', 'ccvm', 'value'), FALSE),
+ (1629, 'relf4', 'c', oils_i18n_gettext('968', 'Gradient and bathymetric tints', 'ccvm', 'value'), FALSE),
+ (1630, 'relf4', 'd', oils_i18n_gettext('969', 'Hachures', 'ccvm', 'value'), FALSE),
+ (1631, 'relf4', 'e', oils_i18n_gettext('970', 'Bathymetry, soundings', 'ccvm', 'value'), FALSE),
+ (1632, 'relf4', 'f', oils_i18n_gettext('971', 'Form lines', 'ccvm', 'value'), FALSE),
+ (1633, 'relf4', 'g', oils_i18n_gettext('972', 'Spot heights', 'ccvm', 'value'), FALSE),
+ (1634, 'relf4', 'i', oils_i18n_gettext('973', 'Pictorially', 'ccvm', 'value'), FALSE),
+ (1635, 'relf4', 'j', oils_i18n_gettext('974', 'Land forms', 'ccvm', 'value'), FALSE),
+ (1636, 'relf4', 'k', oils_i18n_gettext('975', 'Bathymetry, isolines', 'ccvm', 'value'), FALSE),
+ (1637, 'relf4', 'm', oils_i18n_gettext('976', 'Rock drawings', 'ccvm', 'value'), FALSE),
+ (1638, 'relf4', 'z', oils_i18n_gettext('977', 'Other', 'ccvm', 'value'), FALSE),
+
+ (1639, 'spfm1', ' ', oils_i18n_gettext('978', 'No specified special format characteristics', 'ccvm', 'value'), FALSE),
+ (1640, 'spfm1', 'e', oils_i18n_gettext('979', 'Manuscript', 'ccvm', 'value'), FALSE),
+ (1641, 'spfm1', 'j', oils_i18n_gettext('980', 'Picture card, post card', 'ccvm', 'value'), FALSE),
+ (1642, 'spfm1', 'k', oils_i18n_gettext('981', 'Calendar', 'ccvm', 'value'), FALSE),
+ (1643, 'spfm1', 'l', oils_i18n_gettext('982', 'Puzzle', 'ccvm', 'value'), FALSE),
+ (1644, 'spfm1', 'n', oils_i18n_gettext('983', 'Game', 'ccvm', 'value'), FALSE),
+ (1645, 'spfm1', 'o', oils_i18n_gettext('984', 'Wall map', 'ccvm', 'value'), FALSE),
+ (1646, 'spfm1', 'p', oils_i18n_gettext('985', 'Playing cards', 'ccvm', 'value'), FALSE),
+ (1647, 'spfm1', 'r', oils_i18n_gettext('986', 'Loose-leaf', 'ccvm', 'value'), FALSE),
+ (1648, 'spfm1', 'z', oils_i18n_gettext('987', 'Other', 'ccvm', 'value'), FALSE),
+
+ (1649, 'spfm2', 'e', oils_i18n_gettext('979', 'Manuscript', 'ccvm', 'value'), FALSE),
+ (1650, 'spfm2', 'j', oils_i18n_gettext('980', 'Picture card, post card', 'ccvm', 'value'), FALSE),
+ (1651, 'spfm2', 'k', oils_i18n_gettext('981', 'Calendar', 'ccvm', 'value'), FALSE),
+ (1652, 'spfm2', 'l', oils_i18n_gettext('982', 'Puzzle', 'ccvm', 'value'), FALSE),
+ (1653, 'spfm2', 'n', oils_i18n_gettext('983', 'Game', 'ccvm', 'value'), FALSE),
+ (1654, 'spfm2', 'o', oils_i18n_gettext('984', 'Wall map', 'ccvm', 'value'), FALSE),
+ (1655, 'spfm2', 'p', oils_i18n_gettext('985', 'Playing cards', 'ccvm', 'value'), FALSE),
+ (1656, 'spfm2', 'r', oils_i18n_gettext('986', 'Loose-leaf', 'ccvm', 'value'), FALSE),
+ (1657, 'spfm2', 'z', oils_i18n_gettext('987', 'Other', 'ccvm', 'value'), FALSE),
+
+ (1658, 'ills', ' ', oils_i18n_gettext('1658', 'No Illustrations', 'ccvm', 'value'), FALSE),
+ (1659, 'ills', 'a', oils_i18n_gettext('1659', 'Illustrations', 'ccvm', 'value'), FALSE),
+ (1660, 'ills', 'b', oils_i18n_gettext('1660', 'Maps', 'ccvm', 'value'), FALSE),
+ (1661, 'ills', 'c', oils_i18n_gettext('1661', 'Portraits', 'ccvm', 'value'), FALSE),
+ (1662, 'ills', 'd', oils_i18n_gettext('1662', 'Charts', 'ccvm', 'value'), FALSE),
+ (1663, 'ills', 'e', oils_i18n_gettext('1663', 'Plans', 'ccvm', 'value'), FALSE),
+ (1664, 'ills', 'f', oils_i18n_gettext('1664', 'Plates', 'ccvm', 'value'), FALSE),
+ (1665, 'ills', 'g', oils_i18n_gettext('1665', 'Music', 'ccvm', 'value'), FALSE),
+ (1666, 'ills', 'h', oils_i18n_gettext('1666', 'Facsimiles', 'ccvm', 'value'), FALSE),
+ (1667, 'ills', 'i', oils_i18n_gettext('1667', 'Coats of arms', 'ccvm', 'value'), FALSE),
+ (1668, 'ills', 'j', oils_i18n_gettext('1668', 'Genealogical tables', 'ccvm', 'value'), FALSE),
+ (1669, 'ills', 'k', oils_i18n_gettext('1669', 'Forms', 'ccvm', 'value'), FALSE),
+ (1670, 'ills', 'l', oils_i18n_gettext('1670', 'Samples', 'ccvm', 'value'), FALSE),
+ (1671, 'ills', 'm', oils_i18n_gettext('1671', 'Phonodisc, phonowire, etc.', 'ccvm', 'value'), FALSE),
+ (1672, 'ills', 'o', oils_i18n_gettext('1672', 'Photographs', 'ccvm', 'value'), FALSE),
+ (1673, 'ills', 'p', oils_i18n_gettext('1673', 'Illuminations', 'ccvm', 'value'), FALSE),
+
+ (1674, 'ills1', ' ', oils_i18n_gettext('1658', 'No Illustrations', 'ccvm', 'value'), FALSE),
+ (1675, 'ills1', 'a', oils_i18n_gettext('1659', 'Illustrations', 'ccvm', 'value'), FALSE),
+ (1676, 'ills1', 'b', oils_i18n_gettext('1660', 'Maps', 'ccvm', 'value'), FALSE),
+ (1677, 'ills1', 'c', oils_i18n_gettext('1661', 'Portraits', 'ccvm', 'value'), FALSE),
+ (1678, 'ills1', 'd', oils_i18n_gettext('1662', 'Charts', 'ccvm', 'value'), FALSE),
+ (1679, 'ills1', 'e', oils_i18n_gettext('1663', 'Plans', 'ccvm', 'value'), FALSE),
+ (1680, 'ills1', 'f', oils_i18n_gettext('1664', 'Plates', 'ccvm', 'value'), FALSE),
+ (1681, 'ills1', 'g', oils_i18n_gettext('1665', 'Music', 'ccvm', 'value'), FALSE),
+ (1682, 'ills1', 'h', oils_i18n_gettext('1666', 'Facsimiles', 'ccvm', 'value'), FALSE),
+ (1683, 'ills1', 'i', oils_i18n_gettext('1667', 'Coats of arms', 'ccvm', 'value'), FALSE),
+ (1684, 'ills1', 'j', oils_i18n_gettext('1668', 'Genealogical tables', 'ccvm', 'value'), FALSE),
+ (1685, 'ills1', 'k', oils_i18n_gettext('1669', 'Forms', 'ccvm', 'value'), FALSE),
+ (1686, 'ills1', 'l', oils_i18n_gettext('1670', 'Samples', 'ccvm', 'value'), FALSE),
+ (1687, 'ills1', 'm', oils_i18n_gettext('1671', 'Phonodisc, phonowire, etc.', 'ccvm', 'value'), FALSE),
+ (1688, 'ills1', 'o', oils_i18n_gettext('1672', 'Photographs', 'ccvm', 'value'), FALSE),
+ (1689, 'ills1', 'p', oils_i18n_gettext('1673', 'Illuminations', 'ccvm', 'value'), FALSE),
+
+ (1690, 'ills2', 'a', oils_i18n_gettext('1659', 'Illustrations', 'ccvm', 'value'), FALSE),
+ (1691, 'ills2', 'b', oils_i18n_gettext('1660', 'Maps', 'ccvm', 'value'), FALSE),
+ (1692, 'ills2', 'c', oils_i18n_gettext('1661', 'Portraits', 'ccvm', 'value'), FALSE),
+ (1693, 'ills2', 'd', oils_i18n_gettext('1662', 'Charts', 'ccvm', 'value'), FALSE),
+ (1694, 'ills2', 'e', oils_i18n_gettext('1663', 'Plans', 'ccvm', 'value'), FALSE),
+ (1695, 'ills2', 'f', oils_i18n_gettext('1664', 'Plates', 'ccvm', 'value'), FALSE),
+ (1696, 'ills2', 'g', oils_i18n_gettext('1665', 'Music', 'ccvm', 'value'), FALSE),
+ (1697, 'ills2', 'h', oils_i18n_gettext('1666', 'Facsimiles', 'ccvm', 'value'), FALSE),
+ (1698, 'ills2', 'i', oils_i18n_gettext('1667', 'Coats of arms', 'ccvm', 'value'), FALSE),
+ (1699, 'ills2', 'j', oils_i18n_gettext('1668', 'Genealogical tables', 'ccvm', 'value'), FALSE),
+ (1700, 'ills2', 'k', oils_i18n_gettext('1669', 'Forms', 'ccvm', 'value'), FALSE),
+ (1701, 'ills2', 'l', oils_i18n_gettext('1670', 'Samples', 'ccvm', 'value'), FALSE),
+ (1702, 'ills2', 'm', oils_i18n_gettext('1671', 'Phonodisc, phonowire, etc.', 'ccvm', 'value'), FALSE),
+ (1703, 'ills2', 'o', oils_i18n_gettext('1672', 'Photographs', 'ccvm', 'value'), FALSE),
+ (1704, 'ills2', 'p', oils_i18n_gettext('1673', 'Illuminations', 'ccvm', 'value'), FALSE),
+
+ (1705, 'ills3', 'a', oils_i18n_gettext('1659', 'Illustrations', 'ccvm', 'value'), FALSE),
+ (1706, 'ills3', 'b', oils_i18n_gettext('1660', 'Maps', 'ccvm', 'value'), FALSE),
+ (1707, 'ills3', 'c', oils_i18n_gettext('1661', 'Portraits', 'ccvm', 'value'), FALSE),
+ (1708, 'ills3', 'd', oils_i18n_gettext('1662', 'Charts', 'ccvm', 'value'), FALSE),
+ (1709, 'ills3', 'e', oils_i18n_gettext('1663', 'Plans', 'ccvm', 'value'), FALSE),
+ (1710, 'ills3', 'f', oils_i18n_gettext('1664', 'Plates', 'ccvm', 'value'), FALSE),
+ (1711, 'ills3', 'g', oils_i18n_gettext('1665', 'Music', 'ccvm', 'value'), FALSE),
+ (1712, 'ills3', 'h', oils_i18n_gettext('1666', 'Facsimiles', 'ccvm', 'value'), FALSE),
+ (1713, 'ills3', 'i', oils_i18n_gettext('1667', 'Coats of arms', 'ccvm', 'value'), FALSE),
+ (1714, 'ills3', 'j', oils_i18n_gettext('1668', 'Genealogical tables', 'ccvm', 'value'), FALSE),
+ (1715, 'ills3', 'k', oils_i18n_gettext('1669', 'Forms', 'ccvm', 'value'), FALSE),
+ (1716, 'ills3', 'l', oils_i18n_gettext('1670', 'Samples', 'ccvm', 'value'), FALSE),
+ (1717, 'ills3', 'm', oils_i18n_gettext('1671', 'Phonodisc, phonowire, etc.', 'ccvm', 'value'), FALSE),
+ (1718, 'ills3', 'o', oils_i18n_gettext('1672', 'Photographs', 'ccvm', 'value'), FALSE),
+ (1719, 'ills3', 'p', oils_i18n_gettext('1673', 'Illuminations', 'ccvm', 'value'), FALSE),
+
+ (1720, 'ills4', 'a', oils_i18n_gettext('1659', 'Illustrations', 'ccvm', 'value'), FALSE),
+ (1721, 'ills4', 'b', oils_i18n_gettext('1660', 'Maps', 'ccvm', 'value'), FALSE),
+ (1722, 'ills4', 'c', oils_i18n_gettext('1661', 'Portraits', 'ccvm', 'value'), FALSE),
+ (1723, 'ills4', 'd', oils_i18n_gettext('1662', 'Charts', 'ccvm', 'value'), FALSE),
+ (1724, 'ills4', 'e', oils_i18n_gettext('1663', 'Plans', 'ccvm', 'value'), FALSE),
+ (1725, 'ills4', 'f', oils_i18n_gettext('1664', 'Plates', 'ccvm', 'value'), FALSE),
+ (1726, 'ills4', 'g', oils_i18n_gettext('1665', 'Music', 'ccvm', 'value'), FALSE),
+ (1727, 'ills4', 'h', oils_i18n_gettext('1666', 'Facsimiles', 'ccvm', 'value'), FALSE),
+ (1728, 'ills4', 'i', oils_i18n_gettext('1667', 'Coats of arms', 'ccvm', 'value'), FALSE),
+ (1729, 'ills4', 'j', oils_i18n_gettext('1668', 'Genealogical tables', 'ccvm', 'value'), FALSE),
+ (1730, 'ills4', 'k', oils_i18n_gettext('1669', 'Forms', 'ccvm', 'value'), FALSE),
+ (1731, 'ills4', 'l', oils_i18n_gettext('1670', 'Samples', 'ccvm', 'value'), FALSE),
+ (1732, 'ills4', 'm', oils_i18n_gettext('1671', 'Phonodisc, phonowire, etc.', 'ccvm', 'value'), FALSE),
+ (1733, 'ills4', 'o', oils_i18n_gettext('1672', 'Photographs', 'ccvm', 'value'), FALSE),
+ (1734, 'ills4', 'p', oils_i18n_gettext('1673', 'Illuminations', 'ccvm', 'value'), FALSE);
+
+
+-- Composite coded value maps, this way the "primary" fixed field can be used in advanced searches without a ton of ORs and extra work.
+-- Space is used as a filler for any position other than the first, so for something to actually have "No accompanying matter," for example, specifically accm1 must = ' '.
+-- Any other value has the same meaning in any position.
+INSERT INTO config.composite_attr_entry_definition (coded_value, definition) VALUES
+ (1735, '{"_attr":"accm1","_val":" "}'),
+ (713, '[{"_attr":"accm6","_val":"a"},{"_attr":"accm5","_val":"a"},{"_attr":"accm4","_val":"a"},{"_attr":"accm3","_val":"a"},{"_attr":"accm2","_val":"a"},{"_attr":"accm1","_val":"a"}]'),
+ (714, '[{"_attr":"accm6","_val":"b"},{"_attr":"accm5","_val":"b"},{"_attr":"accm4","_val":"b"},{"_attr":"accm3","_val":"b"},{"_attr":"accm2","_val":"b"},{"_attr":"accm1","_val":"b"}]'),
+ (715, '[{"_attr":"accm6","_val":"c"},{"_attr":"accm5","_val":"c"},{"_attr":"accm4","_val":"c"},{"_attr":"accm3","_val":"c"},{"_attr":"accm2","_val":"c"},{"_attr":"accm1","_val":"c"}]'),
+ (716, '[{"_attr":"accm6","_val":"d"},{"_attr":"accm5","_val":"d"},{"_attr":"accm4","_val":"d"},{"_attr":"accm3","_val":"d"},{"_attr":"accm2","_val":"d"},{"_attr":"accm1","_val":"d"}]'),
+ (717, '[{"_attr":"accm6","_val":"e"},{"_attr":"accm5","_val":"e"},{"_attr":"accm4","_val":"e"},{"_attr":"accm3","_val":"e"},{"_attr":"accm2","_val":"e"},{"_attr":"accm1","_val":"e"}]'),
+ (718, '[{"_attr":"accm6","_val":"f"},{"_attr":"accm5","_val":"f"},{"_attr":"accm4","_val":"f"},{"_attr":"accm3","_val":"f"},{"_attr":"accm2","_val":"f"},{"_attr":"accm1","_val":"f"}]'),
+ (719, '[{"_attr":"accm6","_val":"g"},{"_attr":"accm5","_val":"g"},{"_attr":"accm4","_val":"g"},{"_attr":"accm3","_val":"g"},{"_attr":"accm2","_val":"g"},{"_attr":"accm1","_val":"g"}]'),
+ (720, '[{"_attr":"accm6","_val":"h"},{"_attr":"accm5","_val":"h"},{"_attr":"accm4","_val":"h"},{"_attr":"accm3","_val":"h"},{"_attr":"accm2","_val":"h"},{"_attr":"accm1","_val":"h"}]'),
+ (721, '[{"_attr":"accm6","_val":"i"},{"_attr":"accm5","_val":"i"},{"_attr":"accm4","_val":"i"},{"_attr":"accm3","_val":"i"},{"_attr":"accm2","_val":"i"},{"_attr":"accm1","_val":"i"}]'),
+ (722, '[{"_attr":"accm6","_val":"k"},{"_attr":"accm5","_val":"k"},{"_attr":"accm4","_val":"k"},{"_attr":"accm3","_val":"k"},{"_attr":"accm2","_val":"k"},{"_attr":"accm1","_val":"k"}]'),
+ (723, '[{"_attr":"accm6","_val":"r"},{"_attr":"accm5","_val":"r"},{"_attr":"accm4","_val":"r"},{"_attr":"accm3","_val":"r"},{"_attr":"accm2","_val":"r"},{"_attr":"accm1","_val":"r"}]'),
+ (724, '[{"_attr":"accm6","_val":"s"},{"_attr":"accm5","_val":"s"},{"_attr":"accm4","_val":"s"},{"_attr":"accm3","_val":"s"},{"_attr":"accm2","_val":"s"},{"_attr":"accm1","_val":"s"}]'),
+ (725, '[{"_attr":"accm6","_val":"z"},{"_attr":"accm5","_val":"z"},{"_attr":"accm4","_val":"z"},{"_attr":"accm3","_val":"z"},{"_attr":"accm2","_val":"z"},{"_attr":"accm1","_val":"z"}]'),
+
+ (835, '{"_attr":"cont1","_val":" "}'),
+ (836, '[{"_attr":"cont4","_val":"a"},{"_attr":"cont3","_val":"a"},{"_attr":"cont2","_val":"a"},{"_attr":"cont1","_val":"a"}]'),
+ (837, '[{"_attr":"cont4","_val":"b"},{"_attr":"cont3","_val":"b"},{"_attr":"cont2","_val":"b"},{"_attr":"cont1","_val":"b"}]'),
+ (838, '[{"_attr":"cont4","_val":"c"},{"_attr":"cont3","_val":"c"},{"_attr":"cont2","_val":"c"},{"_attr":"cont1","_val":"c"}]'),
+ (839, '[{"_attr":"cont4","_val":"d"},{"_attr":"cont3","_val":"d"},{"_attr":"cont2","_val":"d"},{"_attr":"cont1","_val":"d"}]'),
+ (840, '[{"_attr":"cont4","_val":"e"},{"_attr":"cont3","_val":"e"},{"_attr":"cont2","_val":"e"},{"_attr":"cont1","_val":"e"}]'),
+ (841, '[{"_attr":"cont4","_val":"f"},{"_attr":"cont3","_val":"f"},{"_attr":"cont2","_val":"f"},{"_attr":"cont1","_val":"f"}]'),
+ (842, '[{"_attr":"cont4","_val":"g"},{"_attr":"cont3","_val":"g"},{"_attr":"cont2","_val":"g"},{"_attr":"cont1","_val":"g"}]'),
+ (843, '[{"_attr":"cont4","_val":"h"},{"_attr":"cont3","_val":"h"},{"_attr":"cont2","_val":"h"},{"_attr":"cont1","_val":"h"}]'),
+ (844, '[{"_attr":"cont4","_val":"i"},{"_attr":"cont3","_val":"i"},{"_attr":"cont2","_val":"i"},{"_attr":"cont1","_val":"i"}]'),
+ (845, '[{"_attr":"cont4","_val":"j"},{"_attr":"cont3","_val":"j"},{"_attr":"cont2","_val":"j"},{"_attr":"cont1","_val":"j"}]'),
+ (846, '[{"_attr":"cont4","_val":"k"},{"_attr":"cont3","_val":"k"},{"_attr":"cont2","_val":"k"},{"_attr":"cont1","_val":"k"}]'),
+ (847, '[{"_attr":"cont4","_val":"l"},{"_attr":"cont3","_val":"l"},{"_attr":"cont2","_val":"l"},{"_attr":"cont1","_val":"l"}]'),
+ (848, '[{"_attr":"cont4","_val":"m"},{"_attr":"cont3","_val":"m"},{"_attr":"cont2","_val":"m"},{"_attr":"cont1","_val":"m"}]'),
+ (849, '[{"_attr":"cont4","_val":"n"},{"_attr":"cont3","_val":"n"},{"_attr":"cont2","_val":"n"},{"_attr":"cont1","_val":"n"}]'),
+ (850, '[{"_attr":"cont4","_val":"o"},{"_attr":"cont3","_val":"o"},{"_attr":"cont2","_val":"o"},{"_attr":"cont1","_val":"o"}]'),
+ (851, '[{"_attr":"cont4","_val":"p"},{"_attr":"cont3","_val":"p"},{"_attr":"cont2","_val":"p"},{"_attr":"cont1","_val":"p"}]'),
+ (852, '[{"_attr":"cont4","_val":"q"},{"_attr":"cont3","_val":"q"},{"_attr":"cont2","_val":"q"},{"_attr":"cont1","_val":"q"}]'),
+ (853, '[{"_attr":"cont4","_val":"r"},{"_attr":"cont3","_val":"r"},{"_attr":"cont2","_val":"r"},{"_attr":"cont1","_val":"r"}]'),
+ (854, '[{"_attr":"cont4","_val":"s"},{"_attr":"cont3","_val":"s"},{"_attr":"cont2","_val":"s"},{"_attr":"cont1","_val":"s"}]'),
+ (855, '[{"_attr":"cont4","_val":"t"},{"_attr":"cont3","_val":"t"},{"_attr":"cont2","_val":"t"},{"_attr":"cont1","_val":"t"}]'),
+ (856, '[{"_attr":"cont4","_val":"u"},{"_attr":"cont3","_val":"u"},{"_attr":"cont2","_val":"u"},{"_attr":"cont1","_val":"u"}]'),
+ (857, '[{"_attr":"cont4","_val":"v"},{"_attr":"cont3","_val":"v"},{"_attr":"cont2","_val":"v"},{"_attr":"cont1","_val":"v"}]'),
+ (858, '[{"_attr":"cont4","_val":"w"},{"_attr":"cont3","_val":"w"},{"_attr":"cont2","_val":"w"},{"_attr":"cont1","_val":"w"}]'),
+ (859, '[{"_attr":"cont4","_val":"x"},{"_attr":"cont3","_val":"x"},{"_attr":"cont2","_val":"x"},{"_attr":"cont1","_val":"x"}]'),
+ (860, '[{"_attr":"cont4","_val":"y"},{"_attr":"cont3","_val":"y"},{"_attr":"cont2","_val":"y"},{"_attr":"cont1","_val":"y"}]'),
+ (861, '[{"_attr":"cont4","_val":"z"},{"_attr":"cont3","_val":"z"},{"_attr":"cont2","_val":"z"},{"_attr":"cont1","_val":"z"}]'),
+ (862, '[{"_attr":"cont4","_val":"2"},{"_attr":"cont3","_val":"2"},{"_attr":"cont2","_val":"2"},{"_attr":"cont1","_val":"2"}]'),
+ (863, '[{"_attr":"cont4","_val":"5"},{"_attr":"cont3","_val":"5"},{"_attr":"cont2","_val":"5"},{"_attr":"cont1","_val":"5"}]'),
+ (864, '[{"_attr":"cont4","_val":"6"},{"_attr":"cont3","_val":"6"},{"_attr":"cont2","_val":"6"},{"_attr":"cont1","_val":"6"}]'),
+
+ (881, '{"_attr":"ltxt1","_val":" "}'),
+ (882, '[{"_attr":"ltxt2","_val":"a"},{"_attr":"ltxt1","_val":"a"}]'),
+ (883, '[{"_attr":"ltxt2","_val":"b"},{"_attr":"ltxt1","_val":"b"}]'),
+ (884, '[{"_attr":"ltxt2","_val":"c"},{"_attr":"ltxt1","_val":"c"}]'),
+ (885, '[{"_attr":"ltxt2","_val":"d"},{"_attr":"ltxt1","_val":"d"}]'),
+ (886, '[{"_attr":"ltxt2","_val":"e"},{"_attr":"ltxt1","_val":"e"}]'),
+ (887, '[{"_attr":"ltxt2","_val":"f"},{"_attr":"ltxt1","_val":"f"}]'),
+ (888, '[{"_attr":"ltxt2","_val":"g"},{"_attr":"ltxt1","_val":"g"}]'),
+ (889, '[{"_attr":"ltxt2","_val":"h"},{"_attr":"ltxt1","_val":"h"}]'),
+ (890, '[{"_attr":"ltxt2","_val":"i"},{"_attr":"ltxt1","_val":"i"}]'),
+ (891, '[{"_attr":"ltxt2","_val":"j"},{"_attr":"ltxt1","_val":"j"}]'),
+ (892, '[{"_attr":"ltxt2","_val":"k"},{"_attr":"ltxt1","_val":"k"}]'),
+ (893, '[{"_attr":"ltxt2","_val":"l"},{"_attr":"ltxt1","_val":"l"}]'),
+ (894, '[{"_attr":"ltxt2","_val":"m"},{"_attr":"ltxt1","_val":"m"}]'),
+ (895, '[{"_attr":"ltxt2","_val":"n"},{"_attr":"ltxt1","_val":"n"}]'),
+ (896, '[{"_attr":"ltxt2","_val":"o"},{"_attr":"ltxt1","_val":"o"}]'),
+ (897, '[{"_attr":"ltxt2","_val":"p"},{"_attr":"ltxt1","_val":"p"}]'),
+ (898, '[{"_attr":"ltxt2","_val":"r"},{"_attr":"ltxt1","_val":"r"}]'),
+ (899, '[{"_attr":"ltxt2","_val":"s"},{"_attr":"ltxt1","_val":"s"}]'),
+ (900, '[{"_attr":"ltxt2","_val":"t"},{"_attr":"ltxt1","_val":"t"}]'),
+ (901, '[{"_attr":"ltxt2","_val":"z"},{"_attr":"ltxt1","_val":"z"}]'),
+
+ (965, '{"_attr":"relf1","_val":" "}'),
+ (966, '[{"_attr":"relf4","_val":"a"},{"_attr":"relf3","_val":"a"},{"_attr":"relf2","_val":"a"},{"_attr":"relf1","_val":"a"}]'),
+ (967, '[{"_attr":"relf4","_val":"b"},{"_attr":"relf3","_val":"b"},{"_attr":"relf2","_val":"b"},{"_attr":"relf1","_val":"b"}]'),
+ (968, '[{"_attr":"relf4","_val":"c"},{"_attr":"relf3","_val":"c"},{"_attr":"relf2","_val":"c"},{"_attr":"relf1","_val":"c"}]'),
+ (969, '[{"_attr":"relf4","_val":"d"},{"_attr":"relf3","_val":"d"},{"_attr":"relf2","_val":"d"},{"_attr":"relf1","_val":"d"}]'),
+ (970, '[{"_attr":"relf4","_val":"e"},{"_attr":"relf3","_val":"e"},{"_attr":"relf2","_val":"e"},{"_attr":"relf1","_val":"e"}]'),
+ (971, '[{"_attr":"relf4","_val":"f"},{"_attr":"relf3","_val":"f"},{"_attr":"relf2","_val":"f"},{"_attr":"relf1","_val":"f"}]'),
+ (972, '[{"_attr":"relf4","_val":"g"},{"_attr":"relf3","_val":"g"},{"_attr":"relf2","_val":"g"},{"_attr":"relf1","_val":"g"}]'),
+ (973, '[{"_attr":"relf4","_val":"i"},{"_attr":"relf3","_val":"i"},{"_attr":"relf2","_val":"i"},{"_attr":"relf1","_val":"i"}]'),
+ (974, '[{"_attr":"relf4","_val":"j"},{"_attr":"relf3","_val":"j"},{"_attr":"relf2","_val":"j"},{"_attr":"relf1","_val":"j"}]'),
+ (975, '[{"_attr":"relf4","_val":"k"},{"_attr":"relf3","_val":"k"},{"_attr":"relf2","_val":"k"},{"_attr":"relf1","_val":"k"}]'),
+ (976, '[{"_attr":"relf4","_val":"m"},{"_attr":"relf3","_val":"m"},{"_attr":"relf2","_val":"m"},{"_attr":"relf1","_val":"m"}]'),
+ (977, '[{"_attr":"relf4","_val":"z"},{"_attr":"relf3","_val":"z"},{"_attr":"relf2","_val":"z"},{"_attr":"relf1","_val":"z"}]'),
+
+ (978, '{"_attr":"spfm1","_val":" "}'),
+ (979, '[{"_attr":"spfm2","_val":"e"},{"_attr":"spfm1","_val":"e"}]'),
+ (980, '[{"_attr":"spfm2","_val":"j"},{"_attr":"spfm1","_val":"j"}]'),
+ (981, '[{"_attr":"spfm2","_val":"k"},{"_attr":"spfm1","_val":"k"}]'),
+ (982, '[{"_attr":"spfm2","_val":"l"},{"_attr":"spfm1","_val":"l"}]'),
+ (983, '[{"_attr":"spfm2","_val":"n"},{"_attr":"spfm1","_val":"n"}]'),
+ (984, '[{"_attr":"spfm2","_val":"o"},{"_attr":"spfm1","_val":"o"}]'),
+ (985, '[{"_attr":"spfm2","_val":"p"},{"_attr":"spfm1","_val":"p"}]'),
+ (986, '[{"_attr":"spfm2","_val":"r"},{"_attr":"spfm1","_val":"r"}]'),
+ (987, '[{"_attr":"spfm2","_val":"z"},{"_attr":"spfm1","_val":"z"}]'),
+
+ (1658, '{"_attr":"ills1","_val":" "}'),
+ (1659, '[{"_attr":"ills4","_val":"a"},{"_attr":"ills3","_val":"a"},{"_attr":"ills2","_val":"a"},{"_attr":"ills1","_val":"a"}]'),
+ (1660, '[{"_attr":"ills4","_val":"b"},{"_attr":"ills3","_val":"b"},{"_attr":"ills2","_val":"b"},{"_attr":"ills1","_val":"b"}]'),
+ (1661, '[{"_attr":"ills4","_val":"c"},{"_attr":"ills3","_val":"c"},{"_attr":"ills2","_val":"c"},{"_attr":"ills1","_val":"c"}]'),
+ (1662, '[{"_attr":"ills4","_val":"d"},{"_attr":"ills3","_val":"d"},{"_attr":"ills2","_val":"d"},{"_attr":"ills1","_val":"d"}]'),
+ (1663, '[{"_attr":"ills4","_val":"e"},{"_attr":"ills3","_val":"e"},{"_attr":"ills2","_val":"e"},{"_attr":"ills1","_val":"e"}]'),
+ (1664, '[{"_attr":"ills4","_val":"f"},{"_attr":"ills3","_val":"f"},{"_attr":"ills2","_val":"f"},{"_attr":"ills1","_val":"f"}]'),
+ (1665, '[{"_attr":"ills4","_val":"g"},{"_attr":"ills3","_val":"g"},{"_attr":"ills2","_val":"g"},{"_attr":"ills1","_val":"g"}]'),
+ (1666, '[{"_attr":"ills4","_val":"h"},{"_attr":"ills3","_val":"h"},{"_attr":"ills2","_val":"h"},{"_attr":"ills1","_val":"h"}]'),
+ (1667, '[{"_attr":"ills4","_val":"i"},{"_attr":"ills3","_val":"i"},{"_attr":"ills2","_val":"i"},{"_attr":"ills1","_val":"i"}]'),
+ (1668, '[{"_attr":"ills4","_val":"j"},{"_attr":"ills3","_val":"j"},{"_attr":"ills2","_val":"j"},{"_attr":"ills1","_val":"j"}]'),
+ (1669, '[{"_attr":"ills4","_val":"k"},{"_attr":"ills3","_val":"k"},{"_attr":"ills2","_val":"k"},{"_attr":"ills1","_val":"k"}]'),
+ (1670, '[{"_attr":"ills4","_val":"l"},{"_attr":"ills3","_val":"l"},{"_attr":"ills2","_val":"l"},{"_attr":"ills1","_val":"l"}]'),
+ (1671, '[{"_attr":"ills4","_val":"m"},{"_attr":"ills3","_val":"m"},{"_attr":"ills2","_val":"m"},{"_attr":"ills1","_val":"m"}]'),
+ (1672, '[{"_attr":"ills4","_val":"o"},{"_attr":"ills3","_val":"o"},{"_attr":"ills2","_val":"o"},{"_attr":"ills1","_val":"o"}]'),
+ (1673, '[{"_attr":"ills4","_val":"p"},{"_attr":"ills3","_val":"p"},{"_attr":"ills2","_val":"p"},{"_attr":"ills1","_val":"p"}]');
+
+SELECT evergreen.upgrade_deps_block_check('0968', :eg_version); -- jstompro/gmcharlt
+
+--create hook for actor.usr.create_date
+INSERT INTO action_trigger.hook (key, core_type, description, passive)
+ VALUES ('au.created', 'au', 'A user was created', 't');
+
+--SQL to create event definition for new account creation notice
+--Inactive, owned by top of org tree by default. Modify to suit needs.
+
+INSERT INTO action_trigger.event_definition (
+ active, owner, name, hook,
+ validator, reactor, delay, delay_field,
+ max_delay, template
+) VALUES (
+ 'f', '1', 'New User Created Welcome Notice', 'au.created',
+ 'NOOP_True', 'SendEmail', '10 seconds', 'create_date',
+ '1 day',
+$$
+[%- USE date -%]
+[%- user = target -%]
+[%- lib = target.home_ou -%]
+To: [%- params.recipient_email || user.email %]
+From: [%- helpers.get_org_setting(target.home_ou.id, 'org.bounced_emails') || lib.email || params.sender_email || default_sender %]
+Reply-To: [%- helpers.get_org_setting(target.home_ou.id, 'org.bounced_emails') || lib.email || params.sender_email || default_sender %]
+Subject: New Library Account Sign-up - Welcome!
+Auto-Submitted: auto-generated
+
+Dear [% user.first_given_name %] [% user.family_name %],
+
+Thank you for signing up for an account with the [% lib.name %] on [% user.create_date.substr(0, 10) %].
+
+This email is your confirmation that your account is set up and ready as well as testing to see that we have your correct email address.
+
+If you did not sign up for an account at the library and have received this email in error, please reply and let us know.
+
+You can access your account online at http://catalog/eg/opac/login. From that site you can search the catalog, request materials, renew materials, leave comments, leave suggestions for titles you would like the library to purchase and update your account information.
+
+Sincerely,
+[% lib.name %]
+
+Contact your library for more information:
+
+[% lib.name %]
+[%- SET addr = lib.mailing_address -%]
+[%- IF !addr -%] [%- SET addr = lib.billing_address -%] [%- END %]
+[% addr.street1 %] [% addr.street2 %]
+[% addr.city %], [% addr.state %]
+[% addr.post_code %]
+[% lib.phone %]
+[% lib.email %]
+
+$$);
+
+--insert environment values
+INSERT INTO action_trigger.environment (event_def, path) VALUES
+ (CURRVAL('action_trigger.event_definition_id_seq'), 'home_ou.mailing_address'),
+ (CURRVAL('action_trigger.event_definition_id_seq'), 'home_ou.billing_address');
+
+SELECT evergreen.upgrade_deps_block_check('0969', :eg_version); -- jeffdavis/stompro
+
+INSERT INTO config.org_unit_setting_type
+ (name, grp, label, description, datatype)
+ VALUES
+ ('org.restrict_opt_to_depth',
+ 'sec',
+ oils_i18n_gettext('org.restrict_opt_to_depth',
+ 'Restrict patron opt-in to home library and related orgs at specified depth',
+ 'coust', 'label'),
+ oils_i18n_gettext('org.restrict_opt_to_depth',
+ 'Patrons at this library can only be opted-in at org units which are within the '||
+ 'library''s section of the org tree, at or below the depth specified by this setting. '||
+ 'They cannot be opted in at any other libraries.',
+ 'coust', 'description'),
+ 'integer');
+
+SELECT evergreen.upgrade_deps_block_check('0970', :eg_version); -- Dyrcona/gmcharlt
+
+CREATE OR REPLACE FUNCTION search.facets_for_record_set(ignore_facet_classes TEXT[], hits BIGINT[]) RETURNS TABLE (id INT, value TEXT, count BIGINT) AS $$
+ SELECT id, value, count FROM (
+ SELECT mfae.field AS id,
+ mfae.value,
+ COUNT(DISTINCT mmrsm.source),
+ row_number() OVER (
+ PARTITION BY mfae.field ORDER BY COUNT(distinct mmrsm.source) DESC
+ ) AS rownum
+ FROM metabib.facet_entry mfae
+ JOIN metabib.metarecord_source_map mmrsm ON (mfae.source = mmrsm.source)
+ JOIN config.metabib_field cmf ON (cmf.id = mfae.field)
+ WHERE mmrsm.source IN (SELECT * FROM unnest($2))
+ AND cmf.facet_field
+ AND cmf.field_class NOT IN (SELECT * FROM unnest($1))
+ GROUP by 1, 2
+ ) all_facets
+ WHERE rownum <= (SELECT COALESCE((SELECT value::INT FROM config.global_flag WHERE name = 'search.max_facets_per_field' AND enabled), 1000));
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION search.facets_for_metarecord_set(ignore_facet_classes TEXT[], hits BIGINT[]) RETURNS TABLE (id INT, value TEXT, count BIGINT) AS $$
+ SELECT id, value, count FROM (
+ SELECT mfae.field AS id,
+ mfae.value,
+ COUNT(DISTINCT mmrsm.metarecord),
+ row_number() OVER (
+ PARTITION BY mfae.field ORDER BY COUNT(distinct mmrsm.metarecord) DESC
+ ) AS rownum
+ FROM metabib.facet_entry mfae
+ JOIN metabib.metarecord_source_map mmrsm ON (mfae.source = mmrsm.source)
+ JOIN config.metabib_field cmf ON (cmf.id = mfae.field)
+ WHERE mmrsm.metarecord IN (SELECT * FROM unnest($2))
+ AND cmf.facet_field
+ AND cmf.field_class NOT IN (SELECT * FROM unnest($1))
+ GROUP by 1, 2
+ ) all_facets
+ WHERE rownum <= (SELECT COALESCE((SELECT value::INT FROM config.global_flag WHERE name = 'search.max_facets_per_field' AND enabled), 1000));
+$$ LANGUAGE SQL;
+
+COMMIT;
+
+-- The following updates/inserts are allowed to fail
+
+INSERT INTO config.index_normalizer (name, description, func, param_count) VALUES (
+ 'Number or NULL Normalize',
+ 'Normalize the value to NULL if it is not a number',
+ 'integer_or_null',
+ 0
+);
+
+INSERT INTO config.index_normalizer (name, description, func, param_count) VALUES (
+ 'Approximate Low Date Normalize',
+ 'Normalize the value to the nearest date-ish value, rounding down',
+ 'approximate_low_date',
+ 0
+);
+
+INSERT INTO config.index_normalizer (name, description, func, param_count) VALUES (
+ 'Approximate High Date Normalize',
+ 'Normalize the value to the nearest date-ish value, rounding up',
+ 'approximate_high_date',
+ 0
+);
+
+INSERT INTO config.record_attr_index_norm_map (attr,norm,pos)
+ SELECT m.name, i.id, 0
+ FROM config.record_attr_definition m,
+ config.index_normalizer i
+ WHERE i.func IN ('integer_or_null')
+ AND m.name IN ('date2', 'pubdate');
+
+INSERT INTO config.record_attr_index_norm_map (attr,norm,pos)
+ SELECT m.name, i.id, 0
+ FROM config.record_attr_definition m,
+ config.index_normalizer i
+ WHERE i.func IN ('approximate_low_date')
+ AND m.name IN ('date1');
+
+INSERT INTO config.record_attr_index_norm_map (attr,norm,pos)
+ SELECT m.name, i.id, 0
+ FROM config.record_attr_definition m,
+ config.index_normalizer i
+ WHERE i.func IN ('approximate_high_date')
+ AND m.name IN ('date2');
+
+-- Get rid of bad date1 sorter values so we can avoid a reingest
+DELETE FROM metabib.record_sorter WHERE attr = 'pubdate' AND value !~ '^\d+$';
+
+-- and these are reingests that are allowed be interrupted
+\qecho
+\qecho To use the new identifier|genre index, it is necessary to do
+\qecho a partial reingest of records that have a 655 tag. You can
+\qecho cancel out of this if you wish and run this and the following
+\qecho attribute reingest later.
+\qecho
+SELECT metabib.reingest_metabib_field_entries(record, FALSE, TRUE, FALSE)
+FROM metabib.real_full_rec
+WHERE tag IN ('655')
+GROUP BY record;
+
+\qecho
+\qecho This is a record attribute reingest of your bib records.
+\qecho It will take a while.
+\qecho You may cancel now without losing the effect of the rest of the
+\qecho upgrade script, and arrange the reingest later.
+SELECT COUNT(metabib.reingest_record_attributes(id))
+ FROM biblio.record_entry WHERE deleted IS FALSE;