├── LICENSE
├── testing
├── left-pad.js
├── test.html
├── readme.md
└── norm_test.html
├── stacks_data.js
├── README.md
├── ils_style_callnumber_normalization.md
├── unit_test1.html
├── locCallClass.js
└── sanity_test.html
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 rayvoelker
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/testing/left-pad.js:
--------------------------------------------------------------------------------
1 | /* This program is free software. It comes without any warranty, to
2 | * the extent permitted by applicable law. You can redistribute it
3 | * and/or modify it under the terms of the Do What The Fuck You Want
4 | * To Public License, Version 2, as published by Sam Hocevar. See
5 | * http://www.wtfpl.net/ for more details. */
6 | 'use strict';
7 | //module.exports = leftPad;
8 |
9 | var cache = [
10 | '',
11 | ' ',
12 | ' ',
13 | ' ',
14 | ' ',
15 | ' ',
16 | ' ',
17 | ' ',
18 | ' ',
19 | ' '
20 | ];
21 |
22 | function leftPad (str, len, ch) {
23 | // convert `str` to `string`
24 | str = str + '';
25 | // `len` is the `pad`'s length now
26 | len = len - str.length;
27 | // doesn't need to pad
28 | if (len <= 0) return str;
29 | // `ch` defaults to `' '`
30 | if (!ch && ch !== 0) ch = ' ';
31 | // convert `ch` to `string`
32 | ch = ch + '';
33 | // cache common use cases
34 | if (ch === ' ' && len < 10) return cache[len] + str;
35 | // `pad` starts with an empty string
36 | var pad = '';
37 | // loop
38 | while (true) {
39 | // add `ch` to `pad` if `len` is odd
40 | if (len & 1) pad += ch;
41 | // divide `len` by 2, ditch the remainder
42 | len >>= 1;
43 | // "double" the `ch` so this operation count grows logarithmically on `len`
44 | // each time `ch` is "doubled", the `len` would need to be "doubled" too
45 | // similar to finding a value in binary search tree, hence O(log(n))
46 | if (len) ch += ch;
47 | // `len` is 0, exit the loop
48 | else break;
49 | }
50 | // pad `str`!
51 | return pad + str;
52 | }
53 |
--------------------------------------------------------------------------------
/testing/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
55 |
56 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/stacks_data.js:
--------------------------------------------------------------------------------
1 | //this json data will be used in our app to search for call number locations
2 |
3 | var stacks_data = [
4 | {
5 | "location" : "",
6 | "floor" : 5,
7 | "row_num" : 1,
8 | "lc_from" : "H 1 .E77 v.1 1976",
9 | "lc_to" : "HA202 .K87 1994",
10 | "img_top" : 845,
11 | "img_left" : 120
12 | },
13 | {
14 | "location" : "",
15 | "floor" : 5,
16 | "row_num" : 2,
17 | "lc_from" : "HA 203 .A218 no.54",
18 | "lc_to" : "HB 501 .M392",
19 | "img_top" : 820,
20 | "img_left" : 120
21 | },
22 | {
23 | "location" : "",
24 | "floor" : 5,
25 | "row_num" : 3,
26 | "lc_from" : "HB 501 .M5 A76 1990",
27 | "lc_to" : "HC 240 .N67",
28 | "img_top" : 0,
29 | "img_left" : 0
30 | },
31 | {
32 | "location" : "",
33 | "floor" : 5,
34 | "row_num" : 4,
35 | "lc_from" : "HC 240 .O4 1917",
36 | "lc_to" : "HD 55 .B7",
37 | "img_top" : 0,
38 | "img_left" : 0
39 | },
40 | {
41 | "location" : "",
42 | "floor" : 5,
43 | "row_num" : 5,
44 | "lc_from" : "HD 55 .B89",
45 | "lc_to" : "HD 4965.5 .U6 P3",
46 | "img_top" : 0,
47 | "img_left" : 0
48 | },
49 | {
50 | "location" : "",
51 | "floor" : 5,
52 | "row_num" : 6,
53 | "lc_from" : "HD4965.5.U6 P42",
54 | "lc_to" : "HD 9665.5 .P4",
55 | "img_top" : 0,
56 | "img_left" : 0
57 | },
58 | {
59 | "location" : "",
60 | "floor" : 5,
61 | "row_num" : 7,
62 | "lc_from" : "HD 9665.5 .P72 1983",
63 | "lc_to" : "HF 5353 .M829",
64 | "img_top" : 0,
65 | "img_left" : 0
66 | },
67 | {
68 | "location" : "",
69 | "floor" : 5,
70 | "row_num" : 8,
71 | "lc_from" : "HF 5353 .N3",
72 | "lc_to" : "HF 5548.2 .R6298",
73 | "img_top" : 0,
74 | "img_left" : 0
75 | },
76 | {
77 | "location" : "",
78 | "floor" : 5,
79 | "row_num" : 9,
80 | "lc_from" : "HF 5548.2 .R63",
81 | "lc_to" : "HF 5686 .P24 W44",
82 | "img_top" : 0,
83 | "img_left" : 0
84 | },
85 | {
86 | "location" : "",
87 | "floor" : 5,
88 | "row_num" : 10,
89 | "lc_from" : "HF 5686 .P3 B87",
90 | "lc_to" : "HG 4811 .A3 J35 1970",
91 | "img_top" : 0,
92 | "img_left" : 0
93 | },
94 | ];
95 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | js-loc-callnumbers
2 | ===
3 |
4 | A JavaScript class to normalize and perform various sorting options on Library of Congress Call Numbers within a library institution.
5 |
6 | My main intended use for this class is to provide sorting and comparison functions for library catalog searches in relationship to the physical location of the material in the library stacks -- although, the other various functions may be useful in other projects.
7 |
8 | This is adapted from the efforts of various other developers and projects; including, but not necessarily limited to the following :
9 |
10 | [http://robotlibrarian.billdueber.com](http://robotlibrarian.billdueber.com/2008/11/normalizing-loc-call-numbers-for-sorting/)
11 |
12 | [http://www-personal.umich.edu/~dfulmer](http://www-personal.umich.edu/~dfulmer/api/lc.html)
13 |
14 | [https://code.google.com/p/library-callnumber-lc](https://code.google.com/p/library-callnumber-lc/wiki/Home)
15 |
16 | Unfortunately, the regular expression used in this project may have very distinct limitations in your particular institution; so please let me know if anyone out there has a more complete regular expression (or a more reliable way to parse and "normalize") that defines any and all perfectly valid Library of Congress Call Numbers.
17 |
18 | TODO:
19 | ===
20 | 1. Think about extending the class to a class that maintains "stacks" or "ranges" of call numbers for the purpose of finding items among the those ranges of call numbers. It could be instantiated with either a 1D or 2D array of call numbers in start / end pairs, or with a JSON object that defines the range data (the JSON object being a more easy to maintain solution for the user / system producing the data).
21 | 1. Add a method, or modify the sort method to also return the previous position of each of the sorted items.
22 | Useful situtations for this might inclued inserting a single, or group of call numbers into a pre-sorted array, sorting the array, and then tracking where those items ended up in relationship to the orginal list.
23 | 1. Add a "reshelve" method to make it simple to read a list, and see if a call number is out of position in relationship to the previos and next call numbers in the list. This method may or may not be outside of the scope of this class, but still could be very useful for implementing a more "on-the-fly" or, near-real-time shelving application.
24 |
--------------------------------------------------------------------------------
/ils_style_callnumber_normalization.md:
--------------------------------------------------------------------------------
1 | ILS style call number normalization
2 |
3 | 1. alphabetic characters are set to lowercase
4 | 1. remove anything that is considered a "pre-stamp" from the callnumber
5 | 1. identify the "beginning" of the call number
6 | 1. search for 1 to 3 alphabetic characters (letter portion)
7 | followed by 1 to 4 numeric characters (the number portion).
8 | 1. If there is a decimal after the 1 to 4 numeric
9 | characters (followed by more numeric characters) then pull
10 | those values in as part of the number portion
11 | 1. using the above description, we now use this data to
12 | construct the "beginning" of our call number.
13 | 1. using seven character positions ( 1 2 3 4 5 6 7 ) place the
14 | letter portion into positions 1 through 3, and then the number
15 | portion into positions 4 through 7, right justifying, leaving
16 | spaces in the unoccupied positions. For example, given the call
17 | number "QL697.4 .H69 2010", we would identify the "beginning"
18 | as "QL697.4", and fill out our seven character positions in the
19 | following way:
20 | ```
21 | 1 2 3 4 5 6 7
22 | q l 6 9 7 . 4
23 | ```
24 |
25 | (note, that we included the ".4" after position 7, as it's
26 | still part of the number portion)
27 |
28 | so, the normalized "beginning" of the call number would look
29 | like the following:
30 | ql 697.4
31 |
32 | *regex for capturing this "beginning" portion* (note that this
33 | should return 1 match per valid LC call number, and have 4
34 | possible groups 1) letter portion, 2) number portion, 3)
35 | possible decimal portion of the number, and 4) the rest of the
36 | call number
37 |
38 | ```
39 | /([A-Z]{1,3})\s*(\d{1,4})(\.\d+)*(.+)*\ig
40 | ```
41 | 1. after this beginning portion, the rest of the number is further
42 | normalized
43 | 1. convert any punctuation to spaces
44 |
45 | 1. remove instances of multiple spaces, leaving only one
46 |
47 | 1. *normalize volume data in the call number in the following way:
48 | 1. identify volume characters ("v." and "no")
49 | and then place numbers following the volume characters into a
50 | five character positions, right justifying. For example:
51 | vol 151
52 | normalizes to ..
53 | ```
54 | 1 2 3 4 5
55 | vol 1 5 1
56 | or ...
57 | vol 151
58 | ```
59 |
60 | Finishing up with our example, our call number ("QL697.4 .H69
61 | 2010") would final, normalized call number would end up looking
62 | like the following:
63 | ```
64 | QL697.4 .H69 2010
65 | ql 697.4 h69 2010
66 | ```
67 |
--------------------------------------------------------------------------------
/unit_test1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
18 |
19 |
20 |
21 |
22 |
testing
23 |
24 | issues
25 |
26 |
27 | 411, 412
28 | *breaks normalization rules
29 |
30 |
31 | 342, 344
32 | *portion of pre-stamp incorrectly pulled into call number
33 |
34 |
35 |
36 | 22, 533
37 | *numbers+letter groupings should be seperated by spaces?
38 |
39 |
40 |
41 |
42 | 28, 40, 47, 70, 9974
43 | *letters+number groups should be seperated by spaces?
44 |
45 |
46 |
47 |
48 | 34
49 | *remove trailing spaces?
50 |
51 |
52 |
53 |
54 | 48
55 | *if only the prestamp remains, return only that?
56 |
57 |
58 |
59 |
60 | 79
61 | no space between "beginning" of call number portion and the rest.
62 |
63 |
64 |
65 |
66 | 540
67 | no. normalization is failing?
68 |
69 |
70 |
71 |
72 |
non-matching call number normalizations
73 |
74 |
75 |
76 |
77 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/testing/readme.md:
--------------------------------------------------------------------------------
1 | ILS style call number normalization
2 | ===
3 |
4 | Purpose
5 | ---
6 | This method should create normalized forms of library of congress call numbers that are efficiently stored (in a database, spreadsheet, flat file, etc.), as well as constantly identify and parse call numbers into their normalized forms.
7 |
8 | Method Description
9 | ---
10 | 1. alphabetic characters are set to lowercase
11 | 1. remove anything that is considered a "pre-stamp" from the callnumber
12 | 1. identify the "beginning" of the call number
13 | 1. search for 1 to 3 alphabetic characters (letter portion)
14 | followed by 1 to 4 numeric characters (the number portion).
15 | 1. If there is a decimal after the 1 to 4 numeric
16 | characters (followed by more numeric characters) then pull
17 | those values in as part of the number portion
18 | 1. using the above description, we now use this data to
19 | construct the "beginning" of our call number.
20 | 1. using seven character positions ( 1 2 3 4 5 6 7 ) place the
21 | letter portion into positions 1 through 3, and then the number
22 | portion into positions 4 through 7, right justifying, leaving
23 | spaces in the unoccupied positions. For example, given the call
24 | number "QL697.4 .H69 2010", we would identify the "beginning"
25 | as "QL697.4", and fill out our seven character positions in the
26 | following way:
27 | ```
28 | 1 2 3 4 5 6 7
29 | q l 6 9 7 . 4
30 | ```
31 |
32 | (note, that we included the ".4" after position 7, as it's
33 | still part of the number portion)
34 |
35 | so, the normalized "beginning" of the call number would look
36 | like the following:
37 | ```
38 | ql 697.4
39 | ```
40 |
41 | **regex for capturing this "beginning" portion** (note that this
42 | should return 1 match per valid LC call number, and have 4
43 | possible groups 1) letter portion, 2) number portion, 3)
44 | possible decimal portion of the number, and 4) the rest of the
45 | call number
46 |
47 | ```
48 | /([A-Z]{1,3})\s*(\d{1,4})(\.\d+)*(.+)*\ig
49 | ```
50 | 1. after this beginning portion, the rest of the number is further
51 | normalized
52 | 1. convert any punctuation to spaces
53 |
54 | 1. remove instances of multiple spaces, leaving only one
55 |
56 | 1. *think about maybe normalizing volume data here as well in the
57 | following way:
58 | 1. identify volume characters ("vol", "v.", "no", "n.", etc)
59 | and then place numbers following the volume characters into a
60 | five character positions, right justifying. For example:
61 | vol 151
62 | normalizes to ..
63 | ```
64 | 1 2 3 4 5
65 | vol 1 5 1
66 | ```
67 | or ...
68 |
69 | ```
70 | vol 151
71 | ```
72 |
73 | Finishing up with our example, our call number ("QL697.4 .H69
74 | 2010") would final, normalized call number would end up looking
75 | like the following:
76 | ```
77 | QL697.4 .H69 2010
78 | ql 697.4 h69 2010
79 | ```
80 |
81 |
--------------------------------------------------------------------------------
/locCallClass.js:
--------------------------------------------------------------------------------
1 | // js-loc-callnumbers
2 | // A javascript class to normalize and perform various sorting options on
3 | // Library of Congress Call Numbers within a library institution.
4 |
5 | // constructor
6 | function locCallClass() {
7 | //define the regular expressions used in the normalization
8 | this.lc = /([A-Z]{1,3})\s*(\d{1,4})(\.\d+)*(.+)*/ig;
9 | this.punctuation = /[.,\/#!$%\^&\*;:{}=\-_`~()]/ig;
10 | this.lett_num_group = /([A-Z]{1,}\d{1,})/ig;
11 | this.num_letter_groupings = /(\d{1,})([A-Z]{1,})/ig;
12 | this.v_dot = /(v\s)(\d{1,})/ig;
13 | this.no_dot = /(no\s)(\d{1,})/ig;
14 |
15 | //define and cache the padding lengths (max pad length is 9)
16 | this.cache = ['', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '];
17 |
18 | // alias the function name for returnNormLcCall
19 | this.normalize = this.returnNormLcCall;
20 | }
21 |
22 |
23 | // locCallClass.returnNormLcCall(call_number)
24 | // returns a "normalized" call number
25 | locCallClass.prototype.returnNormLcCall = function(callnumber_string) {
26 | // this is our eventual return value
27 | var local_norm = '',
28 | test = [];
29 |
30 | //~ TODO
31 | //~ get cataloging to fix issues with non-normalizing call numbers
32 | //~ so we don't have to use this hack.
33 | //~ Call numbers like this "KBG .A1" should normalize to "kbg 0 a2"
34 | try{
35 | const exception = /(KBG)(\s*\.)(.+)*/i;
36 | test = exception.exec(callnumber_string);
37 | if (test != null) {
38 | //debugger;
39 | var new_callnumber_string = "";
40 | if( typeof test[1] !== "undefined" ) new_callnumber_string += test[1] + "0";
41 | if( typeof test[2] !== "undefined" ) new_callnumber_string += test[2];
42 | if( typeof test[3] !== "undefined" ) new_callnumber_string += test[3];
43 | test = [];
44 | return this.returnNormLcCall(new_callnumber_string);
45 | }
46 |
47 | }
48 | catch (e){
49 | // console.log('undefined call number ' + e);
50 | }
51 | //~ /TODO
52 |
53 | try{
54 | test = this.lc.exec(callnumber_string.toLowerCase());
55 | }
56 | catch (e){
57 | console.log('undefined call number ' + e);
58 | }
59 |
60 | // if input is not LC, return lower case, trimmed input string,
61 | // with certain characters removed
62 | if (test === null){
63 | console.log("\"" + callnumber_string + "\"" + " not lc");
64 | return callnumber_string
65 | .toLowerCase()
66 | .trim()
67 | .replace(/\/{1,}|-{1,}/gi, " "); //replaces "/" and "-" with spaces
68 | }
69 |
70 | // TODO :
71 | // remove try block?
72 | try {
73 | if(typeof test[1] !== "undefined"){
74 | local_norm = test[1];
75 | }
76 |
77 | local_norm += this.leftPad(test[2],7-test[1].length);
78 |
79 | // append the decimal, if there is one
80 | if(typeof test[3] !== "undefined"){
81 | local_norm += test[3];
82 | }
83 |
84 | // remove any leading or trailing whitespace
85 | local_norm = local_norm.trim();
86 |
87 | // normalize the rest of the call number
88 | var call_number_remainder = "";
89 | if (typeof test[4] !== 'undefined'){
90 | // step 4. i. convert any punctuation to spaces
91 | // append letter+number groups with spaces
92 | // step 4. remove instances of multiple spaces, leaving only one
93 | // remove any trailing (or starting) whitespace
94 | call_number_remainder += test[4]
95 | .replace(this.punctuation, " ") //repalce punctuation with spaces
96 | .replace(this.lett_num_group, "$1 ") //append spaces to letter+number groups
97 | .replace(this.num_letter_groupings, "$1 $2") //place space between numbers and letters occuring next to eachother
98 | .replace(/\s{2,}/g," "); //instances of 2 or more consecutive spaces are replaced by one
99 |
100 |
101 | // TODO :
102 | // consider removing the lastIndex for the following?
103 |
104 | // pad out numbers occuring after "v." and "no."
105 | // note: this calls the helper function for replace "vol_pad()"
106 | call_number_remainder = call_number_remainder.replace(this.v_dot, this.vol_pad.bind(this));
107 | this.v_dot.lastIndex = 0;
108 |
109 | call_number_remainder = call_number_remainder.replace(this.no_dot, this.vol_pad.bind(this));
110 | this.no_dot.lastIndex = 0;
111 |
112 | // reset the lastIndex so the next regex exec doesn't fail on next try
113 | this.punctuation.lastIndex = 0;
114 |
115 | }
116 |
117 | // add a single space to the front of the call_number_remainder
118 | call_number_remainder = call_number_remainder.trim();
119 | call_number_remainder = " " + call_number_remainder;
120 |
121 | //append the begining of the callnumber to the remainder of the call number
122 | local_norm += call_number_remainder;
123 |
124 | //trim spaces from the end, or the begining of the string
125 | local_norm = local_norm.trim();
126 |
127 | } //end try
128 |
129 | catch (e){
130 | console.log(' no test ');
131 | }
132 |
133 | // reset the lastIndex so the next regex exec doesn't fail on next try
134 | this.lc.lastIndex = 0;
135 |
136 | return local_norm;
137 |
138 |
139 | } //end returnNormLcCall
140 |
141 |
142 | // locCallClass.localeCompare(b,a)
143 | // replicates functionality of the normal compare function
144 | // so that it may be used in external sorting operations:
145 | //
146 | // A negative number if the reference string (a) occurs before the
147 | // given string (b);
148 | // positive if the reference string (a) occurs after
149 | // the compare string (b);
150 | // 0 if they are equivalent.
151 | locCallClass.prototype.localeCompare = function (a, b) {
152 | try {
153 | var a_norm = this.returnNormLcCall(a),
154 | b_norm = this.returnNormLcCall(b);
155 |
156 | return ( a_norm < b_norm ? -1 : (a_norm > b_norm ? 1 : 0) );
157 | }
158 | catch (err) {
159 | // console.log("error")
160 | }
161 | }
162 |
163 | // locCallClass.sortCallNumbers()
164 | // takes an array of call numbers and returns a sorted array of call
165 | // numbers in their original format.
166 | // Using something like the following works to sort as well:
167 | // var loc = new locCallClass();
168 | // var sorted_array = loc.unsorted_callnumber_array.sort(function(a,b) {return loc.localeCompare(a,b)});
169 | locCallClass.prototype.sortCallNumbers = function (callnumbers) {
170 | // also bind the scope of this to the sort function to be able to call
171 | // this.localeCompare
172 | var sorted = callnumbers.sort(function (a,b) {
173 | return this.localeCompare(a,b);
174 | }.bind(this));
175 |
176 | return sorted;
177 | }
178 |
179 | // locCallClass.isBetween(a,b,c)
180 | // returns true if a <= c <= b
181 | locCallClass.prototype.isBetween = function (a,b,c) {
182 | //this.localeCompare(a, b) <= 0 if in sort order
183 | return ( (this.localeCompare(a,c) <= 0 && this.localeCompare(c,b) <=0) ? true : false );
184 | }
185 |
186 | // pad the string
187 | locCallClass.prototype.leftPad = function (string, pad_length) {
188 | // make sure that we're treating the string like a string
189 | string = string + '';
190 | pad_length = pad_length - string.length;
191 | // nothing to pad
192 | if (pad_length <= 0) {
193 | return string;
194 | }
195 |
196 | return this.cache[pad_length] + string;
197 | } // end leftPad
198 |
199 | //helper function for volume padding
200 | locCallClass.prototype.vol_pad = function (match, vol_string, num_string, offset, string) {
201 | // padding out number portion to 5 places
202 | return vol_string.trim() + this.leftPad(num_string, 5);
203 | }
204 |
--------------------------------------------------------------------------------
/testing/norm_test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
163 |
164 |
165 |
175 |
176 |
177 |
178 |
179 |
testing
180 |
181 | issues
182 |
183 |
184 | 411, 412
185 | *breaks normalization rules
186 |
187 |
188 | 342, 344
189 | *portion of pre-stamp incorrectly pulled into call number
190 |
191 |
192 |
193 | 22, 533
194 | *numbers+letter groupings should be seperated by spaces?
195 |
196 |
197 |
198 |
199 | 28, 40, 47, 70, 9974
200 | *letters+number groups should be seperated by spaces?
201 |
202 |
203 |
204 |
205 | 34
206 | *remove trailing spaces?
207 |
208 |
209 |
210 |
211 | 48
212 | *if only the prestamp remains, return only that?
213 |
214 |
215 |
216 |
217 | 79
218 | no space between "beginning" of call number portion and the rest.
219 |
220 |
221 |
222 |
223 | 540
224 | no. normalization is failing?
225 |
226 |
227 |
228 |
229 |
23 | "Sanity Check" order of pre-sorted call numbers against this scripts normalization function:
24 | one call number per line (script assumes "range start" on odd lines, "range end" on even lines)
25 |