circ scripts
authorOpenSRF User <opensrf@flinflon.sitka.bclibraries.ca>
Tue, 24 Nov 2009 09:04:32 +0000 (01:04 -0800)
committerOpenSRF User <opensrf@flinflon.sitka.bclibraries.ca>
Tue, 24 Nov 2009 09:04:32 +0000 (01:04 -0800)
40 files changed:
catalog/biblio_descriptor.js [new file with mode: 0755]
catalog/biblio_fingerprint.js [new file with mode: 0755]
catalog/fixed_fields.js [new file with mode: 0755]
catalog/phys_char.js [new file with mode: 0755]
catalog/record_type.js [new file with mode: 0755]
circ/circ_duration.js [new file with mode: 0755]
circ/circ_groups.js [new file with mode: 0755]
circ/circ_item_config.js [new file with mode: 0755]
circ/circ_lib.js [new file with mode: 0755]
circ/circ_permit_copy.js [new file with mode: 0755]
circ/circ_permit_hold.js [new file with mode: 0755]
circ/circ_permit_patron.js [new file with mode: 0755]
circ/circ_permit_renew.js [new file with mode: 0755]
circ/config_BABM.js [new file with mode: 0644]
circ/config_BBUL.js [new file with mode: 0644]
circ/config_BCD.js [new file with mode: 0644]
circ/config_BCREK.js [new file with mode: 0644]
circ/config_BFN.js [new file with mode: 0644]
circ/config_BGI.js [new file with mode: 0644]
circ/config_BGSI.js [new file with mode: 0644]
circ/config_BH.js [new file with mode: 0644]
circ/config_BHA.js [new file with mode: 0644]
circ/config_BIN.js [new file with mode: 0644]
circ/config_BLP-BB.js [new file with mode: 0644]
circ/config_BLP.js [new file with mode: 0644]
circ/config_BM.js [new file with mode: 0644]
circ/config_BNA.js [new file with mode: 0644]
circ/config_BPE.js [new file with mode: 0644]
circ/config_BPR.js [new file with mode: 0644]
circ/config_BPRDP.js [new file with mode: 0644]
circ/config_BR.js [new file with mode: 0644]
circ/config_BS.js [new file with mode: 0644]
circ/config_BSA.js [new file with mode: 0644]
circ/config_BSE.js [new file with mode: 0644]
circ/config_BTE.js [new file with mode: 0644]
circ/config_BVALE.js [new file with mode: 0644]
circ/config_BVDH.js [new file with mode: 0644]
circ/config_BW.js [new file with mode: 0644]
circ/librarymap.js [new file with mode: 0644]
penalty/patron_penalty.js [new file with mode: 0755]

diff --git a/catalog/biblio_descriptor.js b/catalog/biblio_descriptor.js
new file mode 100755 (executable)
index 0000000..1c1d195
--- /dev/null
@@ -0,0 +1,29 @@
+// so we can tell if it's a book or other type
+load_lib('fmall.js');
+load_lib('fmgen.js');
+load_lib('record_type.js');
+load_lib('JSON_v1.js');
+
+var marcdoc = new XML(environment.marc);
+var marc_ns = new Namespace('http://www.loc.gov/MARC21/slim');
+
+default xml namespace = marc_ns;
+
+environment.result = new mrd();
+
+environment.result.item_type( extractFixedField( marcdoc, 'Type' ) );
+environment.result.item_form( extractFixedField( marcdoc, 'Form' ) );
+environment.result.bib_level( extractFixedField( marcdoc, 'BLvl' ) );
+environment.result.control_type( extractFixedField( marcdoc, 'Ctrl' ) );
+environment.result.enc_level( extractFixedField( marcdoc, 'ELvl' ) );
+environment.result.audience( extractFixedField( marcdoc, 'Audn' ) );
+environment.result.lit_form( extractFixedField( marcdoc, 'LitF' ) );
+environment.result.type_mat( extractFixedField( marcdoc, 'TMat' ) );
+environment.result.cat_form( extractFixedField( marcdoc, 'Desc' ) );
+environment.result.pub_status( extractFixedField( marcdoc, 'DtSt' ) );
+environment.result.item_lang( extractFixedField( marcdoc, 'Lang' ) );
+environment.result.date1( extractFixedField( marcdoc, 'Date1' ) );
+environment.result.date2( extractFixedField( marcdoc, 'Date2' ) );
+
+environment.result.vr_format( videorecordingFormatCode( marcdoc ) );
+
diff --git a/catalog/biblio_fingerprint.js b/catalog/biblio_fingerprint.js
new file mode 100755 (executable)
index 0000000..83992c2
--- /dev/null
@@ -0,0 +1,138 @@
+// so we can tell if it's a book or other type
+load_lib('record_type.js');
+load_lib('JSON_v1.js');
+
+environment.result = {};
+
+var marcdoc = new XML(environment.marc);
+var marc_ns = new Namespace('http://www.loc.gov/MARC21/slim');
+
+var modsdoc = new XML(environment.mods);
+var mods_ns = new Namespace('http://www.loc.gov/mods/');
+default xml namespace = marc_ns;
+
+//var mods3_ns = new Namespace('http://www.loc.gov/mods/v3');
+
+
+var rtype = recordType(marcdoc); // BKS, SER, VIS, MIX, MAP, SCO, REC, COM
+
+var quality = 0;
+var t = '';
+var a = '';
+
+try {
+       // first, related items entries (700t)
+       var t = marcdoc.datafield.( @tag == '700' ).subfield.( @code == 't');
+       if (!t.length()) throw "No title in related item added entry (700)";
+       
+       a = t.parent().subfield.( @code == 'a' );
+
+       quality += 10;
+
+       log_debug("title: " + t);
+       log_debug("author: " + a);
+} catch(e) {
+       log_debug(e);
+       log_debug("Looking in main entries");
+
+       var _t = '';
+       try {
+               try { 
+                       try { // uniform title
+                               _t = marcdoc.datafield.( @tag == '240' ).subfield.( @code == 'a' );
+                               if (!_t.length()) throw "No title in 240";
+                       } catch(e) { // translation of title
+                               log_debug(e);
+                               _t = marcdoc.datafield.( @tag == '242' ).subfield.( @code == 'a' );
+                               if (!_t.length()) throw "No title in 242";
+                       }
+               } catch(e) { // alternate title (not as note) 
+                       log_debug(e);
+                       _t = marcdoc.datafield.( @tag == '246' && !(@ind1.match(/0|1/)) ).subfield.( @code == 'a' );
+                       if (!_t.length()) throw "No title in 246";
+               }
+
+               t = _t[0];
+               log_debug("Title: " + t);
+               quality += 25;
+
+       } catch(e) {
+               log_debug(e);
+               log_debug("Using title proper (245a)");
+               t = marcdoc.datafield.( @tag == '245' ).subfield.( @code == 'a' );
+               t = t[0];
+               quality += 10;
+       }
+
+       try {
+               var _a = marcdoc.datafield.( @tag == '100' || @tag == '110' || @tag == '111').subfield.( @code == 'a' );
+               if (!_a.length()) throw "No author in 100, 110, 111";
+               
+               a = _a[0];
+               log_debug("Author: " + a);
+
+       } catch(e) {
+               log_debug(e);
+               log_debug("Trying to find a publisher (260b)");
+               a = marcdoc.datafield.( @tag == '260' ).subfield.( @code == 'b' );
+               a = a[0];
+       }
+}
+
+if (rtype != 'BKS') {
+       quality += marcdoc.datafield.length() / 2;
+} else {
+       quality += 40 + marcdoc.datafield.length();
+}
+
+var title = t;
+if (!title) {
+       log_debug("no title found");
+       title = '';
+} else {
+       title = title.toString();
+}
+
+title = title
+       .toLowerCase()
+       .replace(/\[.+?\]/,'')
+       .replace(/\bthe\b|\ban?d?\b|\W+/g,'');
+
+
+var author = a;
+if (!author) {
+       author = '';
+} else {
+       author = author.toString();
+}
+
+author = author.toLowerCase().replace(/^\s*(\w+).*?$/,"$1");
+
+environment.result.fingerprint = title + author;
+
+if (marcdoc.datafield.(@tag == '040').subfield.(@code == 'a').toString().match(/DLC/)) {
+       quality += 5;
+       log_debug( 'got DLC bump' );
+}
+
+if (marcdoc.datafield.(@tag == '039').subfield.(@code == 'b').toString().match(/oclc/i)) {
+       quality += 10;
+       log_debug( 'got OCLC source bump' );
+       
+} else if (marcdoc.datafield.(@tag == '039').subfield.(@code == 'b').toString().match(/isxn/i)) {
+       quality += 5;
+       log_debug( 'got ISxN source bump' );
+       
+} else if (marcdoc.datafield.(@tag == '039').subfield.(@code == 'b').toString().match(/local/i)) {
+       quality += 1;
+       log_debug( 'got Local source bump' );
+}
+
+if (extractFixedField(marcdoc, 'Lang') == 'eng') {
+       quality += 100;
+       log_debug( 'got language bump for ' + extractFixedField(marcdoc, 'Lang') );
+}
+
+
+environment.result.quality = quality;
+
diff --git a/catalog/fixed_fields.js b/catalog/fixed_fields.js
new file mode 100755 (executable)
index 0000000..4e7871c
--- /dev/null
@@ -0,0 +1,277 @@
+
+var rec_type = {
+        BKS : { Type : /[at]{1}/,      BLvl : /[acdm]{1}/ },
+       SER : { Type : /[a]{1}/,        BLvl : /[bsi]{1}/ },
+       VIS : { Type : /[gkro]{1}/,     BLvl : /[abcdmsi]{1}/ },
+       MIX : { Type : /[p]{1}/,        BLvl : /[cdi]{1}/ },
+       MAP : { Type : /[ef]{1}/,       BLvl : /[abcdmsi]{1}/ },
+       SCO : { Type : /[cd]{1}/,       BLvl : /[abcdmsi]{1}/ },
+       REC : { Type : /[ij]{1}/,       BLvl : /[abcdmsi]{1}/ },
+       COM : { Type : /[m]{1}/,        BLvl : /[abcdmsi]{1}/ }
+};
+
+var ff_pos = {
+       Ctry : {
+               _8 : {
+                       BKS : {start : 15, len : 3, def : ' ' },
+                       SER : {start : 15, len : 3, def : ' ' },
+                       VIS : {start : 15, len : 3, def : ' ' },
+                       MIX : {start : 15, len : 3, def : ' ' },
+                       MAP : {start : 15, len : 3, def : ' ' },
+                       SCO : {start : 15, len : 3, def : ' ' },
+                       REC : {start : 15, len : 3, def : ' ' },
+                       COM : {start : 15, len : 3, def : ' ' },
+               }
+       },
+       Lang : {
+               _8 : {
+                       BKS : {start : 35, len : 3, def : ' ' },
+                       SER : {start : 35, len : 3, def : ' ' },
+                       VIS : {start : 35, len : 3, def : ' ' },
+                       MIX : {start : 35, len : 3, def : ' ' },
+                       MAP : {start : 35, len : 3, def : ' ' },
+                       SCO : {start : 35, len : 3, def : ' ' },
+                       REC : {start : 35, len : 3, def : ' ' },
+                       COM : {start : 35, len : 3, def : ' ' },
+               }
+       },
+       MRec : {
+               _8 : {
+                       BKS : {start : 38, len : 1, def : ' ' },
+                       SER : {start : 38, len : 1, def : ' ' },
+                       VIS : {start : 38, len : 1, def : ' ' },
+                       MIX : {start : 38, len : 1, def : ' ' },
+                       MAP : {start : 38, len : 1, def : ' ' },
+                       SCO : {start : 38, len : 1, def : ' ' },
+                       REC : {start : 38, len : 1, def : ' ' },
+                       COM : {start : 38, len : 1, def : ' ' },
+               }
+       },
+       DtSt : {
+               _8 : {
+                       BKS : {start : 6, len : 1, def : ' ' },
+                       SER : {start : 6, len : 1, def : 'c' },
+                       VIS : {start : 6, len : 1, def : ' ' },
+                       MIX : {start : 6, len : 1, def : ' ' },
+                       MAP : {start : 6, len : 1, def : ' ' },
+                       SCO : {start : 6, len : 1, def : ' ' },
+                       REC : {start : 6, len : 1, def : ' ' },
+                       COM : {start : 6, len : 1, def : ' ' },
+               }
+       },
+       Type : {
+               ldr : {
+                       BKS : {start : 6, len : 1, def : 'a' },
+                       SER : {start : 6, len : 1, def : 'a' },
+                       VIS : {start : 6, len : 1, def : 'g' },
+                       MIX : {start : 6, len : 1, def : 'p' },
+                       MAP : {start : 6, len : 1, def : 'e' },
+                       SCO : {start : 6, len : 1, def : 'c' },
+                       REC : {start : 6, len : 1, def : 'i' },
+                       COM : {start : 6, len : 1, def : 'm' },
+               }
+       },
+       Ctrl : {
+               ldr : {
+                       BKS : {start : 8, len : 1, def : ' ' },
+                       SER : {start : 8, len : 1, def : ' ' },
+                       VIS : {start : 8, len : 1, def : ' ' },
+                       MIX : {start : 8, len : 1, def : ' ' },
+                       MAP : {start : 8, len : 1, def : ' ' },
+                       SCO : {start : 8, len : 1, def : ' ' },
+                       REC : {start : 8, len : 1, def : ' ' },
+                       COM : {start : 8, len : 1, def : ' ' },
+               }
+       },
+       BLvl : {
+               ldr : {
+                       BKS : {start : 7, len : 1, def : 'm' },
+                       SER : {start : 7, len : 1, def : 's' },
+                       VIS : {start : 7, len : 1, def : 'm' },
+                       MIX : {start : 7, len : 1, def : 'c' },
+                       MAP : {start : 7, len : 1, def : 'm' },
+                       SCO : {start : 7, len : 1, def : 'm' },
+                       REC : {start : 7, len : 1, def : 'm' },
+                       COM : {start : 7, len : 1, def : 'm' },
+               }
+       },
+       Desc : {
+               ldr : {
+                       BKS : {start : 18, len : 1, def : ' ' },
+                       SER : {start : 18, len : 1, def : ' ' },
+                       VIS : {start : 18, len : 1, def : ' ' },
+                       MIX : {start : 18, len : 1, def : ' ' },
+                       MAP : {start : 18, len : 1, def : ' ' },
+                       SCO : {start : 18, len : 1, def : ' ' },
+                       REC : {start : 18, len : 1, def : ' ' },
+                       COM : {start : 18, len : 1, def : ' ' },
+               }
+       },
+       ELvl : {
+               ldr : {
+                       BKS : {start : 17, len : 1, def : ' ' },
+                       SER : {start : 17, len : 1, def : ' ' },
+                       VIS : {start : 17, len : 1, def : ' ' },
+                       MIX : {start : 17, len : 1, def : ' ' },
+                       MAP : {start : 17, len : 1, def : ' ' },
+                       SCO : {start : 17, len : 1, def : ' ' },
+                       REC : {start : 17, len : 1, def : ' ' },
+                       COM : {start : 17, len : 1, def : ' ' },
+               }
+       },
+       TMat : {
+               _8 : {
+                       VIS : {start : 33, len : 1, def : ' ' },
+               },
+               _6 : {
+                       VIS : {start : 16, len : 1, def : ' ' },
+               }
+       },
+       Indx : {
+               _8 : {
+                       BKS : {start : 31, len : 1, def : '0' },
+                       MAP : {start : 31, len : 1, def : '0' },
+               },
+               _6 : {
+                       BKS : {start : 14, len : 1, def : '0' },
+                       MAP : {start : 14, len : 1, def : '0' },
+               }
+       },
+       Date1 : {
+               _8 : {
+                       BKS : {start : 7, len : 4, def : ' ' },
+                       SER : {start : 7, len : 4, def : ' ' },
+                       VIS : {start : 7, len : 4, def : ' ' },
+                       MIX : {start : 7, len : 4, def : ' ' },
+                       MAP : {start : 7, len : 4, def : ' ' },
+                       SCO : {start : 7, len : 4, def : ' ' },
+                       REC : {start : 7, len : 4, def : ' ' },
+                       COM : {start : 7, len : 4, def : ' ' },
+               },
+       },
+       Date2 : {
+               _8 : {
+                       BKS : {start : 11, len : 4, def : ' ' },
+                       SER : {start : 11, len : 4, def : '9' },
+                       VIS : {start : 11, len : 4, def : ' ' },
+                       MIX : {start : 11, len : 4, def : ' ' },
+                       MAP : {start : 11, len : 4, def : ' ' },
+                       SCO : {start : 11, len : 4, def : ' ' },
+                       REC : {start : 11, len : 4, def : ' ' },
+                       COM : {start : 11, len : 4, def : ' ' },
+               },
+       },
+       LitF : {
+               _8 : {
+                       BKS : {start : 33, len : 1, def : '0' },
+               },
+               _6 : {
+                       BKS : {start : 16, len : 1, def : '0' },
+               }
+       },
+       Biog : {
+               _8 : {
+                       BKS : {start : 34, len : 1, def : ' ' },
+               },
+               _6 : {
+                       BKS : {start : 17, len : 1, def : ' ' },
+               }
+       },
+       Ills : {
+               _8 : {
+                       BKS : {start : 18, len : 4, def : ' ' },
+               },
+               _6 : {
+                       BKS : {start : 1, len : 4, def : ' ' },
+               }
+       },
+       Fest : {
+               _8 : {
+                       BKS : {start : 30, len : 1, def : '0' },
+               },
+               _6 : {
+                       BKS : {start : 13, len : 1, def : '0' },
+               }
+       },
+       Conf : {
+               _8 : {
+                       BKS : {start : 24, len : 4, def : ' ' },
+                       SER : {start : 25, len : 3, def : ' ' },
+               },
+               _6 : {
+                       BKS : {start : 7, len : 4, def : ' ' },
+                       SER : {start : 8, len : 3, def : ' ' },
+               }
+       },
+       GPub : {
+               _8 : {
+                       BKS : {start : 28, len : 1, def : ' ' },
+                       SER : {start : 28, len : 1, def : ' ' },
+                       VIS : {start : 28, len : 1, def : ' ' },
+                       MAP : {start : 28, len : 1, def : ' ' },
+                       COM : {start : 28, len : 1, def : ' ' },
+               },
+               _6 : {
+                       BKS : {start : 11, len : 1, def : ' ' },
+                       SER : {start : 11, len : 1, def : ' ' },
+                       VIS : {start : 11, len : 1, def : ' ' },
+                       MAP : {start : 11, len : 1, def : ' ' },
+                       COM : {start : 11, len : 1, def : ' ' },
+               }
+       },
+       Audn : {
+               _8 : {
+                       BKS : {start : 22, len : 1, def : ' ' },
+                       SER : {start : 22, len : 1, def : ' ' },
+                       VIS : {start : 22, len : 1, def : ' ' },
+                       SCO : {start : 22, len : 1, def : ' ' },
+                       REC : {start : 22, len : 1, def : ' ' },
+                       COM : {start : 22, len : 1, def : ' ' },
+               },
+               _6 : {
+                       BKS : {start : 5, len : 1, def : ' ' },
+                       SER : {start : 5, len : 1, def : ' ' },
+                       VIS : {start : 5, len : 1, def : ' ' },
+                       SCO : {start : 5, len : 1, def : ' ' },
+                       REC : {start : 5, len : 1, def : ' ' },
+                       COM : {start : 5, len : 1, def : ' ' },
+               }
+       },
+       Form : {
+               _8 : {
+                       BKS : {start : 23, len : 1, def : ' ' },
+                       SER : {start : 23, len : 1, def : ' ' },
+                       VIS : {start : 29, len : 1, def : ' ' },
+                       MIX : {start : 23, len : 1, def : ' ' },
+                       MAP : {start : 29, len : 1, def : ' ' },
+                       SCO : {start : 23, len : 1, def : ' ' },
+                       REC : {start : 23, len : 1, def : ' ' },
+               },
+               _6 : {
+                       BKS : {start : 6, len : 1, def : ' ' },
+                       SER : {start : 6, len : 1, def : ' ' },
+                       VIS : {start : 12, len : 1, def : ' ' },
+                       MIX : {start : 6, len : 1, def : ' ' },
+                       MAP : {start : 12, len : 1, def : ' ' },
+                       SCO : {start : 6, len : 1, def : ' ' },
+                       REC : {start : 6, len : 1, def : ' ' },
+               }
+       },
+       'S/L' : {
+               _8 : {
+                       SER : {start : 34, len : 1, def : '0' },
+               },
+               _6 : {
+                       SER : {start : 17, len : 1, def : '0' },
+               }
+       },
+       'Alph' : {
+               _8 : {
+                       SER : {start : 33, len : 1, def : ' ' },
+               },
+               _6 : {
+                       SER : {start : 16, len : 1, def : ' ' },
+               }
+       },
+};
+
diff --git a/catalog/phys_char.js b/catalog/phys_char.js
new file mode 100755 (executable)
index 0000000..4a6ba8d
--- /dev/null
@@ -0,0 +1,1062 @@
+var physical_characteristics  = {
+       c : {
+               label     : "Electronic Resource",
+               subfields : {
+                       b : {   start : 1,
+                               len   : 1,
+                               label : "SMD",
+                               values: {       a : "Tape Cartridge",
+                                               b : "Chip cartridge",
+                                               c : "Computer optical disk cartridge",
+                                               f : "Tape cassette",
+                                               h : "Tape reel",
+                                               j : "Magnetic disk",
+                                               m : "Magneto-optical disk",
+                                               o : "Optical disk",
+                                               r : "Remote",
+                                               u : "Unspecified",
+                                               z : "Other",
+                               },
+                       },
+                       d : {   start : 3,
+                               len   : 1,
+                               label : "Color",
+                               values: {       a : "One color",
+                                               b : "Black-and-white",
+                                               c : "Multicolored",
+                                               g : "Gray scale",
+                                               m : "Mixed",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       e : {   start : 4,
+                               len   : 1,
+                               label : "Dimensions",
+                               values: {       a : "3 1/2 in.",
+                                               e : "12 in.",
+                                               g : "4 3/4 in. or 12 cm.",
+                                               i : "1 1/8 x 2 3/8 in.",
+                                               j : "3 7/8 x 2 1/2 in.",
+                                               n : "Not applicable",
+                                               o : "5 1/4 in.",
+                                               u : "Unknown",
+                                               v : "8 in.",
+                                               z : "Other",
+                               },
+                       },
+                       f : {   start : 5,
+                               len   : 1,
+                               label : "Sound",
+                               values: {       ' ' : "No sound (Silent)",
+                                               a   : "Sound",
+                                               u   : "Unknown",
+                               },
+                       },
+                       g : {   start : 6,
+                               len   : 3,
+                               label : "Image bit depth",
+                               values: {       mmm   : "Multiple",
+                                               nnn   : "Not applicable",
+                                               '---' : "Unknown",
+                               },
+                       },
+                       h : {   start : 9,
+                               len   : 1,
+                               label : "File formats",
+                               values: {       a : "One file format",
+                                               m : "Multiple file formats",
+                                               u : "Unknown",
+                               },
+                       },
+                       i : {   start : 10,
+                               len   : 1,
+                               label : "Quality assurance target(s)",
+                               values: {       a : "Absent",
+                                               n : "Not applicable",
+                                               p : "Present",
+                                               u : "Unknown",
+                               },
+                       },
+                       j : {   start : 11,
+                               len   : 1,
+                               label : "Antecedent/Source",
+                               values: {       a : "File reproduced from original",
+                                               b : "File reproduced from microform",
+                                               c : "File reproduced from electronic resource",
+                                               d : "File reproduced from an intermediate (not microform)",
+                                               m : "Mixed",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                               },
+                       },
+                       k : {   start : 12,
+                               len   : 1,
+                               label : "Level of compression",
+                               values: {       a : "Uncompressed",
+                                               b : "Lossless",
+                                               d : "Lossy",
+                                               m : "Mixed",
+                                               u : "Unknown",
+                               },
+                       },
+                       l : {   start : 13,
+                               len   : 1,
+                               label : "Reformatting quality",
+                               values: {       a : "Access",
+                                               n : "Not applicable",
+                                               p : "Preservation",
+                                               r : "Replacement",
+                                               u : "Unknown",
+                               },
+                       },
+               },
+       },
+       d : {
+               label     : "Globe",
+               subfields : {
+                       b : {   start : 1,
+                               len   : 1,
+                               label : "SMD",
+                               values: {       a : "Celestial globe",
+                                               b : "Planetary or lunar globe",
+                                               c : "Terrestrial globe",
+                                               e : "Earth moon globe",
+                                               u : "Unspecified",
+                                               z : "Other",
+                               },
+                       },
+                       d : {   start : 3,
+                               len   : 1,
+                               label : "Color",
+                               values: {       a : "One color",
+                                               c : "Multicolored",
+                               },
+                       },
+                       e : {   start : 4,
+                               len   : 1,
+                               label : "Physical medium",
+                               values: {       a : "Paper",
+                                               b : "Wood",
+                                               c : "Stone",
+                                               d : "Metal",
+                                               e : "Synthetics",
+                                               f : "Skins",
+                                               g : "Textile",
+                                               p : "Plaster",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       f : {   start : 5,
+                               len   : 1,
+                               label : "Type of reproduction",
+                               values: {       f : "Facsimile",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+               },
+       },
+       a : {
+               label     : "Map",
+               subfields : {
+                       b : {   start : 1,
+                               len   : 1,
+                               label : "SMD",
+                               values: {       d : "Atlas",
+                                               g : "Diagram",
+                                               j : "Map",
+                                               k : "Profile",
+                                               q : "Model",
+                                               r : "Remote-sensing image",
+                                               s : "Section",
+                                               u : "Unspecified",
+                                               y : "View",
+                                               z : "Other",
+                               },
+                       },
+                       d : {   start : 3,
+                               len   : 1,
+                               label : "Color",
+                               values: {       a : "One color",
+                                               c : "Multicolored",
+                               },
+                       },
+                       e : {   start : 4,
+                               len   : 1,
+                               label : "Physical medium",
+                               values: {       a : "Paper",
+                                               b : "Wood",
+                                               c : "Stone",
+                                               d : "Metal",
+                                               e : "Synthetics",
+                                               f : "Skins",
+                                               g : "Textile",
+                                               p : "Plaster",
+                                               q : "Flexible base photographic medium, positive",
+                                               r : "Flexible base photographic medium, negative",
+                                               s : "Non-flexible base photographic medium, positive",
+                                               t : "Non-flexible base photographic medium, negative",
+                                               u : "Unknown",
+                                               y : "Other photographic medium",
+                                               z : "Other",
+                               },
+                       },
+                       f : {   start : 5,
+                               len   : 1,
+                               label : "Type of reproduction",
+                               values: {       f : "Facsimile",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       g : {   start : 6,
+                               len   : 1,
+                               label : "Production/reproduction details",
+                               values: {       a : "Photocopy, blueline print",
+                                               b : "Photocopy",
+                                               c : "Pre-production",
+                                               d : "Film",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       h : {   start : 7,
+                               len   : 1,
+                               label : "Positive/negative",
+                               values: {       a : "Positive",
+                                               b : "Negative",
+                                               m : "Mixed",
+                                               n : "Not applicable",
+                               },
+                       },
+               },
+       },
+       h : {
+               label     : "Microform",
+               subfields : {
+                       b : {   start : 1,
+                               len   : 1,
+                               label : "SMD",
+                               values: {       a : "Aperture card",
+                                               b : "Microfilm cartridge",
+                                               c : "Microfilm cassette",
+                                               d : "Microfilm reel",
+                                               e : "Microfiche",
+                                               f : "Microfiche cassette",
+                                               g : "Microopaque",
+                                               u : "Unspecified",
+                                               z : "Other",
+                               },
+                       },
+                       d : {   start : 3,
+                               len   : 1,
+                               label : "Positive/negative",
+                               values: {       a : "Positive",
+                                               b : "Negative",
+                                               m : "Mixed",
+                                               u : "Unknown",
+                               },
+                       },
+                       e : {   start : 4,
+                               len   : 1,
+                               label : "Dimensions",
+                               values: {       a : "8 mm.",
+                                               e : "16 mm.",
+                                               f : "35 mm.",
+                                               g : "70mm.",
+                                               h : "105 mm.",
+                                               l : "3 x 5 in. (8 x 13 cm.)",
+                                               m : "4 x 6 in. (11 x 15 cm.)",
+                                               o : "6 x 9 in. (16 x 23 cm.)",
+                                               p : "3 1/4 x 7 3/8 in. (9 x 19 cm.)",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       f : {   start : 5,
+                               len   : 4,
+                               label : "Reduction ratio range/Reduction ratio",
+                               values: {       a : "Low (1-16x)",
+                                               b : "Normal (16-30x)",
+                                               c : "High (31-60x)",
+                                               d : "Very high (61-90x)",
+                                               e : "Ultra (90x-)",
+                                               u : "Unknown",
+                                               v : "Reduction ratio varies",
+                               },
+                       },
+                       g : {   start : 9,
+                               len   : 1,
+                               label : "Color",
+                               values: {       b : "Black-and-white",
+                                               c : "Multicolored",
+                                               m : "Mixed",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       h : {   start : 10,
+                               len   : 1,
+                               label : "Emulsion on film",
+                               values: {       a : "Silver halide",
+                                               b : "Diazo",
+                                               c : "Vesicular",
+                                               m : "Mixed",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       i : {   start : 11,
+                               len   : 1,
+                               label : "Quality assurance target(s)",
+                               values: {       a : "1st gen. master",
+                                               b : "Printing master",
+                                               c : "Service copy",
+                                               m : "Mixed generation",
+                                               u : "Unknown",
+                               },
+                       },
+                       j : {   start : 12,
+                               len   : 1,
+                               label : "Base of film",
+                               values: {       a : "Safety base, undetermined",
+                                               c : "Safety base, acetate undetermined",
+                                               d : "Safety base, diacetate",
+                                               l : "Nitrate base",
+                                               m : "Mixed base",
+                                               n : "Not applicable",
+                                               p : "Safety base, polyester",
+                                               r : "Safety base, mixed",
+                                               t : "Safety base, triacetate",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+               },
+       },
+       m : {
+               label     : "Motion Picture",
+               subfields : {
+                       b : {   start : 1,
+                               len   : 1,
+                               label : "SMD",
+                               values: {       a : "Film cartridge",
+                                               f : "Film cassette",
+                                               r : "Film reel",
+                                               u : "Unspecified",
+                                               z : "Other",
+                               },
+                       },
+                       d : {   start : 3,
+                               len   : 1,
+                               label : "Color",
+                               values: {       b : "Black-and-white",
+                                               c : "Multicolored",
+                                               h : "Hand-colored",
+                                               m : "Mixed",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       e : {   start : 4,
+                               len   : 1,
+                               label : "Motion picture presentation format",
+                               values: {       a : "Standard sound aperture, reduced frame",
+                                               b : "Nonanamorphic (wide-screen)",
+                                               c : "3D",
+                                               d : "Anamorphic (wide-screen)",
+                                               e : "Other-wide screen format",
+                                               f : "Standard. silent aperture, full frame",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       f : {   start : 5,
+                               len   : 1,
+                               label : "Sound on medium or separate",
+                               values: {       a : "Sound on medium",
+                                               b : "Sound separate from medium",
+                                               u : "Unknown",
+                               },
+                       },
+                       g : {   start : 6,
+                               len   : 1,
+                               label : "Medium for sound",
+                               values: {       a : "Optical sound track on motion picture film",
+                                               b : "Magnetic sound track on motion picture film",
+                                               c : "Magnetic audio tape in cartridge",
+                                               d : "Sound disc",
+                                               e : "Magnetic audio tape on reel",
+                                               f : "Magnetic audio tape in cassette",
+                                               g : "Optical and magnetic sound track on film",
+                                               h : "Videotape",
+                                               i : "Videodisc",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       h : {   start : 7,
+                               len   : 1,
+                               label : "Dimensions",
+                               values: {       a : "Standard 8 mm.",
+                                               b : "Super 8 mm./single 8 mm.",
+                                               c : "9.5 mm.",
+                                               d : "16 mm.",
+                                               e : "28 mm.",
+                                               f : "35 mm.",
+                                               g : "70 mm.",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       i : {   start : 8,
+                               len   : 1,
+                               label : "Configuration of playback channels",
+                               values: {       k : "Mixed",
+                                               m : "Monaural",
+                                               n : "Not applicable",
+                                               q : "Multichannel, surround or quadraphonic",
+                                               s : "Stereophonic",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       j : {   start : 9,
+                               len   : 1,
+                               label : "Production elements",
+                               values: {       a : "Work print",
+                                               b : "Trims",
+                                               c : "Outtakes",
+                                               d : "Rushes",
+                                               e : "Mixing tracks",
+                                               f : "Title bands/inter-title rolls",
+                                               g : "Production rolls",
+                                               n : "Not applicable",
+                                               z : "Other",
+                               },
+                       },
+               },
+       },
+       k : {
+               label     : "Non-projected Graphic",
+               subfields : {
+                       b : {   start : 1,
+                               len   : 1,
+                               label : "SMD",
+                               values: {       c : "Collage",
+                                               d : "Drawing",
+                                               e : "Painting",
+                                               f : "Photo-mechanical print",
+                                               g : "Photonegative",
+                                               h : "Photoprint",
+                                               i : "Picture",
+                                               j : "Print",
+                                               l : "Technical drawing",
+                                               n : "Chart",
+                                               o : "Flash/activity card",
+                                               u : "Unspecified",
+                                               z : "Other",
+                               },
+                       },
+                       d : {   start : 3,
+                               len   : 1,
+                               label : "Color",
+                               values: {       a : "One color",
+                                               b : "Black-and-white",
+                                               c : "Multicolored",
+                                               h : "Hand-colored",
+                                               m : "Mixed",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       e : {   start : 4,
+                               len   : 1,
+                               label : "Primary support material",
+                               values: {       a : "Canvas",
+                                               b : "Bristol board",
+                                               c : "Cardboard/illustration board",
+                                               d : "Glass",
+                                               e : "Synthetics",
+                                               f : "Skins",
+                                               g : "Textile",
+                                               h : "Metal",
+                                               m : "Mixed collection",
+                                               o : "Paper",
+                                               p : "Plaster",
+                                               q : "Hardboard",
+                                               r : "Porcelain",
+                                               s : "Stone",
+                                               t : "Wood",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       f : {   start : 5,
+                               len   : 1,
+                               label : "Secondary support material",
+                               values: {       a : "Canvas",
+                                               b : "Bristol board",
+                                               c : "Cardboard/illustration board",
+                                               d : "Glass",
+                                               e : "Synthetics",
+                                               f : "Skins",
+                                               g : "Textile",
+                                               h : "Metal",
+                                               m : "Mixed collection",
+                                               o : "Paper",
+                                               p : "Plaster",
+                                               q : "Hardboard",
+                                               r : "Porcelain",
+                                               s : "Stone",
+                                               t : "Wood",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+               },
+       },
+       g : {
+               label     : "Projected Graphic",
+               subfields : {
+                       b : {   start : 1,
+                               len   : 1,
+                               label : "SMD",
+                               values: {       c : "Film cartridge",
+                                               d : "Filmstrip",
+                                               f : "Film filmstrip type",
+                                               o : "Filmstrip roll",
+                                               s : "Slide",
+                                               t : "Transparency",
+                                               z : "Other",
+                               },
+                       },
+                       d : {   start : 3,
+                               len   : 1,
+                               label : "Color",
+                               values: {       b : "Black-and-white",
+                                               c : "Multicolored",
+                                               h : "Hand-colored",
+                                               m : "Mixed",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       e : {   start : 4,
+                               len   : 1,
+                               label : "Base of emulsion",
+                               values: {       d : "Glass",
+                                               e : "Synthetics",
+                                               j : "Safety film",
+                                               k : "Film base, other than safety film",
+                                               m : "Mixed collection",
+                                               o : "Paper",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       f : {   start : 5,
+                               len   : 1,
+                               label : "Sound on medium or separate",
+                               values: {       a : "Sound on medium",
+                                               b : "Sound separate from medium",
+                                               u : "Unknown",
+                               },
+                       },
+                       g : {   start : 6,
+                               len   : 1,
+                               label : "Medium for sound",
+                               values: {       a : "Optical sound track on motion picture film",
+                                               b : "Magnetic sound track on motion picture film",
+                                               c : "Magnetic audio tape in cartridge",
+                                               d : "Sound disc",
+                                               e : "Magnetic audio tape on reel",
+                                               f : "Magnetic audio tape in cassette",
+                                               g : "Optical and magnetic sound track on film",
+                                               h : "Videotape",
+                                               i : "Videodisc",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       h : {   start : 7,
+                               len   : 1,
+                               label : "Dimensions",
+                               values: {       a : "Standard 8 mm.",
+                                               b : "Super 8 mm./single 8 mm.",
+                                               c : "9.5 mm.",
+                                               d : "16 mm.",
+                                               e : "28 mm.",
+                                               f : "35 mm.",
+                                               g : "70 mm.",
+                                               j : "2 x 2 in. (5 x 5 cm.)",
+                                               k : "2 1/4 x 2 1/4 in. (6 x 6 cm.)",
+                                               s : "4 x 5 in. (10 x 13 cm.)",
+                                               t : "5 x 7 in. (13 x 18 cm.)",
+                                               v : "8 x 10 in. (21 x 26 cm.)",
+                                               w : "9 x 9 in. (23 x 23 cm.)",
+                                               x : "10 x 10 in. (26 x 26 cm.)",
+                                               y : "7 x 7 in. (18 x 18 cm.)",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       i : {   start : 8,
+                               len   : 1,
+                               label : "Secondary support material",
+                               values: {       c : "Cardboard",
+                                               d : "Glass",
+                                               e : "Synthetics",
+                                               h : "metal",
+                                               j : "Metal and glass",
+                                               k : "Synthetics and glass",
+                                               m : "Mixed collection",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+               },
+       },
+       r : {
+               label     : "Remote-sensing Image",
+               subfields : {
+                       b : {   start : 1,
+                               len   : 1,
+                               label : "SMD",
+                               values: { u : "Unspecified" },
+                       },
+                       d : {   start : 3,
+                               len   : 1,
+                               label : "Altitude of sensor",
+                               values: {       a : "Surface",
+                                               b : "Airborne",
+                                               c : "Spaceborne",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       e : {   start : 4,
+                               len   : 1,
+                               label : "Attitude of sensor",
+                               values: {       a : "Low oblique",
+                                               b : "High oblique",
+                                               c : "Vertical",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                               },
+                       },
+                       f : {   start : 5,
+                               len   : 1,
+                               label : "Cloud cover",
+                               values: {       0 : "0-09%",
+                                               1 : "10-19%",
+                                               2 : "20-29%",
+                                               3 : "30-39%",
+                                               4 : "40-49%",
+                                               5 : "50-59%",
+                                               6 : "60-69%",
+                                               7 : "70-79%",
+                                               8 : "80-89%",
+                                               9 : "90-100%",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                               },
+                       },
+                       g : {   start : 6,
+                               len   : 1,
+                               label : "Platform construction type",
+                               values: {       a : "Balloon",
+                                               b : "Aircraft-low altitude",
+                                               c : "Aircraft-medium altitude",
+                                               d : "Aircraft-high altitude",
+                                               e : "Manned spacecraft",
+                                               f : "Unmanned spacecraft",
+                                               g : "Land-based remote-sensing device",
+                                               h : "Water surface-based remote-sensing device",
+                                               i : "Submersible remote-sensing device",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       h : {   start : 7,
+                               len   : 1,
+                               label : "Platform use category",
+                               values: {       a : "Meteorological",
+                                               b : "Surface observing",
+                                               c : "Space observing",
+                                               m : "Mixed uses",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       i : {   start : 8,
+                               len   : 1,
+                               label : "Sensor type",
+                               values: {       a : "Active",
+                                               b : "Passive",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       j : {   start : 9,
+                               len   : 2,
+                               label : "Data type",
+                               values: {       nn : "Not applicable",
+                                               uu : "Unknown",
+                                               zz : "Other",
+                                               aa : "Visible light",
+                                               da : "Near infrared",
+                                               db : "Middle infrared",
+                                               dc : "Far infrared",
+                                               dd : "Thermal infrared",
+                                               de : "Shortwave infrared (SWIR)",
+                                               df : "Reflective infrared",
+                                               dv : "Combinations",
+                                               dz : "Other infrared data",
+                                               ga : "Sidelooking airborne radar (SLAR)",
+                                               gb : "Synthetic aperture radar (SAR-single frequency)",
+                                               gc : "SAR-multi-frequency (multichannel)",
+                                               gd : "SAR-like polarization",
+                                               ge : "SAR-cross polarization",
+                                               gf : "Infometric SAR",
+                                               gg : "Polarmetric SAR",
+                                               gu : "Passive microwave mapping",
+                                               gz : "Other microwave data",
+                                               ja : "Far ultraviolet",
+                                               jb : "Middle ultraviolet",
+                                               jc : "Near ultraviolet",
+                                               jv : "Ultraviolet combinations",
+                                               jz : "Other ultraviolet data",
+                                               ma : "Multi-spectral, multidata",
+                                               mb : "Multi-temporal",
+                                               mm : "Combination of various data types",
+                                               pa : "Sonar-water depth",
+                                               pb : "Sonar-bottom topography images, sidescan",
+                                               pc : "Sonar-bottom topography, near-surface",
+                                               pd : "Sonar-bottom topography, near-bottom",
+                                               pe : "Seismic surveys",
+                                               pz : "Other acoustical data",
+                                               ra : "Gravity anomales (general)",
+                                               rb : "Free-air",
+                                               rc : "Bouger",
+                                               rd : "Isostatic",
+                                               sa : "Magnetic field",
+                                               ta : "Radiometric surveys",
+                               },
+                       },
+               },
+       },
+       s : {
+               label     : "Sound Recording",
+               subfields : {
+                       b : {   start : 1,
+                               len   : 1,
+                               label : "SMD",
+                               values: {       d : "Sound disc",
+                                               e : "Cylinder",
+                                               g : "Sound cartridge",
+                                               i : "Sound-track film",
+                                               q : "Roll",
+                                               s : "Sound cassette",
+                                               t : "Sound-tape reel",
+                                               u : "Unspecified",
+                                               w : "Wire recording",
+                                               z : "Other",
+                               },
+                       },
+                       d : {   start : 3,
+                               len   : 1,
+                               label : "Speed",
+                               values: {       a : "16 rpm",
+                                               b : "33 1/3 rpm",
+                                               c : "45 rpm",
+                                               d : "78 rpm",
+                                               e : "8 rpm",
+                                               f : "1.4 mps",
+                                               h : "120 rpm",
+                                               i : "160 rpm",
+                                               k : "15/16 ips",
+                                               l : "1 7/8 ips",
+                                               m : "3 3/4 ips",
+                                               o : "7 1/2 ips",
+                                               p : "15 ips",
+                                               r : "30 ips",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       e : {   start : 4,
+                               len   : 1,
+                               label : "Configuration of playback channels",
+                               values: {       m : "Monaural",
+                                               q : "Quadraphonic",
+                                               s : "Stereophonic",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       f : {   start : 5,
+                               len   : 1,
+                               label : "Groove width or pitch",
+                               values: {       m : "Microgroove/fine",
+                                               n : "Not applicable",
+                                               s : "Coarse/standard",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       g : {   start : 6,
+                               len   : 1,
+                               label : "Dimensions",
+                               values: {       a : "3 in.",
+                                               b : "5 in.",
+                                               c : "7 in.",
+                                               d : "10 in.",
+                                               e : "12 in.",
+                                               f : "16 in.",
+                                               g : "4 3/4 in. (12 cm.)",
+                                               j : "3 7/8 x 2 1/2 in.",
+                                               o : "5 1/4 x 3 7/8 in.",
+                                               s : "2 3/4 x 4 in.",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       h : {   start : 7,
+                               len   : 1,
+                               label : "Tape width",
+                               values: {       l : "1/8 in.",
+                                               m : "1/4in.",
+                                               n : "Not applicable",
+                                               o : "1/2 in.",
+                                               p : "1 in.",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       i : {   start : 8,
+                               len   : 1,
+                               label : "Tape configuration ",
+                               values: {       a : "Full (1) track",
+                                               b : "Half (2) track",
+                                               c : "Quarter (4) track",
+                                               d : "8 track",
+                                               e : "12 track",
+                                               f : "16 track",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       m : {   start : 12,
+                               len   : 1,
+                               label : "Special playback",
+                               values: {       a : "NAB standard",
+                                               b : "CCIR standard",
+                                               c : "Dolby-B encoded, standard Dolby",
+                                               d : "dbx encoded",
+                                               e : "Digital recording",
+                                               f : "Dolby-A encoded",
+                                               g : "Dolby-C encoded",
+                                               h : "CX encoded",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       n : {   start : 13,
+                               len   : 1,
+                               label : "Capture and storage",
+                               values: {       a : "Acoustical capture, direct storage",
+                                               b : "Direct storage, not acoustical",
+                                               d : "Digital storage",
+                                               e : "Analog electrical storage",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+               },
+       },
+       f : {
+               label     : "Tactile Material",
+               subfields : {
+                       b : {   start : 1,
+                               len   : 1,
+                               label : "SMD",
+                               values: {       a : "Moon",
+                                               b : "Braille",
+                                               c : "Combination",
+                                               d : "Tactile, with no writing system",
+                                               u : "Unspecified",
+                                               z : "Other",
+                               },
+                       },
+                       d : {   start : 3,
+                               len   : 2,
+                               label : "Class of braille writing",
+                               values: {       a : "Literary braille",
+                                               b : "Format code braille",
+                                               c : "Mathematics and scientific braille",
+                                               d : "Computer braille",
+                                               e : "Music braille",
+                                               m : "Multiple braille types",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       e : {   start : 4,
+                               len   : 1,
+                               label : "Level of contraction",
+                               values: {       a : "Uncontracted",
+                                               b : "Contracted",
+                                               m : "Combination",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       f : {   start : 6,
+                               len   : 3,
+                               label : "Braille music format",
+                               values: {       a : "Bar over bar",
+                                               b : "Bar by bar",
+                                               c : "Line over line",
+                                               d : "Paragraph",
+                                               e : "Single line",
+                                               f : "Section by section",
+                                               g : "Line by line",
+                                               h : "Open score",
+                                               i : "Spanner short form scoring",
+                                               j : "Short form scoring",
+                                               k : "Outline",
+                                               l : "Vertical score",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       g : {   start : 9,
+                               len   : 1,
+                               label : "Special physical characteristics",
+                               values: {       a : "Print/braille",
+                                               b : "Jumbo or enlarged braille",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+               },
+       },
+       v : {
+               label     : "Videorecording",
+               subfields : {
+                       b : {   start : 1,
+                               len   : 1,
+                               label : "SMD",
+                               values: {       c : "Videocartridge",
+                                               d : "Videodisc",
+                                               f : "Videocassette",
+                                               r : "Videoreel",
+                                               u : "Unspecified",
+                                               z : "Other",
+                               },
+                       },
+                       d : {   start : 3,
+                               len   : 1,
+                               label : "Color",
+                               values: {       b : "Black-and-white",
+                                               c : "Multicolored",
+                                               m : "Mixed",
+                                               n : "Not applicable",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       e : {   start : 4,
+                               len   : 1,
+                               label : "Videorecording format",
+                               values: {       a : "Beta",
+                                               b : "VHS",
+                                               c : "U-matic",
+                                               d : "EIAJ",
+                                               e : "Type C",
+                                               f : "Quadruplex",
+                                               g : "Laserdisc",
+                                               h : "CED",
+                                               i : "Betacam",
+                                               j : "Betacam SP",
+                                               k : "Super-VHS",
+                                               m : "M-II",
+                                               o : "D-2",
+                                               p : "8 mm.",
+                                               q : "Hi-8 mm.",
+                                               u : "Unknown",
+                                               v : "DVD",
+                                               z : "Other",
+                               },
+                       },
+                       f : {   start : 5,
+                               len   : 1,
+                               label : "Sound on medium or separate",
+                               values: {       a : "Sound on medium",
+                                               b : "Sound separate from medium",
+                                               u : "Unknown",
+                               },
+                       },
+                       g : {   start : 6,
+                               len   : 1,
+                               label : "Medium for sound",
+                               values: {       a : "Optical sound track on motion picture film",
+                                               b : "Magnetic sound track on motion picture film",
+                                               c : "Magnetic audio tape in cartridge",
+                                               d : "Sound disc",
+                                               e : "Magnetic audio tape on reel",
+                                               f : "Magnetic audio tape in cassette",
+                                               g : "Optical and magnetic sound track on motion picture film",
+                                               h : "Videotape",
+                                               i : "Videodisc",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       h : {   start : 7,
+                               len   : 1,
+                               label : "Dimensions",
+                               values: {       a : "8 mm.",
+                                               m : "1/4 in.",
+                                               o : "1/2 in.",
+                                               p : "1 in.",
+                                               q : "2 in.",
+                                               r : "3/4 in.",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+                       i : {   start : 8,
+                               len   : 1,
+                               label : "Configuration of playback channel",
+                               values: {       k : "Mixed",
+                                               m : "Monaural",
+                                               n : "Not applicable",
+                                               q : "Multichannel, surround or quadraphonic",
+                                               s : "Stereophonic",
+                                               u : "Unknown",
+                                               z : "Other",
+                               },
+                       },
+               },
+       },
+};
+
diff --git a/catalog/record_type.js b/catalog/record_type.js
new file mode 100755 (executable)
index 0000000..0a6988b
--- /dev/null
@@ -0,0 +1,90 @@
+// Constants ...
+load_lib('phys_char.js');
+load_lib('fixed_fields.js');
+load_lib('JSON_v1.js');
+
+function recordType (rec) {
+
+       var marcns = new Namespace("http://www.loc.gov/MARC21/slim");
+       var _l = rec.marcns::leader.toString();
+
+       var _t = _l.substr(ff_pos.Type.ldr.BKS.start, ff_pos.Type.ldr.BKS.len);
+       var _b = _l.substr(ff_pos.BLvl.ldr.BKS.start, ff_pos.BLvl.ldr.BKS.len);
+
+       for (var t in rec_type) {
+               if (_t.match(rec_type[t].Type) && _b.match(rec_type[t].BLvl)) {
+                       return t;
+               }
+       }
+}
+
+function videorecordingFormatName (rec) {
+       var marcns = new Namespace("http://www.loc.gov/MARC21/slim");
+       var _7 = rec.marcns::controlfield.(@tag.match(/007/)).text().toString();
+
+       if (_7.match(/^v/)) {
+               var _v_e = _7.substr(
+                       physical_characteristics.v.subfields.e.start,
+                       physical_characteristics.v.subfields.e.len
+               );
+
+               return physical_characteristics.v.subfields.e.values[ _v_e ];
+       }
+
+       return null;
+}
+
+function videorecordingFormatCode (rec) {
+       var marcns = new Namespace("http://www.loc.gov/MARC21/slim");
+       var _7 = rec.marcns::controlfield.(@tag.match(/007/)).text().toString();
+
+       if (_7.match(/^v/)) {
+               return _7.substr(
+                       physical_characteristics.v.subfields.e.start,
+                       physical_characteristics.v.subfields.e.len
+               );
+       }
+
+       return null;
+}
+
+
+function extractFixedField (rec, field) {
+
+       var marcns = new Namespace("http://www.loc.gov/MARC21/slim");
+       var _l = rec.marcns::leader.toString();
+       var _8 = rec.marcns::controlfield.(@tag.match(/008/)).text().toString();
+       var _6 = rec.marcns::controlfield.(@tag.match(/006/)).text().toString();
+
+       var rtype = recordType(rec);
+
+       var val;
+
+       if (ff_pos[field].ldr) {
+               if (ff_pos[field].ldr[rtype]) {
+                       val = _l.substr(
+                               ff_pos[field].ldr[rtype].start,
+                               ff_pos[field].ldr[rtype].len
+                       );
+               }
+       } else if (ff_pos[field]._8) {
+               if (ff_pos[field]._8[rtype]) {
+                       val = _8.substr(
+                               ff_pos[field]._8[rtype].start,
+                               ff_pos[field]._8[rtype].len
+                       );
+               }
+       }
+
+       if (!val && ff_pos[field]._6) {
+               if (ff_pos[field]._6[rtype]) {
+                       val = _6.substr(
+                               ff_pos[field]._6[rtype].start,
+                               ff_pos[field]._6[rtype].len
+                       );
+               }
+       }
+               
+       return val;
+}
+
diff --git a/circ/circ_duration.js b/circ/circ_duration.js
new file mode 100755 (executable)
index 0000000..6f6a3d4
--- /dev/null
@@ -0,0 +1,49 @@
+function go(){
+
+load_lib('circ/circ_item_config.js');
+load_lib('JSON_v1.js');
+log_vars('circ_duration');
+
+
+/* treat pre-cat copies like vanilla books */
+if( isTrue(isPrecat) ) {
+       log_info("pre-cat copy getting duration defaults...");
+       result.durationRule                     = 'default';
+       result.recurringFinesRule       = 'default';
+       result.maxFine                          = 'default'
+       return;
+}
+
+
+/* grab the config from the config script */
+var config = getItemConfig();
+var itemForm   = (marcXMLDoc) ? extractFixedField(marcXMLDoc,'Form') : "";
+
+
+/* ----------------------------------------------------------------------------- 
+       Now set the rule values based on the config.  If there is no configured info
+       on this copy, fall back on defaults.
+       ----------------------------------------------------------------------------- */
+if( config ) {
+
+       log_debug("circ_duration found a config for the copy");
+       result.durationRule                     = config.durationRule;
+       result.recurringFinesRule       = config.recurringFinesRule;
+       result.maxFine                      = config.maxFine;
+
+} else {
+
+       result.durationRule = 'default';
+       result.recurringFinesRule = 'default';
+       result.maxFine = 'default';
+}
+
+
+log_info('final duration results: ' + 
+    result.durationRule + ' : ' + result.recurringFinesRule + ' : ' + result.maxFine );
+
+} go();
+
+
+
+
diff --git a/circ/circ_groups.js b/circ/circ_groups.js
new file mode 100755 (executable)
index 0000000..036d56e
--- /dev/null
@@ -0,0 +1,21 @@
+/* ---------------------------------------------------------------------
+       Set up the limits for the various profiles (aka permission groups).
+       Values of -1 mean there is no limit 
+
+       maxItemsOut                     - the maximum number of items the user can have out
+       fineThreshold           - the fine threshold. 
+       overdueThreshold        - the overdue items threshold.
+       maxHolds                                - The maximum number of holds the user can have
+
+       A user exceeds the fineThreshold and/or overdueThreshold if they are 
+       equal to or exceed the threshold
+       --------------------------------------------------------------------- */
+
+var GROUP_CONFIG = {
+       'Patron' : {
+               maxItemsOut         : 50,
+               fineThreshold       : 10,
+               overdueThreshold    : 10,
+               maxHolds            : -1
+       },
+}
diff --git a/circ/circ_item_config.js b/circ/circ_item_config.js
new file mode 100755 (executable)
index 0000000..c54d0cc
--- /dev/null
@@ -0,0 +1,87 @@
+load_lib('circ/circ_lib.js');
+load_lib('JSON_v1.js');
+log_debug('loading circ_item_config.js ...');
+
+
+/* SIP media types
+000 Other
+001 Book
+002 Magazine
+003 Bound journal
+004 Audio tape
+005 Video tape
+006 CD/CDROM
+007 Diskette
+008 Book with diskette
+009 Book with CD
+010 Book with audio tape
+*/
+
+/* ----------------------------------------------------------------------------- 
+       Configure the duration rules for the various item types and circ modifiers
+       MARC Fixed Field info:
+       http://www.oclc.org/bibformats/en/fixedfield/
+       ----------------------------------------------------------------------------- */
+
+var MARC_ITEM_TYPE_MAP = {
+       a : { /* Language material [Books] */
+               SIPMediaType                    : '001',
+               magneticMedia                   : 'f',
+               durationRule                    : 'default',
+               recurringFinesRule          : 'default',
+               maxFine                                 : 'default'
+       },
+    /* add more MARC item type configs as needed... */
+}
+
+/* make 't' and 'a' share the same config info */
+MARC_ITEM_TYPE_MAP.t = MARC_ITEM_TYPE_MAP.a;
+
+
+var CIRC_MOD_MAP = {
+       'bestseller'                            : {
+               SIPMediaType                    : '001',
+               magneticMedia                   : 'f',
+               durationRule                    : 'default',
+               recurringFinesRule          : 'default',
+               maxFine                                 : 'default'
+       },
+}
+
+
+/* this will set defaults even if no one asked for them */
+log_debug("Calling getItemConfig() to force defaults..");
+result.item_config = getItemConfig();
+
+
+function getItemConfig() {
+
+       var config = null;
+       var marcType    = getMARCItemType();
+       var circMod             = copy.circ_modifier;
+
+    if( circMod ) {
+        config = CIRC_MOD_MAP[circMod];
+        if(!config) 
+            config = CIRC_MOD_MAP[circMod.toLowerCase()]
+    }
+
+    if(!config)
+               config = MARC_ITEM_TYPE_MAP[marcType];
+
+    if(!config) {
+        config = {};
+               config.SIPMediaType = '001';
+               config.magneticMedia = 'f';
+               config.durationRule     = 'default';
+               config.recurringFinesRule = 'default';
+               config.maxFine = 'default';
+    }
+
+    return config
+}
+
+
+
+
+
diff --git a/circ/circ_lib.js b/circ/circ_lib.js
new file mode 100755 (executable)
index 0000000..64923ed
--- /dev/null
@@ -0,0 +1,314 @@
+load_lib('catalog/record_type.js');
+load_lib('circ/circ_groups.js');
+load_lib('JSON_v1.js');
+
+
+try {
+       if( environment.copy ) {
+               environment.copy.fetchBestHold = function() {
+                       var key = scratchKey();
+                       environment.copy.__OILS_FUNC_fetch_best_hold(scratchPad(key));
+                       var val = getScratch(key);
+                       return (val) ? val : null;
+               }
+       }
+} catch(e) {}
+
+
+/* ----------------------------------------------------------------------------- 
+       Collect all of the global variables
+       ----------------------------------------------------------------------------- */
+
+/* the global result object.  Any data returned to the 
+       caller must be put into this object.  */
+var result                             = environment.result = {};
+result.event                   = 'SUCCESS';
+result.events                  = [];
+result.fatalEvents     = [];
+result.infoEvents              = [];
+
+
+/* Pull in any variables passed in from the calling process */
+var copy                                       = environment.copy;
+var volume                             = environment.volume;
+var title                              = environment.title;
+var recDescriptor              = environment.titleDescriptor;
+var patron                             = environment.patron;
+var patronItemsOut     = environment.patronItemsOut;
+var patronOverdueCount = environment.patronOverdueCount;
+var patronFines                = environment.patronFines;
+var isRenewal                  = environment.isRenewal;
+var isPrecat                   = environment.isPrecat;
+var currentLocation    = environment.location;
+var holdRequestLib     = environment.requestLib;
+var holdPickupLib       = environment.pickupLib; /* hold pickup lib */
+var requestor = environment.requestor || patron;
+var newHold = environment.newHold;
+
+
+
+/* create some new vars based on the data we have wherever possible */
+var patronProfile;
+var copyStatus;
+var marcXMLDoc;
+
+if( patron && patron.profile ) 
+       patronProfile = patron.profile.name;
+if( copy && copy.status ) 
+       copyStatus = copy.status.name;
+if( title && title.marc )
+       marcXMLDoc = new XML(title.marc);
+
+
+
+/* copy the group tree into some other useful data structures */
+var groupTree          = environment.groupTree;
+var groupList          = {};
+var groupIDList        = {};
+flattenGroupTree(groupTree);
+
+
+
+
+
+
+/* ----------------------------------------------------------------------------- 
+       Define all of the utility functions
+       ----------------------------------------------------------------------------- */
+
+
+
+/* useful functions for creating wrappers around system functions */
+var __scratchKey = 0;
+var __SCRATCH = {};
+function scratchKey()          { return '_' + __scratchKey++; };
+function scratchPad(key)       { return '__SCRATCH.'+ key; }
+function getScratch(key)       { return __SCRATCH[ key ]; }
+function scratchClear()                { for( var o in __SCRATCH ) __SCRATCH[o] = null; }
+
+
+/* note: returns false if the value is 'f' or 'F' ... */
+function isTrue(d) {
+       if(     d && 
+                       d != "0" && 
+                       d != "f" &&
+                       d != "F" )
+                       return true;
+       return false;
+}
+
+/* Utility function for iterating over array */
+function iterate( arr, callback ) {
+       for( var i = 0; i < arr.length; i++ ) 
+               callback(arr[i]);
+}
+
+
+/**
+  * returns a list of items that when passed to the callback 
+  * 'func' returned true returns null if none were found
+  */
+function grep( arr, func ) {
+       var results = [];
+       iterate( arr, 
+               function(d) {
+                       if( func(d) ) 
+                               results.push(d);
+               }
+       );
+       if(results.length > 0)  
+               return results;
+       return null;
+}
+
+
+
+function flattenGroupTree(node) {
+       if(!node) return null;
+       groupList[node.name] = node;
+       groupIDList[node.id] = node;
+       iterate( node.children,
+               function(n) {
+                       flattenGroupTree(n);
+               }
+       );
+}
+
+
+
+/**
+  * Returns true if 'child' is equal or descends from 'parent'
+  * @param parent The name of the parent group
+  * @param child The name of the child group
+  */
+function isGroupDescendant( parent, child ) {
+       log_debug("checking descendant p="+parent + " c=" + child);
+       return __isGroupDescendant(
+               groupList[parent],
+               groupList[child]);
+}
+
+function isGroupDescendantId( parentName, childId ) {
+       log_debug("checking descendant ID p="+parentName + " c=" + childId);
+       return __isGroupDescendant(
+               groupList[parentName],
+               groupIDList[childId]);
+}
+
+
+/**
+  * Returns true if 'child' is equal or descends from 'parent'
+  * @param parent The node of the parent group
+  * @param child The node of the child group
+  */
+function __isGroupDescendant( parent, child ) {
+    if(!(parent && child)) return false;
+       if (parent.id == child.id) return true;
+       var node = child;
+       while( (node = groupIDList[node.parent]) ) {
+               if( node.id == parent.id ) 
+                       return true;
+       }
+       return false;
+}
+
+
+function getMARCItemType() {
+       if(     copy &&
+                       copy.circ_as_type &&
+                       copy.circ_as_type != 'undef' )
+               return copy.circ_as_type;
+       
+       return (marcXMLDoc) ? extractFixedField(marcXMLDoc, 'Type') : "";
+}
+
+
+function isOrgDescendent( parentName, childId ) {
+       var key = scratchKey();
+       __OILS_FUNC_isOrgDescendent(scratchPad(key), parentName, childId);
+       var val = getScratch(key);
+       if( val == '1' ) return true;
+       return false;
+}
+
+/* returns the number of unfulfilled holds open on this user */
+function userHoldCount(userid) {
+   var key = scratchKey();
+   __OILS_FUNC_userHoldCount(scratchPad(key), userid);
+   return getScratch(key);
+}
+
+function hasCommonAncestor( org1, org2, depth ) {
+       var key = scratchKey();
+       __OILS_FUNC_hasCommonAncestor(scratchPad(key), org1, org2, depth);
+       var val = getScratch(key);
+       if( val == '1' ) return true;
+       return false;
+}
+
+/* returns a dictionary of circmod : count for checked out items */
+function checkoutsByCircModifier(userid) {
+    var key = scratchKey();
+    __OILS_FUNC_userCircsByCircmod(scratchPad(key), userid);
+    var val = getScratch(key);
+    return (val) ? val : {};
+}
+
+/* useful for testing */
+function die(msg) {
+       log_error("die(): "+msg);
+       log_stderr("die(): "+msg);
+       var foo = null;
+       var baz = foo.bar;
+}
+
+
+
+/* logs a load of info */
+function log_vars( prefix ) {
+       var str = prefix + ' : ';
+
+       if(patron) {
+               str += ' Patron=' + patron.id;
+               str += ', Patron_Username='+ patron.usrname;
+               str += ', Patron_Profile_Group='+ patronProfile;
+               str += ', Patron_Fines='        + patronFines;
+               str += ', Patron_OverdueCount=' + patronOverdueCount;
+               str += ', Patron_Items_Out=' + patronItemsOut;
+
+               try {
+                       str += ', Patron_Barcode='      + patron.card.barcode;
+                       str += ', Patron_Library='      + patron.home_ou.name;
+               } catch(e) {}
+       }
+
+    if(requestor.id != patron.id) 
+        str+= ' Requestor='+requestor.usrname;
+
+       if(copy)        {
+               str += ', Copy=' + copy.id;
+               str += ', Copy_Barcode=' + copy.barcode;
+               str += ', Copy_status=' + copyStatus;
+      str += (copy.circ_modifier) ? ', Circ_Mod=' + copy.circ_modifier : '';
+
+               try {
+                       str += ', Circ_Lib=' + copy.circ_lib.shortname;
+                       str += ', Copy_location=' + copy.location.name;
+               } catch(e) {}
+       }
+
+       if(volume) {
+        str += ', Item_Owning_lib=' + volume.owning_lib;
+        str += ', Volume='     + volume.id;
+    }
+
+       if(title) str += ', Record='    + title.id;
+
+       if(recDescriptor)       {
+               str += ', Record_Descriptor=' + recDescriptor.id;
+               str += ', Item_Type='                   + recDescriptor.item_type;
+               str += ', Item_Form='                   + recDescriptor.item_form;
+               str += ', Item_Lang='                   + recDescriptor.item_lang;
+               str += ', Item_Audience='               + recDescriptor.audience;
+       }
+
+       str += ', Is_Renewal: ' + ( (isTrue(isRenewal)) ? "yes" : "no" );
+       str += ', Is_Precat: '  + ( (isTrue(isPrecat)) ? "yes" : "no" );
+       str += (holdRequestLib) ? ', Hold_request_lib=' + holdRequestLib.shortname : '';
+    str += (holdPickupLib) ? ', Hold_Pickup_Lib=' + holdPickupLib : '';
+
+       log_info(str);
+}
+
+
+
+/**
+  * Returns config information for the requested group.  If 
+  * no config info exists for the requested group, then this
+  * function searches up the tree to find the config info 
+  * for the nearest ancestor
+  * @param The name of the group who's config info to return
+  */
+function findGroupConfig(name) {
+       if(!name) return null;
+       var node = groupList[name];
+       do {
+               if( GROUP_CONFIG[node.name] ) {
+                       debugGroupConfig(name, node.name, GROUP_CONFIG[node.name]);
+                       return GROUP_CONFIG[node.name];
+               }
+       } while( (node = groupIDList[node.parent]) );
+       return null;
+}
+
+
+/** prints out the settings for the given group config **/
+function debugGroupConfig(name, foundName, config) {
+       if(!config) return;
+       var str = "findGroupConfig('"+name+"'): returning config info for '"+ foundName +"': ";
+       for( var i in config ) 
+               str += i + '=' + config[i] + '  ';
+       log_debug(str);
+}
+
+
diff --git a/circ/circ_permit_copy.js b/circ/circ_permit_copy.js
new file mode 100755 (executable)
index 0000000..053d9b7
--- /dev/null
@@ -0,0 +1,24 @@
+function go() {
+
+/* load the lib script */
+load_lib('circ/circ_lib.js');
+load_lib('JSON_v1.js');
+log_vars('circ_permit_copy');
+
+
+if( ! isTrue(copy.circulate) || !isTrue(copy.location.circulate) ) 
+       result.events.push('COPY_CIRC_NOT_ALLOWED');
+
+
+if( ! isTrue(isRenewal) ) {
+       if(copyStatus != 'Available' && 
+               copyStatus != 'On holds shelf' && copyStatus != 'Reshelving' ) {
+                       result.events.push('COPY_NOT_AVAILABLE');
+       } 
+}
+
+
+       
+} go();
+
+
diff --git a/circ/circ_permit_hold.js b/circ/circ_permit_hold.js
new file mode 100755 (executable)
index 0000000..942aace
--- /dev/null
@@ -0,0 +1,42 @@
+function go() {
+
+load_lib('circ/circ_lib.js');
+load_lib('JSON_v1.js');
+log_vars('circ_permit_hold');
+
+
+
+if( isTrue(patron.barred) ) 
+       result.events.push('PATRON_BARRED');
+
+if( isTrue(copy.ref) ) 
+       result.events.push('ITEM_NOT_HOLDABLE');
+
+if( !isTrue(copy.circulate) ) 
+       result.events.push('ITEM_NOT_HOLDABLE');
+
+
+var config = findGroupConfig(patronProfile);
+
+
+if( config ) {
+
+    /* see if they have too many items out */
+    if(newHold) {
+        log_info("This is a new hold, checking maxHolds...");
+        var limit = config.maxHolds;
+        var count = userHoldCount(patron.id);
+        if( limit >= 0 && count >= limit ) {
+            log_info("patron has " + count + " open holds");
+            result.events.push('MAX_HOLDS');
+        }
+    } else {
+        log_info("Ignoring maxHolds on existing hold...");
+    }
+}
+
+
+} go();
+
+
+
diff --git a/circ/circ_permit_patron.js b/circ/circ_permit_patron.js
new file mode 100755 (executable)
index 0000000..9549688
--- /dev/null
@@ -0,0 +1,33 @@
+function go() {
+
+/* load the script library */
+load_lib('circ/circ_lib.js');
+load_lib('JSON_v1.js');
+log_vars('circ_permit_patron');
+
+
+if( isTrue(patron.barred) ) 
+       result.events.push('PATRON_BARRED');
+
+var config = findGroupConfig(patronProfile);
+
+if( config ) {
+
+    var limit = config.maxItemsOut;
+    if( limit >= 0 ) {
+        log_info('patron items out = ' + patronItemsOut +' limit = ' + limit);
+        if( !isTrue(isRenewal) && patronItemsOut >= limit ) {
+            result.events.push('PATRON_EXCEEDS_CHECKOUT_COUNT');
+        }
+    }
+    
+} else {
+
+    log_warn("** profile has no configured information: " + patronProfile);
+}
+
+
+
+} go();
+
+
diff --git a/circ/circ_permit_renew.js b/circ/circ_permit_renew.js
new file mode 100755 (executable)
index 0000000..2eaac55
--- /dev/null
@@ -0,0 +1,8 @@
+function go() {
+
+/* load the lib script */
+load_lib('circ/circ_lib.js');
+load_lib('JSON_v1.js');
+log_vars('circ_permit_renew');
+
+} go();
diff --git a/circ/config_BABM.js b/circ/config_BABM.js
new file mode 100644 (file)
index 0000000..94658dc
--- /dev/null
@@ -0,0 +1,72 @@
+/** Policies for BABM */
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BABM");
+
+    var circMod = (copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+
+    return {
+
+        getLoanDuration : function() {
+            /* returns config.rule_circ_duration.name */
+               var circMod = (copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+
+               if(patronProfile == 'InterLibraryLoan'){
+                       return '21_2';
+            }
+               return '14_2';
+        },
+
+        getRecurringFine : function() {
+            /* returns config.rule_recuring_fine.name */
+            return 'tencents';
+        },
+
+        getMaxFine : function() {
+            /* returns config.rule_max_fine.name */
+            return 'fivedollar';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            log_debug("exceedsMaxCheckoutsByCircMod()");
+            return false;
+        },
+
+        isAllowedCirc : function() {
+               return 'true';
+        },
+
+        isAllowedHold : function() {
+            return 'true';
+        },
+
+        getGroupConfig : function() {
+            /* returns the combined user config object */
+
+            // override some defaults
+            GROUP_CONFIG.BCOneCard.maxItemsOut = 4;
+            GROUP_CONFIG.InterLibraryLoan.maxItemsOut = 4;
+            
+            var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+            
+            // these are global settings for BH users
+            config.fineThreshold = 2;
+                   config.maxHolds = 2;
+               config.overdueThreshold = 2;
+               config.maxItemsOut = 8;
+
+
+            // debugging...
+            var str = "BABM getGroupConfig():";
+               for( var i in config ){ 
+                       str += i + '=' + config[i] + '  ';
+            }
+               log_debug(str);
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BBUL.js b/circ/config_BBUL.js
new file mode 100644 (file)
index 0000000..8d441d5
--- /dev/null
@@ -0,0 +1,85 @@
+/** Policies for BPE **/
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BBUL");
+
+    return {
+
+        getLoanDuration : function() {
+            /* returns config.rule_circ_duration.name */
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+                       
+            if (isGroupDescendant('InterLibraryLoan', patronProfile)) {
+                return '52_2';
+            }
+
+            var map = {
+                'book'          :   '28_2',
+                'best-seller'   :   '14_1',
+                'media'         :   '14_1',
+                'holiday-special':  '14_0',
+                'magazine'      :   '14_0'
+            };
+                   
+            return map[circMod] || '28_2';         
+                   
+        },
+
+        getRecurringFine : function() {
+            /* returns config.rule_recuring_fine.name */
+       
+            if (isGroupDescendant('InterLibraryLoan', patronProfile)) {
+                return 'staff';
+            }
+
+            if (isGroupDescendant('Institution', patronProfile)) {
+                return 'staff';
+            }
+            return 'terrace';
+        },
+
+        getMaxFine : function() {
+            /* returns config.rule_max_fine.name */
+            return 'default';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+                return false;
+        },
+
+        isAllowedCirc : function() {
+           return true;
+        },
+                
+        isAllowedHold : function() {
+           return true;
+        },
+        getGroupConfig : function() {
+            /* returns the combined user config object */
+
+            // override some defaults
+
+                       GROUP_CONFIG.InterLibraryLoan.maxItemsOut = 10;
+            var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+            
+            // these are global settings for BH users
+            config.fineThreshold = 10;
+            config.maxHolds = 50;
+            config.overdueThreshold = 10;
+            config.maxItemsOut = 50;
+
+
+            // debugging...
+            var str = "BBUL getGroupConfig():";
+               for( var i in config ){ 
+                       str += i + '=' + config[i] + '  ';
+            }
+               log_debug(str);
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BCD.js b/circ/config_BCD.js
new file mode 100644 (file)
index 0000000..bc7bbe8
--- /dev/null
@@ -0,0 +1,141 @@
+/** Policies for BCD **/
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BCD");
+
+    return {
+
+        getLoanDuration : function() {
+            if (copy.call_number == -1){
+                return '21_0';
+            }
+            /* returns config.rule_circ_duration.name */
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+            if(patronProfile == 'InterLibraryLoan'){
+                return '42_0';
+            }
+
+            var map = {
+              '1-day-loan'               : '1day_no_renew',
+              '7-day-loan'               : '7_0',
+              'dvd'                      : '7_2',
+              'inter-library-loan'       : '21_0',
+              'juvenile-holiday-special' : '21_0',
+              'juvenile-serial'          : '21_0',
+              'magazine'                 : '7_0',
+              'videos'                   : '7_2'
+            };
+
+            return map[circMod] || 'default'; /* 21_2 */
+
+        },
+
+        getRecurringFine : function() {
+           if (patronProfile == 'Local System Administrator' || patronProfile == 'Catalogers' || patronProfile == 'CircCat' || patronProfile == 'Board' || patronProfile == 'Volunteer') {
+             return 'zero';
+           }
+
+           /* returns config.rule_recuring_fine.name */
+           var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+           var map = {
+              '1-day-loan'               : 'zero',
+              '7-day-loan'               : 'twentycent',
+              'audio-cassette'           : 'twentycent', 
+              'audio-cds'                : 'twentycent',
+              'audio-cds-cnib'           : 'zero',
+              'book'                     : 'twentycent',
+              'cd-rom'                   : 'twentycent',
+              'dvd'                      : 'twentycent',
+              'inter-library-loan'       : 'twentycent',
+              'juvenile-collection'      : 'fivecents',
+              'juvenile-holiday-special' : 'fivecents',
+              'kit'                      : 'fivecents',
+              'magazine'                 : 'twentycent',
+              'paperbacks'               : 'twentycent',
+              'videos'                   : 'twentycent',
+              'juvenile-serial'          : 'fivecents',
+              'large-print'              : 'twentycent'
+             
+           };
+
+           return map[circMod] || 'twentycent';
+        },
+
+          
+        getMaxFine : function() {
+           /* returns config.rule_max_fine.name */
+           var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+           var map = {
+             'magazine' : 'threedollar',
+             'juvenile-serial' : 'threedollar'
+           };
+
+           return map[circMod] || 'fivedollar';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            return false;
+        },
+
+        isAllowedCirc : function() {
+          return true;
+        },
+        isAllowedHold : function() {
+            return true;
+        },
+        getGroupConfig : function() {
+
+          // set defaults
+          var maxItemsOutValue        =  30;
+          var maxHoldsValue           =  20;
+          var overdueThresholdValue   =  20;
+          var fineThresholdValue      =  10;
+          
+          // set special values for group
+          switch (patronProfile) {
+            case 'Board':
+            case 'Homebound':
+            case 'InterLibraryLoan':
+            case 'Volunteer':
+              fineThresholdValue      =  -1;
+              break;
+            case 'JuvenileRes':
+              maxItemsOutValue        =  20;
+              break;
+            case 'BCOneCard':
+              maxItemsOutValue        =   5;
+              maxHoldsValue           =   5;
+              overdueThresholdValue   =   5;
+              break;
+            case 'Staff':
+              maxItemsOutValue        =  -1;
+              maxHoldsValue           =  -1;
+              overdueThresholdValue   =  -1;
+              fineThresholdValue      =  -1;
+              break;
+          }
+
+          // return group config
+          var config = {
+            'maxHolds'          :  maxHoldsValue,
+            'maxItemsOut'       :  maxItemsOutValue,
+            'overdueThreshold'  :  overdueThresholdValue,
+            'fineThreshold'     :  fineThresholdValue
+          };
+
+          // debugging...
+          var str = "BCD getGroupConfig():";
+          for( var i in config ){ 
+            str += i + '=' + config[i] + '  ';
+          }
+          log_debug(str);
+
+          return config;
+        }
+    };
+}
diff --git a/circ/config_BCREK.js b/circ/config_BCREK.js
new file mode 100644 (file)
index 0000000..53e6c54
--- /dev/null
@@ -0,0 +1,158 @@
+/** Policies for BCREK **/
+
+function getPolicy() {
+
+  load_lib('circ/circ_lib.js');
+  log_info("Loading policy info for BCREK");
+
+  return {
+
+    getLoanDuration : function() {
+
+      /* returns config.rule_circ_duration.name */
+      var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+      var map = {
+        'circ-reserve-1-hour'  : '1hr_0',
+        'circ-reserve-2-hour'  : '2hr_0',
+        'circ-reserve-4-hour'  : '4hr_0',
+        'circ-reserve-24-hour' : '24hr_0',
+        'circ-reserve-72-hour' : '72hr_0',
+        '7-day-loan'           : '7_6',
+        'archives'             : '7_0',
+        'book'                 : '21_6',
+        'floppy-disc'          : '3_2',
+        'inter-library-loan'   : '14_0',
+        'ill-media'            : '3_2',
+        'kit'                  : '21_6',
+        'library-equipment'    : '3_2',
+        'magazine'             : '7_6',
+        'maps'                 : '7_6',
+        'media'                : '21_6',
+        'online'               : '21_6',
+        'semester'             : '21_6', /* TODO: do term loan for this */
+        'videos'               : '7_6'
+      };
+
+      return map[circMod] || '21_6';
+
+    },
+
+    getRecurringFine : function() {
+
+      /* returns config.rule_recuring_fine.name */
+      var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+      
+      var map = {
+        'circ-reserve-1-hour'  : 'onedollarperhour',
+        'circ-reserve-2-hour'  : 'onedollarperhour',
+        'circ-reserve-4-hour'  : 'onedollarperhour',
+        'circ-reserve-24-hour' : 'onedollarperhour',
+        'circ-reserve-72-hour' : 'onedollarperhour',
+        'library-equipment'    : 'fivedollarsperhour',
+        'floppy-disc'          : 'zero',
+        'archives'             : 'zero',
+        'online'               : 'zero'
+      };
+      return map[circMod] || 'fiftycents';
+    },
+
+    getMaxFine : function() {
+
+      /* returns config.rule_recuring_fine.name */
+      var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+      var map = {
+        'library-equipment'  : 'thirtydollar',
+        'floppy-disc'        : 'zero',
+        'archives'           : 'zero',
+        'online'             : 'zero'
+      };
+      return map[circMod] || 'tendollar';
+    },
+
+    exceedsMaxCheckoutsByCircMod : function() {
+      return false;
+    },
+
+    isAllowedCirc : function() {
+      return true;
+    },
+    
+    isAllowedHold : function() {
+      return true;
+    },
+
+    getGroupConfig : function() {
+      /* returns the combined user config object */
+
+      var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+      
+      // set defaults
+      var maxItemsOutValue        =  20;
+      var maxHoldsValue           =   0;
+      var overdueThresholdValue   =  10;
+      var fineThresholdValue      =  30;
+      
+      // set special values for group
+      if (isGroupDescendant('Library Staff', patronProfile)) {
+        maxItemsOutValue        = 1000;
+        maxHoldsValue           = 1000;
+        overdueThresholdValue   = 1000;
+        fineThresholdValue      =   -1;
+      } else if (isGroupDescendant('Institution Staff', patronProfile)) {
+        maxItemsOutValue        =  100;
+        maxHoldsValue           =  100;
+        overdueThresholdValue   =  100;
+        fineThresholdValue      =   -1;
+      } else {
+        switch (patronProfile) {
+          case 'Community Borrowers':
+            maxItemsOutValue        =  20;
+            maxHoldsValue           =   0;
+            overdueThresholdValue   =  10;
+            fineThresholdValue      =  30;
+            break;
+          case 'Students':
+            maxItemsOutValue        = 100;
+            maxHoldsValue           =  50;
+            overdueThresholdValue   =  25;
+            fineThresholdValue      =  30;
+            break;
+          case 'Distance Students':
+            maxItemsOutValue        =  50;
+            maxHoldsValue           =  50;
+            overdueThresholdValue   =  20;
+            fineThresholdValue      =  30;
+            break;
+          case 'InterLibraryLoan':
+            maxItemsOutValue        =  20;
+            maxHoldsValue           =  10;
+            overdueThresholdValue   =  10;
+            fineThresholdValue      =  -1;
+            break;
+        }
+      }
+
+      // return group config
+      config = {
+        'maxHolds'          :  maxHoldsValue || 100,
+        'maxItemsOut'       :  maxItemsOutValue,
+        'overdueThreshold'  :  overdueThresholdValue,
+        'fineThreshold'     :  fineThresholdValue
+      };
+
+      // debugging...
+      var str = "BCREK getGroupConfig():";
+      for( var i in config ){ 
+        str += i + '=' + config[i] + '  ';
+      }
+      log_debug(str);
+
+      return config;
+    }
+  };
+}
+
diff --git a/circ/config_BFN.js b/circ/config_BFN.js
new file mode 100644 (file)
index 0000000..295808d
--- /dev/null
@@ -0,0 +1,85 @@
+/** Policies for BTE */
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BFN");
+
+
+    return {
+
+        getLoanDuration : function() {
+            var circMod = (copy && copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+
+               if(patronProfile == 'Bush People'){
+                       return '28_3';
+               }
+            var map = {
+                '3-week-videos'     :   '21_3',
+                'juvenile-collection':  '21_3',
+                'videos'            :   '7_3',
+                'video-collection'  :   '7_3',
+                'nfb-videos'        :   '7_3'
+                       };
+                   
+            return map[circMod] || '21_3';
+               },
+
+        getRecurringFine : function() {
+            var circMod = (copy && copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+
+            var map = {
+                '3-week-videos'     :   'video',
+                'videos'            :   'video',
+                'video-collection'  :   'video',
+                'nfb-videos'        :   'video',
+                'juvenile-collection':  'juvenile'
+            };
+            
+            return map[circMod] || 'default';
+               },
+
+       getMaxFine : function() {
+               return 'default';
+
+       },
+
+       exceedsMaxCheckoutsByCircMod : function() {
+               return false;
+       },
+
+       isAllowedCirc : function() {
+               return true;
+       },
+
+    isAllowedHold : function() {
+        return true;
+    },
+
+       getGroupConfig : function() {
+               /* returns the combined user config object */
+
+               // override some defaults
+               GROUP_CONFIG.Patrons.maxItemsOut = -1;
+               GROUP_CONFIG.JuvenileRes.maxItemsOut = 6;
+           GROUP_CONFIG.Patrons.fineThreshold = 20;
+        
+               var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+               
+               // these are global settings for BFN users
+               config.maxHolds = -1;
+               config.fineThreshold = 20;
+               config.overdueThreshold = -1;
+               
+               // debugging...
+               var str = "BFN getGroupConfig():";
+               for( var i in config ){ 
+                       str += i + '=' + config[i] + '  ';
+               }
+        log_debug(str);
+
+               return config;
+       }
+    };
+}
+
diff --git a/circ/config_BGI.js b/circ/config_BGI.js
new file mode 100644 (file)
index 0000000..a886645
--- /dev/null
@@ -0,0 +1,173 @@
+/** Policies for Gibsons **/
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BGI");
+
+    var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+    return {
+
+        getLoanDuration : function() {
+            var map = {
+                'book'                  :   '21_2',
+                'paperbacks'            :   '21_2',
+                'magazine'              :   '7day',
+                'cassettebook'          :   '21_2',
+                'videos'                :   '7day',
+                'dvd'                   :   '7_1', // short = 3 days
+                'talking-books'         :   '7day',
+                'video-games'           :   '7day',
+                'audio-cds'             :   '7_1',
+                'juvenile-collection'   :   '21_2',
+                'juvenile-video'        :   '7day',
+                'kit'                   :   '21_1',
+                'new-books'             :   '21_2',
+                'inter-library-loan'    :   '21_0',
+                'best-seller'           :   '7_0', // short - 1 day (dvd)
+                'juvenile-serial'       :   '7day',
+                'language-learning'     :   '21_2'
+            };
+
+            return map[circMod] || '21_2';
+        },
+
+        getRecurringFine : function() {
+            if(patronProfile == 'InterLibraryLoan'){
+                return 'zero';
+            }
+            var map = {
+                'book'                  :   'default',
+                'paperbacks'            :   'default',
+                'magazine'              :   'default',
+                'cassettebook'          :   'default',
+                'videos'                :   'fiftycents',
+                'dvd'                   :   'onedollar',
+                'talking-books'         :   'default',
+                'video-games'           :   'onedollar',
+                'audio-cds'             :   'onedollar',
+                'juvenile-collection'   :   'tencents',
+                'juvenile-video'        :   'fiftycents', // high - $1
+                'kit'                   :   'tencents',
+                'new-books'             :   'default',
+                'inter-library-loan'    :   'onedollar',
+                'best-seller'           :   'onedollar',
+                'juvenile-serial'       :   'tencents',
+                'language-learning'     :   'default'
+            };
+
+            return map[circMod] || 'default';
+        },
+
+        getMaxFine : function() {
+
+            var map = {
+                'book'                  :   'fivedollar',
+                'paperbacks'            :   'fivedollar',
+                'magazine'              :   'fivedollar',
+                'cassettebook'          :   'fivedollar',
+                'videos'                :   'fivedollar',
+                'dvd'                   :   'fivedollar',
+                'talking-books'         :   'fivedollar',
+                'video-games'           :   'fivedollar',
+                'audio-cds'             :   'fivedollar',
+                'juvenile-collection'   :   'fivedollar',
+                'juvenile-video'        :   'threedollar', // high - $1
+                'kit'                   :   'fivedollar',
+                'new-books'             :   'fivedollar',
+                'inter-library-loan'    :   'fivedollar',
+                'best-seller'           :   'fivedollar',
+                'juvenile-serial'       :   'threedollar',
+                'language-learning'     :   'fivedollar'
+            };
+
+
+            return map[circMod] || 'fivedollar';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            var maxByCircMod = {
+                       'talking-books' : 4,
+                       'audio-cds' : 3,
+                       'video-games' : 1,
+                       'dvd' : 3,
+                       'playaway' : 1
+               };
+            if(isGroupDescendant('Staff', patronProfile)){
+                return false;
+            }
+            var circMod = (copy && copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+            var maxCount = maxByCircMod[circMod];
+            if(!maxCount || maxCount === null){ 
+                return false;
+            }
+            var outCount = checkoutsByCircModifier(patron.id)[circMod] || 0;
+            return outCount >= maxCount;
+        },
+
+        isAllowedCirc : function() {
+            return true;
+        },
+                
+        isAllowedHold : function() {
+            var nontransitmap = {
+                'videos'            :'1',
+                'video-game'        :'1',
+                'new-books'         :'1',
+                'best-seller'       :'1',
+                'language-learning' :'1',
+                'dvd'               :'1'
+                };
+             if((copy.circ_lib.id != holdPickupLib) && (nontransitmap[circMod])){
+                return 'false';
+            }
+       
+               if (circMod == 'best-seller'){
+                               return false;
+               }
+               return true;
+        },
+
+        getGroupConfig : function() {
+
+            // set defaults
+            var maxHoldsValue           =  -1 ;
+            var maxItemsOutValue        =  40;
+            var overdueThresholdValue   =  5;
+            var fineThresholdValue      =  3;
+            
+            // set special values for group
+            switch (patronProfile) {
+              case 'Homebound':
+                fineThresholdValue = 12;
+                overdueThresholdValue  = 100;
+                break;
+              case 'NonResident':
+                maxHoldsValue = 100;
+                maxItemsOutValue = 100;
+                overdueThresholdValue = 100;
+                break;
+              case 'InterLibraryLoan':
+                maxItemsOutValue = -1;
+                fineThresholdValue = 10;
+                overdueThresholdValue = 100;
+                break;
+              case 'BCOneCard':
+                maxItemsOutValue = 7;
+                overdueThresholdValue = 3;
+                break;
+               }
+
+            // return group config
+            var config = {
+              'maxHolds'          :  maxHoldsValue,
+              'maxItemsOut'       :  maxItemsOutValue,
+              'overdueThreshold'  :  overdueThresholdValue,
+              'fineThreshold'     :  fineThresholdValue
+            };
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BGSI.js b/circ/config_BGSI.js
new file mode 100644 (file)
index 0000000..2f4d567
--- /dev/null
@@ -0,0 +1,142 @@
+/** Policies for Salt Spring Public Libry BGSI **/
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BGSI");
+
+    return {
+
+        getLoanDuration : function() {
+
+            if (patronProfile == 'InterLibraryLoan'){
+              return '56_2';
+           }
+
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            var map = {
+                'dvd'                     : '7_1',
+                'cd-rom'                  : '7_1',
+                'juvenile-collection'     : '21_2',
+                'library-equipment'       : '30_0',
+                'magazine'                : '21_0',
+                'mass-market-paperbacks'  : '21_2',
+                'mp-3-audio-disc'         : '21_2',
+                'non-circulating'         : '21_2', 
+                'talking-books'           : '21_2',
+                'videos'                  : '7_1',
+                'compact-discs'           : '21_2'
+            };
+
+            return map[circMod] || '21_2';
+        },
+
+        getRecurringFine : function() {
+            
+            if (patronProfile == 'InterLibraryLoan'){
+              return 'zero';
+            }
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            var map = {
+                'dvd'                     : 'fiftycents',
+                'cd-rom'                  : 'twentycent',
+                'juvenile-collection'     : 'tencents',
+                'library-equipment'       : 'zero',
+                'magazine'                : 'tencents',
+                'mass-market-paperbacks'  : 'tencents',
+                'mp-3-audio-disc'         : 'twentycent',
+                'non-circulating'         : 'twentycent', 
+                'talking-books'           : 'twentycent',
+                'videos'                  : 'twentycent',
+                'compact-discs'           : 'twentycent'
+            };
+
+            return map[circMod] || 'twentycent';
+        },
+
+        getMaxFine : function() {
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            var map = {
+                'dvd'                     : 'fivedollar',
+                'cd-rom'                  : 'fivedollar',
+                'juvenile-collection'     : 'twodollar',
+                'library-equipment'       : 'fivedollar',
+                'magazine'                : 'onedollar',
+                'mass-market-paperbacks'  : 'twodollar',
+                'mp-3-audio-disc'         : 'fivedollar',
+                'non-circulating'         : 'fullprice', 
+                'talking-books'           : 'fivedollar',
+                'videos'                  : 'fivedollar',
+                'compact-discs'           : 'fivedollar'
+            };
+
+            return map[circMod] || 'fivedollar';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            log_debug('exceedsMaxCheckoutsByCircMod()');
+
+            return false;
+        },
+
+        isAllowedCirc : function() {
+            return true;
+        },
+                
+        isAllowedHold : function() {
+            return true;
+        },
+
+        getGroupConfig : function() {
+
+            // set defaults
+            var maxHoldsValue           =  -1;
+            var maxItemsOutValue        =  12;
+            var overdueThresholdValue   =  -1;
+            var fineThresholdValue      =   5;
+            
+            // set special values for group
+            switch (patronProfile) {
+              case 'Board':
+              case 'Homebound':
+              case 'Institution':
+              case 'JuvenileRes':
+              case 'NonResident':
+             case 'InterLibraryLoan':
+               maxItemsOutValue        = -1;
+               break;
+             case 'BCOneCard':
+               maxItemsOutValue        = 5;
+               break;
+             case 'Temporary':
+               maxItemsOutValue        = 5;
+               break;
+             case 'Transient':
+               maxItemsOutValue        = 5;
+               break;
+             case 'NoFines':
+             case 'Volunteer':
+             case 'Staff':
+                maxItemsOutValue       =  -1;
+               fineThresholdValue      = -1;
+                break;
+              default:
+                //do nothing
+            }
+
+            // return group config
+            var config = {
+              'maxHolds'          :  maxHoldsValue,
+              'maxItemsOut'       :  maxItemsOutValue,
+              'overdueThreshold'  :  overdueThresholdValue,
+              'fineThreshold'     :  fineThresholdValue
+            };
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BH.js b/circ/config_BH.js
new file mode 100644 (file)
index 0000000..a03587d
--- /dev/null
@@ -0,0 +1,109 @@
+/** Policies for BH */
+/* record-lp doesn't exist!!! Ignore it!!  */
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BH");
+
+    var circMod = (copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+
+    return {
+
+        getLoanDuration : function() {
+            /* returns config.rule_circ_duration.name */
+            var circMod = (copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+                
+                       if(patronProfile == 'InterLibraryLoan'){
+                               return '28_2';
+            }
+
+            var map = {
+                'holiday-special'       :   '14_2',
+                'compact-discs'         :   '7_1',
+                'talking-books'         :   '7_1',
+                'videos'                :   '7_1',
+                'dvd'                   :   '7_1'
+            };
+
+            return map[circMod] || '21_2'; 
+
+        },
+
+        getRecurringFine : function() {
+            /* returns config.rule_recuring_fine.name */
+                       if(patronProfile == 'InterLibraryLoan'){
+                               return 'staff';
+            }
+            
+            var map = {
+                'compact-discs'     :       'fiftycents',
+                'talking-books'     :       'fiftycents',
+                'videos'            :       'fiftycents',
+                'dvd'               :       'fiftycents'
+            };
+            return map[circMod] || 'fivecents';
+
+        },
+
+        getMaxFine : function() {
+            /* returns config.rule_max_fine.name */
+            return 'threedollar';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            log_debug("exceedsMaxCheckoutsByCircMod()");
+            if(isGroupDescendant('Staff', patronProfile)){
+                return false;
+            }
+            var circMod = (copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+            if (!(circMod == 'compact-discs' || circMod == 'talking-books' || circMod == 'videos' || circMod == 'dvd')) {
+                return false;
+                       }
+            var maxCount = 4;
+            var mediaCount = 0;
+            mediaCount += parseInt(checkoutsByCircModifier(patron.id)['compact-discs']) || 0;
+            mediaCount += parseInt(checkoutsByCircModifier(patron.id)['talking-books']) || 0;
+            mediaCount += parseInt(checkoutsByCircModifier(patron.id)['videos']) || 0;
+            mediaCount += parseInt(checkoutsByCircModifier(patron.id)['dvd']) || 0;
+            log_debug("found max out by circ mod "+circMod+" and checked out media total count is "+mediaCount);
+            return mediaCount >= maxCount;
+        },
+
+        isAllowedCirc : function() {
+           if(patronProfile == 'JuvenileRes') {
+                if(circMod == 'compact-discs' || circMod == 'talking-books' || circMod == 'videos' || circMod == 'dvd'){
+                    return false;
+                }
+           }
+           return true;
+        },
+        
+        isAllowedHold : function() {
+            return true;
+        },
+
+        getGroupConfig : function() {
+            /* returns the combined user config object */
+
+            // override some defaults
+
+            var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+            
+            // these are global settings for BH users
+            config.fineThreshold = 5;
+            config.maxHolds = -1;
+            config.overdueThreshold = 5;
+
+            // debugging...
+            var str = "BH getGroupConfig():";
+               for( var i in config ){ 
+                       str += i + '=' + config[i] + '  ';
+            }
+               log_debug(str);
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BHA.js b/circ/config_BHA.js
new file mode 100644 (file)
index 0000000..3cd420b
--- /dev/null
@@ -0,0 +1,81 @@
+/** Policies for Salt Spring Public Libry BGSI **/
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BGSI");
+
+    return {
+
+        getLoanDuration : function() {
+
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            var map = {
+                'dvd'                     : '7_3',
+                'videos'                  : '7_3'
+            };
+
+            return map[circMod] || '21_10';
+        },
+
+        getRecurringFine : function() {
+            if (patronProfile == 'InterLibraryLoan'){
+                return 'zero';
+            }
+            return 'fivecents';
+        },
+
+        getMaxFine : function() {
+            return 'twofifty';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            return false;
+        },
+
+        isAllowedCirc : function() {
+            return true;
+        },
+                
+        isAllowedHold : function() {
+            return true;
+        },
+
+        getGroupConfig : function() {
+
+            // set defaults
+            var maxHoldsValue           =  100;
+            var maxItemsOutValue        =  50;
+            var overdueThresholdValue   =  100;
+            var fineThresholdValue      =   10;
+            
+            // set special values for group
+            switch (patronProfile) {
+                   case 'InterLibraryLoan':
+                    maxItemsOutValue   = 1000;
+                    break;
+                case 'BCOneCard':
+                       maxItemsOutValue        = 5;
+                           break;
+                case 'Staff':
+                    maxItemsOutValue       =  1000;
+                           fineThresholdValue  = 100;
+                    break;
+              default:
+                //do nothing
+            }
+
+            // return group config
+            var config = {
+              'maxHolds'          :  maxHoldsValue,
+              'maxItemsOut'       :  maxItemsOutValue,
+              'overdueThreshold'  :  overdueThresholdValue,
+              'fineThreshold'     :  fineThresholdValue
+            };
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BIN.js b/circ/config_BIN.js
new file mode 100644 (file)
index 0000000..91d6f70
--- /dev/null
@@ -0,0 +1,99 @@
+/** Policies for Invermere Public Libry BIN **/
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BIN");
+
+    return {
+
+        getLoanDuration : function() {
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+                       var map = {
+                               'audio-cassette'          : '21_10',
+                               'compact-discs'           : '21_10',
+                               'dvd'                     : '21_10',
+                               'videos'                  : '21_10',
+                               'book'                    : '21_10',
+                               'juvenile-collection'     :     '21_10',
+                               'paperbacks'              : '21_10',
+                               'magazine'               :      '7_3'
+                       };
+
+                   return map[circMod] || 'default';
+        },
+
+               getRecurringFine : function() {
+                       var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+                       var map = {
+                               'audio-cassette'      : 'default',
+                               'compact-discs'       : 'default',
+                               'dvd'                 : 'default',
+                               'videos'              : 'default',
+                               'book'                : 'default',
+                               'juvenile-collection' : 'tencents',
+                               'paperbacks'          : 'tencents',
+                               'magazine'           : 'default',
+                               'non-circulating'     : 'default'
+                       };
+
+                       return map[circMod] || 'default';
+               },
+
+               getMaxFine : function() {
+                       var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+                       var map = {
+                               'audio-cassette'       : 'default',
+                               'compact-discs'        : 'default',
+                               'dvd'                  : 'default',
+                               'videos'               : 'default',
+                               'book'                 : 'default',
+                               'juvenile-collection'  : 'default',
+                               'paperbacks'           : 'default',
+                               'magazine'            : 'default_low',
+                               'non-circulating'      : 'default'
+                       };
+
+                       return map[circMod] || 'default';
+               },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            return false;
+        },
+
+        isAllowedCirc : function() {
+               return true;
+        },
+                
+        isAllowedHold : function() {
+               return true;
+        },
+
+               getGroupConfig : function() {
+
+                       GROUP_CONFIG.Patrons.maxHolds       =  10;
+                       GROUP_CONFIG.JuvenileRes.maxHolds   =  10;
+                       GROUP_CONFIG.NonResident.maxHolds   =  10;
+                       GROUP_CONFIG.BCOneCard.maxHolds     =   0;
+                       GROUP_CONFIG.Temporary.maxHolds     =   3;
+                       GROUP_CONFIG.Transient.maxHolds     =  10;
+                       GROUP_CONFIG.Volunteer.maxHolds     =  10;
+                       GROUP_CONFIG.Staff.maxHolds         =  10;
+
+                       var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+
+                       //config.maxHolds                   =  10;
+                       config.maxItemsOut                  = 100;
+                       GROUP_CONFIG.BCOneCard.maxItemsOut      =       5;
+                       GROUP_CONFIG.Temporary.maxItemsOut      =       3;
+
+                       config.overdueThreshold             =  -1;
+                       config.fineThreshold                =  10;
+
+                       return config;
+               }
+    };
+}
+
diff --git a/circ/config_BLP-BB.js b/circ/config_BLP-BB.js
new file mode 100644 (file)
index 0000000..c8cfd0e
--- /dev/null
@@ -0,0 +1,71 @@
+/** Policies for Lillooet Book Bus BLP-BB  **/
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BLP");
+
+    return {
+
+        getLoanDuration : function() {
+            return '31_1';
+        },
+
+        getRecurringFine : function() {
+            return 'zero';
+        },
+
+        getMaxFine : function() {
+            return 'fullprice';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            log_debug('exceedsMaxCheckoutsByCircMod()');
+
+            return false;
+        },
+
+        isAllowedCirc : function() {
+            return true;
+        },
+                
+        isAllowedHold : function() {
+            return true;
+        },
+
+        getGroupConfig : function() {
+
+            // set defaults
+            var maxHoldsValue           =   4;
+            var maxItemsOutValue        =  20;
+            var overdueThresholdValue   =  20;
+            var fineThresholdValue      =  -1;
+            
+            // set special values for group
+            switch (patronProfile) {
+              case 'Patrons':
+                fineThresholdValue     =  100;
+                break;
+              case 'InterLibraryLoan':
+                maxItemsOutValue            =  150;
+                maxHoldsValue          =    0;
+                overdueThresholdValue  =  150;
+                break;
+              case 'BCOneCard':
+                maxHoldsValue = 0;
+                break;
+            }
+
+            // return group config
+            var config = {
+              'maxHolds'          :  maxHoldsValue,
+              'maxItemsOut'       :  maxItemsOutValue,
+              'overdueThreshold'  :  overdueThresholdValue,
+              'fineThreshold'     :  fineThresholdValue
+            };
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BLP.js b/circ/config_BLP.js
new file mode 100644 (file)
index 0000000..55c6f5a
--- /dev/null
@@ -0,0 +1,135 @@
+/** Policies for Lillooet (BLP-LL, BLP-GB, BLP-BR) **/
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BLP");
+
+    return {
+
+        getLoanDuration : function() {
+
+            if (isGroupDescendant('InterLibraryLoan', patronProfile)) {
+                return '42day';
+            }
+
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            var map = {
+                'audio-cassette'            :  '14_2',
+                'audio-cds'                 :  '14_2',
+                'cassette-and-book-in-bag'  :  '14_2',
+                'cassettebook'              :  '14_2',
+                'cd-and-book-in-bag'        :  '14_2',
+                'cd-audiobook'              :  '14_2',
+                'cd-rom'                    :  '14_2',
+                'compact-discs'             :  '14_2',
+                'dvd'                       :  '14_2',
+                'media'                     :  '14_2',
+                'mp-3-audio-disc'           :  '14_2',
+                'talking-books'             :  '14_2',
+                'videos'                    :  '14_2'
+            };
+
+            return map[circMod] || '21_2';
+        },
+
+        getRecurringFine : function() {
+            if(patronProfile == 'InterLibraryLoan' || patronProfile == 'Volunteer' || patronProfile == 'Board'){
+                return 'zero';
+            }
+
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            var map = {
+                'audio-cassette'            :  'fiftycents',
+                'audio-cds'                 :  'fiftycents',
+                'cassette-and-book-in-bag'  :  'fiftycents',
+                'cassettebook'              :  'fiftycents',
+                'cd-and-book-in-bag'        :  'fiftycents',
+                'cd-audiobook'              :  'fiftycents',
+                'cd-rom'                    :  'fiftycents',
+                'compact-discs'             :  'fiftycents',
+                'dvd'                       :  'fiftycents',
+                'media'                     :  'fiftycents',
+                'mp-3-audio-disc'           :  'fiftycents',
+                'talking-books'             :  'fiftycents',
+                'videos'                    :  'fiftycents',
+
+                'inter-library-loan'  :  'zero',
+                'restricted-access'   :  'zero',
+                'non-circulating'     :  'zero'
+            };
+
+            return map[circMod] || 'default';
+        },
+
+        getMaxFine : function() {
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            var map = {
+                'audio-cassette'            :  'fivedollar',
+                'audio-cds'                 :  'fivedollar',
+                'cassette-and-book-in-bag'  :  'fivedollar',
+                'cassettebook'              :  'fivedollar',
+                'cd-and-book-in-bag'        :  'fivedollar',
+                'cd-audiobook'              :  'fivedollar',
+                'cd-rom'                    :  'fivedollar',
+                'compact-discs'             :  'fivedollar',
+                'dvd'                       :  'fivedollar',
+                'media'                     :  'fivedollar',
+                'mp-3-audio-disc'           :  'fivedollar',
+                'talking-books'             :  'fivedollar',
+                'videos'                    :  'fivedollar'
+            };
+
+            return map[circMod] || 'fivedollar';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            log_debug('exceedsMaxCheckoutsByCircMod()');
+
+            return false;
+        },
+
+        isAllowedCirc : function() {
+            return true;
+        },
+                
+        isAllowedHold : function() {
+            return true;
+        },
+
+        getGroupConfig : function() {
+
+            // set defaults
+            var maxHoldsValue           =   4;
+            var maxItemsOutValue        =  20;
+            var overdueThresholdValue   =  20;
+            var fineThresholdValue      =  -1;
+            
+            // set special values for group
+            switch (patronProfile) {
+              case 'InterLibraryLoan':
+                maxItemsOutValue            = 150;
+                maxHoldsValue          =   0;
+                overdueThresholdValue  = 150;
+                break;
+              case 'BCOneCard':
+                maxHoldsValue = 0;
+                break;
+            }
+
+            // return group config
+            var config = {
+              'maxHolds'          :  maxHoldsValue,
+              'maxItemsOut'       :  maxItemsOutValue,
+              'overdueThreshold'  :  overdueThresholdValue,
+              'fineThreshold'     :  fineThresholdValue
+            };
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BM.js b/circ/config_BM.js
new file mode 100644 (file)
index 0000000..eda7e49
--- /dev/null
@@ -0,0 +1,99 @@
+/** Policies for BM **/
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BM");
+
+    return {
+
+        getLoanDuration : function() {
+            /* returns config.rule_circ_duration.name */
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            var map = {
+                'book'      :   '21_2',
+                'videos'    :   '7day',
+                'dvd'       :   '7day',
+                'magazine'  :   '7day',
+                'video'     :   '7day'
+            };
+
+            return map[circMod] || '21_2'; 
+
+        },
+
+        getRecurringFine : function() {
+            /* returns config.rule_recuring_fine.name */
+               return 'tencents';
+        },
+
+        getMaxFine : function() {
+            /* returns config.rule_max_fine.name */
+            return 'threedollar';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            log_debug("exceedsMaxCheckoutsByCircMod()");
+
+               if(isGroupDescendant('Staff', patronProfile)) {
+                return false;
+               }
+
+               var circMod = (copy && copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+                       
+               circModCount = checkoutsByCircModifier(patron.id)[circMod] || 0;
+               var maxByCircMod = {
+                       'videos' : 3,
+                       'video' : 3,
+                       'dvd' : 3
+               };
+               var circModLimit = maxByCircMod[circMod] || 30;
+                       
+               log_debug("go Max for circ_mod:"+circMod+"/patron:"+patronProfile+" is "+circModLimit+ " - you had "+circModCount);
+               return circModCount >= circModLimit;
+
+        },
+
+        isAllowedCirc : function() {
+        
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            if(patronProfile == 'BCOneCard'){
+                       if (circMod != 'book') {
+                           return 'false';
+                       }
+               }
+               return true;
+        },
+
+        isAllowedHold : function() {
+            return true;
+        },
+                
+        getGroupConfig : function() {
+            /* returns the combined user config object */
+
+            // override some defaults
+
+            var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+            
+            // these are global settings for BH users
+            config.fineThreshold = 20;
+            config.maxHolds = -1;
+            config.overdueThreshold = 3;
+            config.maxItemsOut = 30;
+
+
+            // debugging...
+            var str = "BM getGroupConfig():";
+               for( var i in config ){ 
+                       str += i + '=' + config[i] + '  ';
+            }
+               log_debug(str);
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BNA.js b/circ/config_BNA.js
new file mode 100644 (file)
index 0000000..db05a02
--- /dev/null
@@ -0,0 +1,81 @@
+/** Policies for BNA**/
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info forBNA");
+
+    return {
+
+        getLoanDuration : function() {
+            /* returns config.rule_circ_duration.name */
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            if (isGroupDescendant('InterLibraryLoan', patronProfile)) {
+                return '28_2';
+            }
+
+            var map = {
+                'book'      :   '21_2',
+                'videos'    :   '7day',
+                'dvd'       :   '7day',
+                'magazine'  :   '7day'
+            };
+
+               return map[circMod] || '21_2'; 
+                   
+        },
+
+        getRecurringFine : function() {
+            /* returns config.rule_recuring_fine.name */
+            if (isGroupDescendant('InterLibraryLoan', patronProfile)) {
+                return 'staff';
+            }
+            return 'tencents';
+        },
+
+        getMaxFine : function() {
+            /* returns config.rule_max_fine.name */
+            return 'default';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            return false;
+        },
+
+        isAllowedCirc : function() {
+               return 'true';
+        },
+                
+        isAllowedHold : function() {
+               return 'true';
+        },
+        
+        getGroupConfig : function() {
+            /* returns the combined user config object */
+
+            // override some defaults
+           GROUP_CONFIG.Patrons.fineThreshold = 20;
+           GROUP_CONFIG.JuvenileRes.fineThreshold = 10;
+           //GROUP_CONFIG.JuvenileNonRes.fineThreshold = 10;
+           
+            var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+            
+            // these are global settings for BH users
+            config.maxHolds = -1;
+            config.overdueThreshold = -1;
+            config.maxItemsOut = 99;
+
+
+            // debugging...
+            var str = "BNA getGroupConfig():";
+               for( var i in config ){ 
+                       str += i + '=' + config[i] + '  ';
+            }
+               log_debug(str);
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BPE.js b/circ/config_BPE.js
new file mode 100644 (file)
index 0000000..bec8814
--- /dev/null
@@ -0,0 +1,117 @@
+/** Policies for BPE **/
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BPE");
+
+    return {
+
+        getLoanDuration : function() {
+            /* returns config.rule_circ_duration.name */
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+            var map = {
+                '7-day-loan':           '7_0',
+                'book':                '28_3',
+                'cd-audiobook':        '28_1',
+                'talking-books':       '28_1',
+                'juvenile-collection': '28_3',
+                'videos':              '7_1',
+                'dvd':                 '7_1',
+                'compact-discs':       '14_1',
+                'magazine':            '14_1',
+                'cd-roms':             '14_1',
+                'pamphlets':           '1day_no_renew',
+                'maps':                '1day_no_renew',
+                'juvenile-7day':       '7_0',
+                'book-7day':           '7_0'
+            };
+            return map[circMod] || 'default';
+        },
+
+        getRecurringFine : function() {
+            /* returns config.rule_recuring_fine.name */
+                       return 'staff';
+        },
+
+        getMaxFine : function() {
+            /* returns config.rule_max_fine.name */
+            return 'default';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            log_debug("exceedsMaxCheckoutsByCircMod()");
+
+                       if(isGroupDescendant('Staff', patronProfile)){
+                return false;
+            }
+
+                       var circMod = (copy && copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+                       var circModCount = checkoutsByCircModifier(patron.id)[circMod] || 0;
+                       var maxByCircMod;
+            var circModLimit;
+
+                       if(patronProfile == 'JuvenileRes'){
+                           maxByCircMod = {
+                                       'videos' : 10,
+                                       'compact-discs' : 4,
+                                       'cd-audiobook' : 6,
+                                       'pamphlets' : 2,
+                                       'dvd' : 4
+                           };
+                circModLimit = maxByCircMod[circMod] || 10;
+                       } 
+                       else {
+                           maxByCircMod = {
+                                       'videos' : 10,
+                                       'compact-discs' : 4,
+                                       'cd-audiobook' : 6,
+                                       'pamphlets' : 2,
+                                       'dvd' : 4
+                           };
+                               circModLimit = maxByCircMod[circMod] || 30;
+                       }
+                       
+//                     var circModLimit = 0;
+               log_debug("go Max for circ_mod:"+circMod+"/patron:"+patronProfile+" is "+circModLimit+ " - you had "+circModCount);
+                       return circModCount >= circModLimit;
+
+        },
+
+
+        isAllowedCirc : function() {
+           return true;
+        },
+
+        isAllowedHold : function() {
+           return true;
+        },
+
+
+        getGroupConfig : function() {
+            /* returns the combined user config object */
+
+            // override some defaults
+
+            var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+            
+            // these are global settings for BH users
+            config.fineThreshold = 5;
+            config.maxHolds = -1;
+            config.overdueThreshold = 10;
+            config.maxItemsOut = 30;
+                       GROUP_CONFIG.JuvenileRes.maxItemsOut = 10;
+
+
+            // debugging...
+            var str = "BPE getGroupConfig():";
+               for( var i in config ){ 
+                       str += i + '=' + config[i] + '  ';
+            }
+               log_debug(str);
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BPR.js b/circ/config_BPR.js
new file mode 100644 (file)
index 0000000..c47e1a4
--- /dev/null
@@ -0,0 +1,134 @@
+/** Policies for BPR */
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BPR");
+
+    return {
+        getLoanDuration : function() {
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+//            if (copy.call_number == -1){
+//                return '21_0';
+//            }
+
+                       /* circ duration rules are:
+                       default = 21 days
+                       1day = 1 day
+                       7 day = 7 days
+                       everything is 2 renewals */
+                       
+                       var map = {
+                               '1-day-loan'         : '1day',
+                               '7-day-loan'         : '7day',
+                               'digital-disc'       : '7day',
+                               'library-equipment'  : '1day',
+                               'pamphlets'          : '1day',
+                               'videos'             : '7day',
+                               'videos-educational' : '7day',
+                               'videos-features'    : '7day'
+                       };
+
+                       if(patronProfile == 'Lighthouse'){
+                               return 'lighthouse'; // 90 days
+            }
+
+                   return map[circMod] || 'default'; //21 days
+        },
+       
+       getRecurringFine : function() {
+                       var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+                       /* recurring fine rules are:
+                       video = $1, juvenile = $0.10, equipment = $30, default = $0.25
+                       ILL = 0.50, staff = 0.00 */
+                       
+                       var map = {
+                               'videos'                 : 'video',
+                               'video'                  : 'video',
+                               'dvd'                : 'video',
+                               'digital-disc'       : 'video',
+                               'videos-educational' : 'video',
+                               'videos-features'    : 'video',
+                               '1-day-loan'         : 'video',
+                               'juvenile-collection': 'juvenile',
+                               'library-equipment'  : 'equipment'
+                       };
+                       if(patronProfile == 'InterLibraryLoan'){
+                               return 'ILL';
+                       }
+            if(patronProfile == 'Staff'){
+                               return 'staff';
+            }
+                       return map[circMod] || 'default';
+               },
+               
+               getMaxFine : function() {
+                       var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+                       /* max fine rules are:
+                       'video' = $10, 'default' = $5.  
+                       */
+                       var map = {
+                               'videos'                 : 'video',
+                               'video'                  : 'video',
+                               'dvd'                : 'video',
+                               'digital-disc'       : 'video',
+                               'videos-educational' : 'video',
+                               'videos-features'    : 'video',
+                               '1-day-loan'         : 'video'
+                       };
+
+                       return map[circMod] || 'default';
+               },
+        exceedsMaxCheckoutsByCircMod : function() {
+            var maxByCircMod = {
+                       'compact-discs' : 5,
+                       'digital-disc' : 3,
+                       'talking-books' : 5
+                   };
+            log_debug("exceedsMaxCheckoutsByCircMod()");
+            if(isGroupDescendant('Staff', patronProfile)){
+                return false;
+            }
+            var circMod = (copy && copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+            var maxCount = maxByCircMod[circMod];
+            log_debug("checking circ mod " + circMod);
+            if(!maxCount || maxCount === null){ 
+                return false;
+            }
+            var outCount = checkoutsByCircModifier(patron.id)[circMod] || 0;
+            log_info("BPR-1392 - found max out "+maxCount+" for circ mod " +circMod+ " and patron "+patron.id+" checked out count is "+outCount);
+            return outCount >= maxCount;
+        },
+        
+        isAllowedCirc : function() {
+            return true;
+        },
+
+        isAllowedHold : function() {
+            return true;
+        },
+
+
+        getGroupConfig : function() {
+            /* returns the combined user config object */
+
+            // override some defaults
+
+            var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+            
+            // these are global settings for BPR users
+                               config.fineThreshold = 5;
+                       
+            // debugging...
+            var str = "BPR getGroupConfig():";
+               for( var i in config ){ 
+                       str += i + '=' + config[i] + '  ';
+            }
+               log_debug(str);
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BPRDP.js b/circ/config_BPRDP.js
new file mode 100644 (file)
index 0000000..e9b4967
--- /dev/null
@@ -0,0 +1,142 @@
+/** Policies for BPRDP */
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BPRDP");
+
+    var map = {
+        'A' : 'compact-discs',
+        'B' : 'talking-books',
+        'C' : 'audio-cds-cnib',
+        'H' : 'holiday-special',
+        'J' : 'juvenile-collection',
+        'L' : 'periodical',
+        'M' : 'periodical',
+        'N' : 'new-books',
+        'O' : 'inter-library-loan',
+        'P' : 'paperbacks',
+        'S' : 'book',
+        'V' : 'videos'
+    };
+
+    var oldcircmod = copy.circ_modifier || 'book';
+    var circmod = (map[oldcircmod]) ? map[oldcircmod] : oldcircmod.toLowerCase();
+
+    return {
+
+        getLoanDuration : function() {
+                       if(patronProfile == 'Homebound'){
+                               return '28_1';
+            }
+                       if(patronProfile == 'InterLibraryLoan'){
+                               return '30_1';
+               }
+                       if(patronProfile == 'Institution') {
+                           if(circmod == 'holiday-special') {
+                               return '28_1';
+                           } else {
+                               if(circmod == 'book') {
+                               return '35_1';
+                       }
+               }
+               }
+               if(patronProfile == 'BCOneCard') {
+                       if( (circmod == 'juvenile-collection' || circmod == 'paperbacks' || circmod == 'book') ) {
+                                       return '14_1';
+                               }
+                       }
+                       
+                       if(circmod == 'juvenile-collection' || circmod == 'book' || circmod == 'paperbacks'){
+                           return '28_1';
+            }
+            if (copy.call_number == -1){
+                return '14_0';
+            }
+
+                       return '14_1';
+        },
+
+        getRecurringFine : function() {
+            /* returns config.rule_recuring_fine.name */
+            if(patronProfile == 'Homebound' || patronProfile == 'InterLibrarLoan'){ 
+               return 'staff';
+            }
+            
+            var map = {
+                'compact-discs'       : 'fiftycents',
+                'talking-books'       : 'fiftycents',
+                'videos'            : 'fiftycents'
+            };
+            return map[circmod] || 'default'; 
+        },
+
+        getMaxFine : function() {
+            /* returns config.rule_max_fine.name */
+            if(patronProfile == 'Homebound' || patronProfile == 'InterLibrarLoan'){ 
+               return 'staff';
+            }
+            var map = {
+                'holiday-special'       : 'default_low',
+                'juvenile-collection'   : 'default_low',
+                'periodical'            : 'default_low',
+                'paperbacks'            : 'default_low'
+            };
+            return map[circmod] || 'default'; 
+        },
+
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            return false;
+        },
+
+               isAllowedCirc : function() {
+                       if(patronProfile == 'BCOneCard') {
+                               if( !(circmod == 'juvenile-collection' || circmod == 'paperbacks' || circmod == 'book') ) {
+                                       return false;
+                               }
+                       }
+                       
+                       if(patronProfile == 'Institution' || patronProfile == 'InterLibraryLoan' || patronProfile == 'Transient') {
+                               if(circmod == 'audio-cds-cnib') {
+                                       return false;
+                               }
+                       }
+
+                       return true;
+               },
+
+        isAllowedHold : function() {
+            return true;
+        },
+
+        getGroupConfig : function() {
+            /* returns the combined user config object */
+            
+            // override some defaults
+                       GROUP_CONFIG.Patrons.maxItemsOut = 30;
+                       GROUP_CONFIG.JuvenileRes.maxItemsOut = 30;
+                       GROUP_CONFIG.NonResident.maxItemsOut = 30;
+                       GROUP_CONFIG.Institution.maxItemsOut = 60;
+            /* GROUP_CONFIG.BCOneCard.maxItemsOut = 5 */
+            GROUP_CONFIG.Transient.maxItemsOut = 5;
+                       GROUP_CONFIG.Homebound.maxItemsOut = 65;
+                       GROUP_CONFIG.InterLibraryLoan.maxItemsOut = 600;
+
+            var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+
+            // these are global settings for BPRDP users
+                       config.fineThreshold = 10;
+                       config.maxHolds = -1;
+            // debugging...
+            var str = "BPRDP getGroupConfig():";
+               for( var i in config ){ 
+                       str += i + '=' + config[i] + '  ';
+               }
+            log_debug(str);
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BR.js b/circ/config_BR.js
new file mode 100644 (file)
index 0000000..19976c9
--- /dev/null
@@ -0,0 +1,108 @@
+/** Policies for Rossland Public Libry BR **/
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BR");
+
+    return {
+
+        getLoanDuration : function() {
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            var map = {
+                // no reference/big books
+                'book'          : '21_3', // need to create this rule! (copy 'staff')
+                'talking-books' : '21_3',
+                'magazine'      : '21_3',
+                'compact-discs' : '7_0',
+                'videos'        : '7_0',
+                'dvd'           : '7_0'
+            };
+
+            return map[circMod] || '21_3'; 
+        },
+
+        getRecurringFine : function() {
+            switch (patronProfile) {
+              case 'Board':
+              case 'InterLibraryLoan':
+              case 'Volunteer':
+              case 'Staff':
+                return 'staff';
+            }
+
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            var map = {
+                // no reference/big books
+                'book'          : 'tencents',
+                'talking-books' : 'tencents',
+                'magazine'      : 'tencents',
+                'compact-discs' : 'video', // $1 per day
+                'videos'        : 'video',
+                'dvd'           : 'video'
+            };
+
+            return map[circMod] || 'tencents';
+        },
+
+        getMaxFine : function() {
+            return 'threedollar'; // all BR items have $3 max fine
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            //log_debug('exceedsMaxCheckoutsByCircMod()');
+            return false;
+        },
+
+        isAllowedCirc : function() {
+            return 'true';
+        },
+                
+        isAllowedHold : function() {
+            return 'true';
+        },
+
+        getGroupConfig : function() {
+
+            // set defaults
+            var maxHoldsValue           =   3;
+            var maxItemsOutValue        =  50;
+            var overdueThresholdValue   =  -1;
+            var fineThresholdValue      =  20;
+            
+            // set special values for group
+            switch (patronProfile) {
+              case 'JuvenileRes':
+                maxItemsOutValue  =  10;
+                break;
+              case 'InterLibraryLoan':
+                maxItemsOutValue  =  500;
+                maxHoldsValue     =    0;
+                break;
+              case 'BCOneCard':
+                maxItemsOutValue   =  5;
+                maxHoldsValue      =  0;
+                fineThresholdValue = -1;
+                break;
+              case 'Temporary':
+                maxItemsOutValue  =  5;
+                break;
+              default:
+                //do nothing
+            }
+
+            // return group config
+            var config = {
+              'maxHolds'          :  maxHoldsValue,
+              'maxItemsOut'       :  maxItemsOutValue,
+              'overdueThreshold'  :  overdueThresholdValue,
+              'fineThreshold'     :  fineThresholdValue
+            };
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BS.js b/circ/config_BS.js
new file mode 100644 (file)
index 0000000..913a480
--- /dev/null
@@ -0,0 +1,131 @@
+/** Policies for BS -- Smithers Public Library **/
+
+function getPolicy() {
+
+       load_lib('circ/circ_lib.js');
+       log_info('Loading policy info for BS');
+
+    var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+       return {
+
+               // returns config.rule_circ_duration.name
+               getLoanDuration: function () {
+
+            if (copy.call_number == -1){
+                    return '21_0';
+            }
+                       
+                       var map = {
+                               'book':            'default',
+                               'magazine':        'default',
+                               'non-circulating': 'default',
+                               'holiday-special': 'default',
+                               'kit':             'default',
+                               'compact-discs':   'default',
+                               'cd-audiobook':    'default',
+                               'dvd':             'default',
+                           'paperback':        'default'
+            };
+                       return map[circMod] || 'default';
+               },
+
+               // returns config.rule_recuring_fine.name
+               getRecurringFine: function () { return 'tencents'; },
+
+               // returns config.rule_max_fine.name
+               getMaxFine: function () { 
+
+            var map = {
+                'paperback' : 'onedollar',
+                'paperbacks'    : 'onedollar',
+                'magazine'  :   'onedollar' };
+
+            return map[circMod]||'default_low'; 
+        },
+
+               // Is a patron exceeding max checkout limit for a circ modifier?
+               exceedsMaxCheckoutsByCircMod: function () {
+                       log_debug('exceedsMaxCheckoutsByCircMod()');
+
+                       if ( isGroupDescendant('Staff', patronProfile) ){
+                               return false; // no limit for staff patrons
+            }
+
+                       var circMod = (copy && copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+
+                       var map = {
+                               'cd-audiobook': 3
+                       };
+                       var max = map[circMod] || -1;
+                       if (max < 0) {
+                return false; // no limit for circMod
+               }
+                       var checkouts = checkoutsByCircModifier(patron.id)[circMod] || 0;
+                       
+                       log_debug("go Max for circ_mod:" +circMod+ "/patron:" +patronProfile+ " is " +max+ " - you had " +checkouts);
+                       return checkouts > max;
+               },
+
+               isAllowedCirc: function () {
+                       if (patron.profile.name == 'BCOneCard' && circMod != 'book'){
+                return 'true';
+            }
+            return 'false';
+            
+               },
+
+        isAllowedHold: function() {
+            return true;
+        },
+
+               // returns the combined user config object
+               getGroupConfig: function () {
+
+                       var normal = {
+                               maxHolds:           5,
+                               maxItemsOut:      100,
+                               overdueThreshold:  -1,
+                               fineThreshold:      10
+                       };
+                       var special = {
+                               maxHolds:           5,
+                               maxItemsOut:      100,
+                               overdueThreshold:  -1,
+                               fineThreshold:     10 
+                       };
+                       var onecard = {
+                               maxHolds:           0,
+                               maxItemsOut:        5,
+                               overdueThreshold:  -1,
+                               fineThreshold:     10 
+                       };
+                       var staff = {
+                               maxHolds:          99,
+                               maxItemsOut:      100,
+                               overdueThreshold:  -1,
+                               fineThreshold:     10 
+                       };
+                       var map = {
+                               Patrons:     normal,
+                               NonResident: special,
+                               JuvenileRes: special,
+                               BCOneCard:   onecard,
+                               Institution: special,
+                               Temporary:   special,
+                               Staff:       staff,
+                               Users:       onecard
+                       };
+                       var config = map[patronProfile] || special;
+
+                       // debugging...
+                       //var str = 'BS getGroupConfig():';
+                       //for (var i in config){
+            //    str += i+ '=' +config[i]+ '  ';
+                       //}
+            //log_debug(str);
+
+                       return config;
+               }
+       };
+}
+
diff --git a/circ/config_BSA.js b/circ/config_BSA.js
new file mode 100644 (file)
index 0000000..a78e650
--- /dev/null
@@ -0,0 +1,171 @@
+/** Policies for Salmo Public Libry BSA **/
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BSA");
+
+    return {
+
+        getLoanDuration : function() {
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            var map = {
+                'juvenile-collection'     :    '21_2',
+                'magazine'                :    '7_1',
+                'hardback'                : '21_2',
+                'mass-market-paperbacks'  : '21_2',
+                'compact-discs'           : '7_1',
+                'cassettebook'            : '7_1',
+                'audio-cds-cnib'          : '42_2', 
+                'book'                    : '21_2',
+                'inter-library-loan'      : '21_2',
+                'dvd'                     : '7_1',
+                'videos'                  : '7_1',
+                'audio-cds'               : '7_1',
+                'cd-and-book-in-bag'      : '7_1',
+                'best-seller'             : '7_0'
+            };
+
+            return map[circMod] || '21_2'; 
+        },
+
+        getRecurringFine : function() {
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            var map = {
+                'juvenile-collection'    : 'twentycent',
+                'magazine'               : 'twentycent',
+                'hardback'               : 'twentycent',
+                'mass-market-paperbacks' : 'twentycent',
+                'compact-discs'          : 'twentycent',
+                'cassettebook'           : 'twentycent',
+                'audio-cds-cnib'         : 'staff',  //TODO: 'zero'?
+                'book'                   : 'twentycent',
+                'non-circulating'        : 'staff',  //TODO: 'zero'?
+                'inter-library-loan'     : 'twentycent',
+                'dvd'                    : 'twentycent',
+                'videos'                 : 'twentycent',
+                'audio-cds'              : 'twentycent',
+                'cd-and-book-in-bag'     : 'twentycent',
+                'best-seller'            : 'twentycent'
+            };
+
+            return map[circMod] || 'twentycent';
+        },
+
+        getMaxFine : function() {
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            var map = {
+                'juvenile-collection'    : 'default',
+                'magazine'               : 'default',
+                'hardback'               : 'default',
+                'mass-market-paperbacks' : 'default',
+                'compact-discs'          : 'default',
+                'cassettebook'           : 'default',
+                'audio-cds-cnib'         : 'staff',  //TODO: 'zero'?
+                'book'                   : 'default',
+                'non-circulating'        : 'staff',  //TODO: 'zero'?
+                'inter-library-loan'     : 'default',
+                'dvd'                    : 'default',
+                'videos'                 : 'default',
+                'audio-cds'              : 'default',
+                'cd-and-book-in-bag'     : 'default',
+                'best-seller'            : 'default'
+            };
+
+            return map[circMod] || 'default';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            log_debug('exceedsMaxCheckoutsByCircMod()');
+
+            if ( isGroupDescendant('Staff', patronProfile) ) {
+              return false; 
+            }
+
+            var circMod = (copy && copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+            
+            var mediaMax = 0;
+            var mediaCount = 0;
+
+            if (circMod == 'dvd' || circMod == 'videos') {
+              mediaMax = 3; 
+              mediaCount += parseInt(checkoutsByCircModifier(patron.id)['dvd']) || 0;
+              mediaCount += parseInt(checkoutsByCircModifier(patron.id)['videos']) || 0;
+              log_debug("found max out by circ mod "+circMod+" and checked out media total count is "+mediaCount);
+              return mediaCount >= mediaMax;
+            } else if (circMod == 'audio-cds' || circMod == 'cassettebook') {
+              mediaMax = 3; 
+              mediaCount += parseInt(checkoutsByCircModifier(patron.id)['audio-cds']) || 0;
+              mediaCount += parseInt(checkoutsByCircModifier(patron.id)['audio-cds-cnib']) || 0;
+              mediaCount += parseInt(checkoutsByCircModifier(patron.id)['cassettebook']) || 0;
+              log_debug("found max out by circ mod "+circMod+" and checked out media total count is "+mediaCount);
+              return mediaCount >= mediaMax;
+            } else if (circMod == 'compact-discs') {
+              mediaMax = 3; 
+              mediaCount += parseInt(checkoutsByCircModifier(patron.id)['compact-discs']) || 0;
+              return mediaCount >= mediaMax;
+            }
+
+            return false;
+        },
+
+        isAllowedCirc : function() {
+            return true;
+        },
+                
+
+        isAllowedHold : function() {
+            return true;
+        },
+
+        getGroupConfig : function() {
+
+            // set defaults
+            var maxHoldsValue           =  10;
+            var maxItemsOutValue        =  10;
+            var overdueThresholdValue   =  10;
+            var fineThresholdValue      =   5;
+            
+            // set special values for group
+            switch (patronProfile) {
+              case 'Board':
+              case 'Homebound':
+              case 'Volunteer':
+                fineThresholdValue = -1;
+                break;
+              case 'JuvenileRes':
+                maxItemsOutValue       =  5;
+                maxHoldsValue          =  5;
+                overdueThresholdValue  =  5;
+                break;
+              case 'BCOneCard':
+                maxItemsOutValue       =  5;
+                maxHoldsValue          =  0;
+                overdueThresholdValue  =  5;
+                break;
+              case 'Staff':
+                maxItemsOutValue       =  -1;
+                maxHoldsValue          =  -1;
+                overdueThresholdValue  =  -1;
+                fineThresholdValue     =  -1;
+                break;
+              default:
+                //do nothing
+            }
+
+            // return group config
+            var config = {
+              'maxHolds'          :  maxHoldsValue,
+              'maxItemsOut'       :  maxItemsOutValue,
+              'overdueThreshold'  :  overdueThresholdValue,
+              'fineThreshold'     :  fineThresholdValue
+            };
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BSE.js b/circ/config_BSE.js
new file mode 100644 (file)
index 0000000..3912398
--- /dev/null
@@ -0,0 +1,145 @@
+/** Policies for Sechelt **/
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BSE");
+
+    var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+    return {
+
+        getLoanDuration : function() {
+            if(patronProfile == 'InterLibraryLoan'){
+                return '42_2';
+            }
+            
+            var map = {
+                'book'                 :       '21_2',
+                'juvenile-collection'  :       '21_2',
+                'mass-market-paperbacks':      '21_2',
+                'dvd'                  :       '7_1',
+                'videos'               :       '7_1',
+                'cassettebooks'                :       '21_2',
+                'compact-disc'         :       '21_2',
+                'juvenile-video'       :       '7_1',
+                'kit'                  :       '21_2',
+                'magazine'             :       '7_1',
+                'juvenile-serial'      :       '7_1',
+                'new-books'            :       '14_1',
+                'talking-books'                :       '42_2',
+                'inter-library-loan'   :       '21_1',
+                'ill-no-renew'         :       '21_0'
+            };
+
+            return map[circMod] || '21_2';
+        },
+
+        getRecurringFine : function() {
+            if(patronProfile == 'InterLibraryLoan' ||
+                patronProfile == 'Board' ||
+                patronProfile == 'Volunteer'){
+                return 'staff';
+            }
+            
+            var map = {
+                'book'                 :       'default',
+                'juvenile-collection'  :       'tencents',
+                'mass-market-paperbacks':      'default',
+                'dvd'                  :       'default',
+                'videos'               :       'default',
+                'cassettebooks'                :       'default',
+                'compact-disc'         :       'default',
+                'juvenile-video'       :       'tencents',
+                'kit'                  :       'tencents',
+                'magazine'             :       'default',
+                'juvenile-serial'      :       'tencents',
+                'new-books'            :       'default',
+                'talking-books'                :       'staff',
+                'inter-library-loan'   :       'fiftycents',
+                'ill-no-renew'         :       'fiftycents'
+            };
+
+            return map[circMod] || 'default';
+        },
+
+        getMaxFine : function() {
+
+            var map = {
+                'book'                 :       'fivedollar',
+                'juvenile-collection'  :       'threedollar',
+                'mass-market-paperbacks':      'threedollar',
+                'dvd'                  :       'fivedollar',
+                'videos'               :       'fivedollar',
+                'cassettebooks'                :       'fivedollar',
+                'compact-disc'         :       'fivedollar',
+                'juvenile-video'       :       'threedollar',
+                'kit'                  :       'threedollar',
+                'magazine'             :       'threedollar',
+                'juvenile-serial'      :       'threedollar',
+                'new-books'            :       'fivedollar',
+                'talking-books'                :       'staff',
+                'inter-library-loan'   :       'hundreddollar',
+                'ill-no-renew'         :       'hundreddollar'
+            };
+
+
+            return map[circMod] || 'fivedollar';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+                return false;
+        },
+
+        isAllowedCirc : function() {
+            return true;
+        },
+                
+        isAllowedHold : function() {
+            var nontransitmap = {
+                'magazine'             :'1',
+                'dvd'                  :'1',
+                'juvenile-video'    :'1',
+                'juvenile-serial'   :'1',
+                'kit'                      :'1',
+                'new-books'                :'1',
+                       'talking-books'         :'1'
+                };
+             if((copy.circ_lib.id != holdPickupLib) && (nontransitmap[circMod])){
+                return 'false';
+            }
+
+            return true;
+        },
+
+        getGroupConfig : function() {
+
+            // set defaults
+            var maxHoldsValue           =  99;
+            var maxItemsOutValue        =  40;
+            var overdueThresholdValue   =  10;
+            var fineThresholdValue      =  5;
+            
+            // set special values for group
+            switch (patronProfile) {
+              case 'InterLibraryLoan':
+                fineThresholdValue = -1;
+                overdueThresholdValue  = 100;
+                maxItemsOutValue = 300;
+                break;
+              case 'Volunteer':
+                fineThresholdValue = -1;
+                break;
+             }
+            // return group config
+            var config = {
+              'maxHolds'          :  maxHoldsValue,
+              'maxItemsOut'       :  maxItemsOutValue,
+              'overdueThreshold'  :  overdueThresholdValue,
+              'fineThreshold'     :  fineThresholdValue
+            };
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BTE.js b/circ/config_BTE.js
new file mode 100644 (file)
index 0000000..83982b2
--- /dev/null
@@ -0,0 +1,120 @@
+/** Policies for BTE */
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BTE");
+
+    var maxByCircMod = {
+        'hardback' : 50,
+        'binder' : 10,
+        'box' : 5,
+        'audio-cassette' : 5,
+        'compact-disc' : 5,
+        'cd-rom' : 5,
+        'dvd' : 3,
+        'folder' : 25,
+        'floppy-disc' : 10,
+        'magazine' : 50,
+        'map' : 50,
+        'pattern' : 5,
+        'paperback' : 50,
+        'photocopy' : 10,
+        'pamphlet' : 50,
+        'record-(lp)' : 5,
+        'spiral-binding' : 50,
+        'stapled' : 5,
+        'video-cassette' : 6,
+        'mass-market-paperbacks' : 50,
+        'cd-and-book-in-bag' : 10,
+        'dvd-rom' : 5,
+        'e-book' : 5,
+        'mp-3-audio-disc' : 5,
+        'literacy-activity-bag' :  2,
+        'ill' : 10
+    };
+
+
+    return {
+
+        getLoanDuration : function() {
+            /* returns config.rule_circ_duration.name */
+            var circMod = (copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+            if(circMod == 'pamphlets'){
+                return '1day';
+            }
+            if(circMod.match(/-short/)){
+                return 'terrace_short';
+            }
+            return 'terrace';
+        },
+
+        getRecurringFine : function() {
+            /* returns config.rule_recuring_fine.name */
+            var circMod = (copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+            if(circMod == 'magazine') {
+                return 'tencents';
+            }
+            return 'terrace';
+        },
+
+        getMaxFine : function() {
+            /* returns config.rule_max_fine.name */
+            if(patronProfile == 'JuvenileRes'){
+                return 'default_low';
+            }
+            return 'default';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            log_debug("exceedsMaxCheckoutsByCircMod()");
+            if(isGroupDescendant('Staff', patronProfile)){
+                return false;
+            }
+            var circMod = (copy && copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+            var maxCount = maxByCircMod[circMod];
+            log_debug("checking circ mod " + circMod);
+            if(!maxCount || maxCount === null){ 
+                maxCount = maxByCircMod[circMod.replace(/-short$/,'')];
+            }
+            if(!maxCount || maxCount === null){
+                return false;
+            }
+            var outCount = checkoutsByCircModifier(patron.id)[circMod] || 0;
+            log_debug("found max out by circ mod "+maxCount+" and checked out count is "+outCount);
+            return outCount >= maxCount;
+        },
+        
+        isAllowedCirc : function() {
+            return true;
+        },
+
+        isAllowedHold : function() {
+            return true;
+        },
+
+        getGroupConfig : function() {
+            /* returns the combined user config object */
+
+            // override some defaults
+            GROUP_CONFIG.Patrons.fineThreshold = 25;
+            GROUP_CONFIG.JuvenileRes.fineThreshold = 10;
+
+            var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+            
+            // these are global settings for BTE users
+            config.maxHolds = 25;
+            config.overdueThreshold = 5;
+
+            // debugging...
+            var str = "BTE getGroupConfig():";
+               for( var i in config ){ 
+                       str += i + '=' + config[i] + '  ';
+               }
+            log_debug(str);
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BVALE.js b/circ/config_BVALE.js
new file mode 100644 (file)
index 0000000..47f68bd
--- /dev/null
@@ -0,0 +1,96 @@
+/** Policies for BNA**/
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info forBNA");
+
+    return {
+
+        getLoanDuration : function() {
+            if (copy.call_number == -1){
+                return '21_0';
+            }
+            /* returns config.rule_circ_duration.name */
+            var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+
+            if (isGroupDescendant('InterLibraryLoan', patronProfile)) {
+                return '35_1';
+            }
+            var map = {
+                'dvd'                     : 'video',
+                'cd-rom'                  : 'video',
+                'video'                  : 'video',
+                'magazine'                : 'video',
+                'compact-discs'           : 'video'
+            };
+
+            return map[circMod] || 'default';
+
+        },
+
+        getRecurringFine : function() {
+            /* returns config.rule_recuring_fine.name */
+           
+           var circMod = copy.circ_modifier ? copy.circ_modifier.toLowerCase() : '';
+          
+               if(patronProfile == 'JuvenileRes' && circMod == 'book'){
+                       return 'fivecents';
+               } 
+        if(patronProfile == 'Board' || patronProfile =='InterLibraryLoan'){
+            return 'zero';
+        }
+         var map = {
+               'dvd'   : 'fiftycents',
+               'video' : 'fiftycents',
+               'cd-rom' : 'fiftycents',
+               'compact-discs' : 'fiftycents'
+          };
+           return map[circMod] || 'tencents';
+        },
+
+        getMaxFine : function() {
+            /* returns config.rule_max_fine.name */
+            return 'video';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+            return false;
+        },
+
+        isAllowedCirc : function() {
+          return true;
+        },
+        isAllowedHold : function() {
+            return true;
+        },
+        getGroupConfig : function() {
+            /* returns the combined user config object */
+
+            var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+            
+            // these are global settings for BH users
+            config.maxHolds = -1;
+            config.overdueThreshold = -1;
+            config.maxItemsOut = 50;
+           config.fineThreshold = 2;
+            
+           // override some defaults
+           GROUP_CONFIG.BCOneCard.maxItemsOut = 5;
+           GROUP_CONFIG.Board.fineThreshold = -1;
+           GROUP_CONFIG.Staff.fineThreshold = -1;
+           GROUP_CONFIG.Volunteer.fineThreshold = -1;
+
+            // debugging...
+            var str = "BNA getGroupConfig():";
+               for( var i in config ){ 
+                       str += i + '=' + config[i] + '  ';
+               }
+            log_debug(str);
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/config_BVDH.js b/circ/config_BVDH.js
new file mode 100644 (file)
index 0000000..3813c45
--- /dev/null
@@ -0,0 +1,52 @@
+/** Policies for BVDH **/
+
+function getPolicy() {
+
+  load_lib('circ/circ_lib.js');
+  log_info("Loading policy info for BVDH");
+
+  return {
+
+    getLoanDuration : function() {
+      return 'default';
+    },
+
+    getRecurringFine : function() {
+      return 'fivecents';
+    },
+
+    getMaxFine : function() {
+      return 'default_low';
+    },
+
+    exceedsMaxCheckoutsByCircMod : function() {
+      return false;
+    },
+
+    isAllowedCirc : function() {
+      return true;
+    },
+
+    isAllowedHold : function() {
+        return true;
+    },
+
+    getGroupConfig : function() {
+      /* returns the combined user config object */
+
+      var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+      
+      // these are global settings for BVDH users
+      config.maxHolds          = 10;
+      config.overdueThreshold  = 10;
+      config.maxItemsOut       = 60;
+      config.fineThreshold     = 10;
+      
+      // override some defaults
+      GROUP_CONFIG.BCOneCard.maxItemsOut = 10;
+
+      return config;
+    }
+  };
+}
+
diff --git a/circ/config_BW.js b/circ/config_BW.js
new file mode 100644 (file)
index 0000000..fc68156
--- /dev/null
@@ -0,0 +1,108 @@
+/** Policies for BW */
+
+function getPolicy() {
+
+    load_lib('circ/circ_lib.js');
+    log_info("Loading policy info for BW");
+
+    var maxByCircMod = {
+           'video-games' : 2
+    };
+
+    return {
+
+        getLoanDuration : function() {
+            /* returns config.rule_circ_duration.name */
+            var circMod = (copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+
+            log_debug("Patron Profile: " + patronProfile);
+            if (isGroupDescendant('InterLibraryLoan', patronProfile)) {
+                return '42day';
+            }
+            if (copy.call_number == -1){
+                return '21_0';
+            }
+
+            var map = {
+                'dvd'                         :   '7day',
+                'holiday-title'              :   '7day',
+                'juvenile-holiday-special'   :   '7day',
+                'video-games'                :   '7day',
+                'videos'                     :   '7day'
+            };
+
+            return map[circMod] || 'default';
+        },
+
+        getRecurringFine : function() {
+            /* returns config.rule_recuring_fine.name */
+            var circMod = (copy && copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+            if (isGroupDescendant('InterLibraryLoan', patronProfile)) {
+                return 'staff';
+            }
+            if(circMod == 'videos' || circMod == 'video-games' || circMod == 'dvd'){
+                return 'video';
+            }
+            if(circMod.match(/juvenile-/)){
+                return 'staff'; /* no fines for kids */
+            }
+            return 'whistler';
+        },
+
+        getMaxFine : function() {
+            return 'default';
+        },
+
+        exceedsMaxCheckoutsByCircMod : function() {
+                   log_debug("exceedsMaxCheckoutsByCircMod()");
+               
+                   if(isGroupDescendant('Staff', patronProfile)){
+                           return false;
+            }
+
+                   var circMod = (copy && copy.circ_modifier) ? copy.circ_modifier.toLowerCase() : '';
+                   var maxCount = maxByCircMod[circMod];
+                   log_debug("checking circ mod " + circMod);
+                   if(!maxCount || maxCount === null){
+                           return false;
+            }
+                   var outCount = checkoutsByCircModifier(patron.id)[circMod] || 0;
+               
+               log_debug("found max out by circ mod "+maxCount+" and checked out count is "+outCount);
+               return outCount >= maxCount;
+           },
+
+    isAllowedCirc : function() {
+        return true;
+    },
+    isAllowedHold : function() {
+        return true;
+    },
+
+       getGroupConfig: function() {
+             /* XXX */
+
+            var config = findGroupConfig(patronProfile) || findGroupConfig('Patrons');
+
+            config.maxItemsOut = 20;
+            config.maxHolds = 10;
+            config.fineThreshold = 5;
+            if(isGroupDescendant('NonResident', patronProfile)){
+                config.maxItemsOut = 10;
+            }
+            if(isGroupDescendant('Staff', patronProfile)){
+                config.maxHolds = 50;
+            }
+            // debugging...
+            var str = "BW getGroupConfig():";
+               for( var i in config ){
+                       str += i + '=' + config[i] + '  ';
+               }
+            log_debug(str);
+
+            return config;
+        }
+    };
+}
+
diff --git a/circ/librarymap.js b/circ/librarymap.js
new file mode 100644 (file)
index 0000000..08cbdf4
--- /dev/null
@@ -0,0 +1,22 @@
+
+function getBranchPolicyMap(shortname) {
+            var map = {
+                'SITKA'     : 'BPR',
+                'BLP-GB'  :  'BLP',
+                'BLP-BR'  :  'BLP',
+                'BLP-LL'  :  'BLP',
+                'BCREK-CRA'   :  'BCREK',
+                'BCREK-CRE'   :  'BCREK',
+                'BCREK-FER'   :  'BCREK',
+                'BCREK-GCR'   :  'BCREK',
+                'BCREK-GOL'   :  'BCREK',
+                'BCREK-INV'   :  'BCREK',
+                'BCREK-KIM'   :  'BCREK',
+                'BCREK-SPA'   :  'BCREK',
+            };
+
+            return map[shortname] || shortname;
+
+
+}
+
diff --git a/penalty/patron_penalty.js b/penalty/patron_penalty.js
new file mode 100755 (executable)
index 0000000..07ed2ee
--- /dev/null
@@ -0,0 +1,31 @@
+function go() {
+
+/* load the lib script */
+load_lib('circ/circ_lib.js');
+load_lib('JSON_v1.js');
+log_vars('patron_penalty');
+
+var config = findGroupConfig(patronProfile);
+
+if( config ) {
+
+       /* check the fine limit */
+       if( config.fineThreshold >= 0 && patronFines >= config.fineThreshold ) 
+               result.fatalEvents.push('PATRON_EXCEEDS_FINES');
+
+       /* check the overdue limit */
+       if( config.overdueThreshold >= 0 && patronOverdueCount >= config.overdueThreshold )
+               result.fatalEvents.push('PATRON_EXCEEDS_OVERDUE_COUNT');
+
+} else {
+       log_warn("profile has no configured information: " + patronProfile);
+}
+
+
+
+
+
+
+} go();
+
+