b5d9c1812b6082cc8ab41d1c005d3d56fb97ffe5
[bookreader.git] / BookReaderIA / datanode / BookReaderJSIA.php
1 <?
2 /*
3 Copyright(c)2008 Internet Archive. Software license AGPL version 3.
4
5 This file is part of BookReader.
6
7     BookReader is free software: you can redistribute it and/or modify
8     it under the terms of the GNU Affero General Public License as published by
9     the Free Software Foundation, either version 3 of the License, or
10     (at your option) any later version.
11
12     BookReader is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU Affero General Public License for more details.
16
17     You should have received a copy of the GNU Affero General Public License
18     along with BookReader.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 header('Content-Type: application/javascript');
22
23 $id = $_REQUEST['id'];
24 $itemPath = $_REQUEST['itemPath'];
25 $subPrefix = $_REQUEST['subPrefix'];
26 $server = $_REQUEST['server'];
27
28 // $$$mang this code has been refactored into BookReaderMeta.inc.php for use e.g. by
29 //         BookReaderPreview.php and BookReaderImages.php.  The code below should be
30 //         taken out and replaced by calls into BookReaderMeta
31
32 // Check if we're on a dev vhost and point to JSIA in the user's public_html on the datanode
33
34 // $$$ TODO consolidate this logic
35 if (strpos($_SERVER["REQUEST_URI"], "/~mang") === 0) { // Serving out of home dir
36     $server .= ':80/~mang';
37 } else if (strpos($_SERVER["REQUEST_URI"], "/~rkumar") === 0) { // Serving out of home dir
38     $server .= ':80/~rkumar';
39 } else if (strpos($_SERVER["REQUEST_URI"], "/~testflip") === 0) { // Serving out of home dir
40     $server .= ':80/~testflip';
41 }
42
43 if (! $subPrefix) {
44     $subPrefix = $id;
45 }
46 $subItemPath = $itemPath . '/' . $subPrefix;
47
48 if ("" == $id) {
49     BRFatal("No identifier specified!");
50 }
51
52 if ("" == $itemPath) {
53     BRFatal("No itemPath specified!");
54 }
55
56 if ("" == $server) {
57     BRFatal("No server specified!");
58 }
59
60 if (!preg_match("|^/\d+/items/{$id}$|", $itemPath)) {
61     BRFatal("Bad id!");
62 }
63
64 // XXX check here that subitem is okay
65
66 $filesDataFile = "$itemPath/${id}_files.xml";
67
68 if (file_exists($filesDataFile)) {
69     $filesData = simplexml_load_file("$itemPath/${id}_files.xml");
70 } else {
71     BRfatal("File metadata not found!");
72 }
73
74 $imageStackInfo = findImageStack($subPrefix, $filesData);
75 if ($imageStackInfo['imageFormat'] == 'unknown') {
76     BRfatal('Couldn\'t find image stack');
77 }
78
79 $imageFormat = $imageStackInfo['imageFormat'];
80 $archiveFormat = $imageStackInfo['archiveFormat'];
81 $imageStackFile = $itemPath . "/" . $imageStackInfo['imageStackFile'];
82
83 if ("unknown" == $imageFormat) {
84   BRfatal("Unknown image format");
85 }
86
87 if ("unknown" == $archiveFormat) {
88   BRfatal("Unknown archive format");
89 }
90
91
92 $scanDataFile = "${subItemPath}_scandata.xml";
93 $scanDataZip  = "$itemPath/scandata.zip";
94 if (file_exists($scanDataFile)) {
95     $scanData = simplexml_load_file($scanDataFile);
96 } else if (file_exists($scanDataZip)) {
97     $cmd  = 'unzip -p ' . escapeshellarg($scanDataZip) . ' scandata.xml';
98     exec($cmd, $output, $retval);
99     if ($retval != 0) BRFatal("Could not unzip ScanData!");
100     
101     $dump = join("\n", $output);
102     $scanData = simplexml_load_string($dump);
103 } else if (file_exists("$itemPath/scandata.xml")) {
104     // For e.g. Scribe v.0 books!
105     $scanData = simplexml_load_file("$itemPath/scandata.xml");
106 } else {
107     BRFatal("ScanData file not found!");
108 }
109
110 $metaDataFile = "$itemPath/{$id}_meta.xml";
111 if (!file_exists($metaDataFile)) {
112     BRFatal("MetaData file not found!");
113 }
114
115
116 $metaData = simplexml_load_file($metaDataFile);
117
118 //$firstLeaf = $scanData->pageData->page[0]['leafNum'];
119 ?>
120
121 // Error reporting - this helps us fix errors quickly
122 function logError(description,page,line) {
123     if (typeof(archive_analytics) != 'undefined') {
124         var values = {
125             'bookreader': 'error',
126             'description': description,
127             'page': page,
128             'line': line,
129             'itemid': '<?echo $id;?>',
130             'subPrefix': '<?echo $subPrefix;?>',
131             'server': '<?echo $server;?>',
132             'bookPath': '<?echo $subItemPath;?>'
133         };
134
135         // if no referrer set '-' as referrer
136         if (document.referrer == '') {
137             values['referrer'] = '-';
138         } else {
139             values['referrer'] = document.referrer;
140         }
141         
142         if (typeof(br) != 'undefined') {
143             values['itemid'] = br.bookId;
144             values['subPrefix'] = br.subPrefix;
145             values['server'] = br.server;
146             values['bookPath'] = br.bookPath;
147         }
148         
149         var qs = archive_analytics.format_bug(values);
150
151         var error_img = new Image(100,25);
152         error_img.src = archive_analytics.img_src + "?" + qs;
153     }
154
155     return false; // allow browser error handling so user sees there was a problem
156 }
157 window.onerror=logError;
158
159 br = new BookReader();
160
161 <?
162 /* Output title leaf if marked */
163 $titleLeaf = '';
164 foreach ($scanData->pageData->page as $page) {
165     if (("Title Page" == $page->pageType) || ("Title" == $page->pageType)) {
166         $titleLeaf = "{$page['leafNum']}";
167         break;
168     }
169 }
170     
171 if ('' != $titleLeaf) {
172     printf("br.titleLeaf = %d;\n", $titleLeaf);
173 }
174 ?>
175
176 br.getPageWidth = function(index) {
177     return this.pageW[index];
178 }
179
180 br.getPageHeight = function(index) {
181     return this.pageH[index];
182 }
183
184 // Returns true if page image is available rotated
185 br.canRotatePage = function(index) {
186     return 'jp2' == this.imageFormat; // Assume single format for now
187 }
188
189 // reduce defaults to 1 (no reduction)
190 // rotate defaults to 0 (no rotation)
191 br.getPageURI = function(index, reduce, rotate) {
192     var _reduce;
193     var _rotate;
194
195     if ('undefined' == typeof(reduce)) {
196         _reduce = 1;
197     } else {
198         _reduce = reduce;
199     }
200     if ('undefined' == typeof(rotate)) {
201         _rotate = 0;
202     } else {
203         _rotate = rotate;
204     }
205     
206     var file = this._getPageFile(index);
207         
208     // $$$ add more image stack formats here
209     return 'http://'+this.server+'/BookReader/BookReaderImages.php?zip='+this.zip+'&file='+file+'&scale='+_reduce+'&rotate='+_rotate;
210 }
211
212 br._getPageFile = function(index) {
213     var leafStr = '0000';
214     var imgStr = this.leafMap[index].toString();
215     var re = new RegExp("0{"+imgStr.length+"}$");
216     
217     var insideZipPrefix = this.subPrefix.match('[^/]+$');
218     var file = insideZipPrefix + '_' + this.imageFormat + '/' + insideZipPrefix + '_' + leafStr.replace(re, imgStr) + '.' + this.imageFormat;
219     
220     return file;
221 }
222
223 br.getPageSide = function(index) {
224     //assume the book starts with a cover (right-hand leaf)
225     //we should really get handside from scandata.xml
226     
227     <? // Use special function if we should infer the page sides based off the title page index
228     if (preg_match('/goog$/', $id) && ('' != $titleLeaf)) {
229     ?>
230     // assume page side based on title pagex
231     var titleIndex = br.leafNumToIndex(br.titleLeaf);
232     // assume title page is RHS
233     var delta = titleIndex - index;
234     if (0 == (delta & 0x1)) {
235         // even delta
236         return 'R';
237     } else {
238         return 'L';
239     }
240     <?
241     }
242     ?>
243     
244     // $$$ we should get this from scandata instead of assuming the accessible
245     //     leafs are contiguous
246     if ('rl' != this.pageProgression) {
247         // If pageProgression is not set RTL we assume it is LTR
248         if (0 == (index & 0x1)) {
249             // Even-numbered page
250             return 'R';
251         } else {
252             // Odd-numbered page
253             return 'L';
254         }
255     } else {
256         // RTL
257         if (0 == (index & 0x1)) {
258             return 'L';
259         } else {
260             return 'R';
261         }
262     }
263 }
264
265 br.getPageNum = function(index) {
266     var pageNum = this.pageNums[index];
267     if (pageNum) {
268         return pageNum;
269     } else {
270         return 'n' + index;
271     }
272 }
273
274 // Single images in the Internet Archive scandata.xml metadata are (somewhat incorrectly)
275 // given a "leaf" number.  Some of these images from the scanning process should not
276 // be displayed in the BookReader (for example colour calibration cards).  Since some
277 // of the scanned images will not be displayed in the BookReader (those marked with
278 // addToAccessFormats false in the scandata.xml) leaf numbers and BookReader page
279 // indexes are generally not the same.  This function returns the BookReader page
280 // index given a scanned leaf number.
281 //
282 // This function is used, for example, to map between search results (that use the
283 // leaf numbers) and the displayed pages in the BookReader.
284 br.leafNumToIndex = function(leafNum) {
285     for (var index = 0; index < this.leafMap.length; index++) {
286         if (this.leafMap[index] == leafNum) {
287             return index;
288         }
289     }
290     
291     return null;
292 }
293
294 // This function returns the left and right indices for the user-visible
295 // spread that contains the given index.  The return values may be
296 // null if there is no facing page or the index is invalid.
297 br.getSpreadIndices = function(pindex) {
298     // $$$ we could make a separate function for the RTL case and
299     //      only bind it if necessary instead of always checking
300     // $$$ we currently assume there are no gaps
301     
302     var spreadIndices = [null, null]; 
303     if ('rl' == this.pageProgression) {
304         // Right to Left
305         if (this.getPageSide(pindex) == 'R') {
306             spreadIndices[1] = pindex;
307             spreadIndices[0] = pindex + 1;
308         } else {
309             // Given index was LHS
310             spreadIndices[0] = pindex;
311             spreadIndices[1] = pindex - 1;
312         }
313     } else {
314         // Left to right
315         if (this.getPageSide(pindex) == 'L') {
316             spreadIndices[0] = pindex;
317             spreadIndices[1] = pindex + 1;
318         } else {
319             // Given index was RHS
320             spreadIndices[1] = pindex;
321             spreadIndices[0] = pindex - 1;
322         }
323     }
324     
325     //console.log("   index %d mapped to spread %d,%d", pindex, spreadIndices[0], spreadIndices[1]);
326     
327     return spreadIndices;
328 }
329
330 // Remove the page number assertions for all but the highest index page with
331 // a given assertion.  Ensures there is only a single page "{pagenum}"
332 // e.g. the last page asserted as page 5 retains that assertion.
333 br.uniquifyPageNums = function() {
334     var seen = {};
335     
336     for (var i = br.pageNums.length - 1; i--; i >= 0) {
337         var pageNum = br.pageNums[i];
338         if ( !seen[pageNum] ) {
339             seen[pageNum] = true;
340         } else {
341             br.pageNums[i] = null;
342         }
343     }
344
345 }
346
347 br.cleanupMetadata = function() {
348     br.uniquifyPageNums();
349 }
350
351 // getEmbedURL
352 //________
353 // Returns a URL for an embedded version of the current book
354 br.getEmbedURL = function(viewParams) {
355     // We could generate a URL hash fragment here but for now we just leave at defaults
356     var url = 'http://' + window.location.host + '/stream/'+this.bookId;
357     if (this.subPrefix != this.bookId) { // Only include if needed
358         url += '/' + this.subPrefix;
359     }
360     url += '?ui=embed';
361     if (typeof(viewParams) != 'undefined') {
362         url += '#' + this.fragmentFromParams(viewParams);
363     }
364     return url;
365 }
366
367 // getEmbedCode
368 //________
369 // Returns the embed code HTML fragment suitable for copy and paste
370 br.getEmbedCode = function(frameWidth, frameHeight, viewParams) {
371     return "<iframe src='" + this.getEmbedURL(viewParams) + "' width='" + frameWidth + "' height='" + frameHeight + "' frameborder='0' ></iframe>";
372 }
373
374 // getOpenLibraryRecord
375 br.getOpenLibraryRecord = function(callback) {
376     // Try looking up by ocaid first, then by source_record
377     
378     var jsonURL = this.olHost + '/query.json?type=/type/edition&*=&ocaid=' + br.bookId;
379     $.ajax({
380         url: jsonURL,
381         success: function(data) {
382             if (data && data.length > 0) {
383                 callback(br, data[0]);
384             } else {
385                 // try sourceid
386                 jsonURL = this.olHost + '/query.json?type=/type/edition&*=&source_records=ia:' + br.bookId;
387                 $.ajax({
388                     url: jsonURL,
389                     success: function(data) {
390                         if (data && data.length > 0) {
391                             callback(br, data[0]);
392                         }
393                     },
394                     dataType: 'jsonp'
395                 });
396             }
397         },
398         dataType: 'jsonp'
399     });
400 }
401
402 br.buildInfoDiv = function(jInfoDiv) {
403     // $$$ it might make more sense to have a URL on openlibrary.org that returns this info
404
405     var escapedTitle = BookReader.util.escapeHTML(this.bookTitle);
406     var domainRe = /(\w+\.(com|org))/;
407     var domainMatch = domainRe.exec(this.bookUrl);
408     var domain = this.bookUrl;
409     if (domainMatch) {
410         domain = domainMatch[1];
411     }
412        
413     // $$$ cover looks weird before it loads
414     jInfoDiv.find('.BRfloatCover').append([
415                     '<div style="height: 140px; min-width: 80px; padding: 0; margin: 0;"><a href="', this.bookUrl, '"><img src="http://www.archive.org/download/', this.bookId, '/page/cover_t.jpg" alt="' + escapedTitle + '" height="140px" /></a></div>'].join('')
416     );
417
418     jInfoDiv.find('.BRfloatMeta').append([
419                     // $$$ description
420                     //'<p>Published ', this.bookPublished,
421                     //, <a href="Open Library Publisher Page">Publisher name</a>',
422                     //'</p>',
423                     //'<p>Written in <a href="Open Library Language page">Language</a></p>',
424                     '<h3>Other Formats</h3>',
425                     '<ul class="links">',
426                         '<li><a href="http://www.archive.org/download/', this.bookId, '/', this.subPrefix, '.pdf">PDF</a><span>|</span></li>',
427                         '<li><a href="http://www.archive.org/download/', this.bookId, '/', this.subPrefix, '_djvu.txt">Plain Text</a><span>|</span></li>',
428                         '<li><a href="http://www.archive.org/download/', this.bookId, '/', this.subPrefix, '_daisy.zip">DAISY</a><span>|</span></li>',
429                         '<li><a href="http://www.archive.org/download/', this.bookId, '/', this.subPrefix, '.epub">ePub</a><span>|</span></li>',
430                         '<li><a href="https://www.amazon.com/gp/digital/fiona/web-to-kindle?clientid=IA&itemid=', this.bookId, '&docid=', this.subPrefix, '">Send to Kindle</a></li>',
431                     '</ul>',
432                     '<p class="moreInfo"><span></span>More information on <a href="'+ this.bookUrl + '">' + domain + '</a>  </p>'].join('\n'));
433                     
434     jInfoDiv.find('.BRfloatFoot').append([
435                 '<span>|</span>',                
436                 '<a href="http://openlibrary.org/contact" class="problem">Report a problem</a>',
437     ].join('\n'));
438                 
439     if (domain == 'archive.org') {
440         jInfoDiv.find('.BRfloatMeta p.moreInfo span').css(
441             {'background': 'url(http://www.archive.org/favicon.ico) no-repeat', 'width': 22, 'height': 18 }
442         );
443     }
444     
445     jInfoDiv.find('.BRfloatTitle a').attr({'href': this.bookUrl, 'alt': this.bookTitle}).text(this.bookTitle);
446     var bookPath = (window.location + '').replace('#','%23');
447     jInfoDiv.find('a.problem').attr('href','http://openlibrary.org/contact?path=' + bookPath);
448
449 }
450
451 br.pageW =  [
452             <?
453             $i=0;
454             foreach ($scanData->pageData->page as $page) {
455                 if (shouldAddPage($page)) {
456                     if(0 != $i) echo ",";   //stupid IE
457                     echo "{$page->cropBox->w}";
458                     $i++;
459                 }
460             }
461             ?>
462             ];
463
464 br.pageH =  [
465             <?
466             $totalHeight = 0;
467             $i=0;            
468             foreach ($scanData->pageData->page as $page) {
469                 if (shouldAddPage($page)) {
470                     if(0 != $i) echo ",";   //stupid IE                
471                     echo "{$page->cropBox->h}";
472                     $totalHeight += intval($page->cropBox->h/4) + 10;
473                     $i++;
474                 }
475             }
476             ?>
477             ];
478 br.leafMap = [
479             <?
480             $i=0;
481             foreach ($scanData->pageData->page as $page) {
482                 if (shouldAddPage($page)) {
483                     if(0 != $i) echo ",";   //stupid IE
484                     echo "{$page['leafNum']}";
485                     $i++;
486                 }
487             }
488             ?>    
489             ];
490
491 br.pageNums = [
492             <?
493             $i=0;
494             foreach ($scanData->pageData->page as $page) {
495                 if (shouldAddPage($page)) {
496                     if(0 != $i) echo ",";   //stupid IE                
497                     if (array_key_exists('pageNumber', $page) && ('' != $page->pageNumber)) {
498                         echo "'{$page->pageNumber}'";
499                     } else {
500                         echo "null";
501                     }
502                     $i++;
503                 }
504             }
505             ?>    
506             ];
507             
508       
509 br.numLeafs = br.pageW.length;
510
511 br.bookId   = '<?echo $id;?>';
512 br.zip      = '<?echo $imageStackFile;?>';
513 br.subPrefix = '<?echo $subPrefix;?>';
514 br.server   = '<?echo $server;?>';
515 br.bookTitle= '<?echo preg_replace("/\'/", "\\'", $metaData->title);?>';
516 br.bookPath = '<?echo $subItemPath;?>';
517 br.bookUrl  = '<?echo "http://www.archive.org/details/$id";?>';
518 br.imageFormat = '<?echo $imageFormat;?>';
519 br.archiveFormat = '<?echo $archiveFormat;?>';
520
521 <?
522
523 # Load some values from meta.xml
524 if ('' != $metaData->{'page-progression'}) {
525   echo "br.pageProgression = '" . $metaData->{"page-progression"} . "';\n";
526 } else {
527   // Assume page progression is Left To Right
528   echo "br.pageProgression = 'lr';\n";
529 }
530
531 $useOLAuth = false;
532 foreach ($metaData->xpath('//collection') as $collection) {
533     if('browserlending' == $collection) {
534         $useOLAuth = true;
535     }
536 }
537
538 #echo "br.olHost = 'http://openlibrary.org'\n";
539 echo "br.olHost = 'http://ol-mang:8080'\n";
540
541 if ($useOLAuth) {
542     echo "br.olAuth = true;\n";
543 } else {
544     echo "br.olAuth = false;\n";
545 }
546
547 # Special cases
548 if ('bandersnatchhsye00scarrich' == $id) {
549     echo "br.mode     = 2;\n";
550     echo "br.auto     = true;\n";
551 }
552
553 ?>
554
555 // Check for config object
556 // $$$ change this to use the newer params object
557 if (typeof(brConfig) != 'undefined') {
558     if (typeof(brConfig["ui"]) != 'undefined') {
559         br.ui = brConfig["ui"];
560     }
561
562     if (brConfig['mode'] == 1) {
563         br.mode = 1;
564         if (typeof(brConfig['reduce'] != 'undefined')) {
565             br.reduce = brConfig['reduce'];
566         }
567     } else if (brConfig['mode'] == 2) {
568         br.mode = 2;      
569     }
570 } // brConfig
571
572
573 function OLAuth() {
574     this.authUrl = br.olHost + '/ia_auth/' + br.bookId;
575     this.olConnect = false;
576     this.loanUUID = false;
577     this.loanToken = false;
578     
579     var cookieRe = /;\s*/;
580     var cookies = document.cookie.split(cookieRe);
581     var length = cookies.length;
582     var i;
583     for (i=0; i<length; i++) {
584         if (0 == cookies[i].indexOf('br-loan-' + br.bookId)) {
585             this.loanUUID = cookies[i].split('=')[1];
586         }
587         if (0 == cookies[i].indexOf('loan-' + br.bookId)) {
588             this.loanToken = cookies[i].split('=')[1];
589         }
590     }
591
592     return this;
593 }
594
595 OLAuth.prototype.init = function() {
596     var htmlStr =  'Checking loan status with Open Library';
597
598     this.showPopup("#ddd", "#000", htmlStr, 'Please wait as we check the status of this book...');
599     var authUrl = this.authUrl+'?rand='+Math.random();
600     if (false !== this.loanUUID) {
601         authUrl += '&loan='+this.loanUUID
602     }
603     if (false !== this.loanToken) {
604         authUrl += '&token='+this.loanToken
605     }
606     $.ajax({url:authUrl, dataType:'jsonp', jsonpCallback:'olAuth.initCallback'});
607 }
608
609 OLAuth.prototype.showPopup = function(bgColor, textColor, msg, resolution) {
610     this.popup = document.createElement("div");
611     $(this.popup).css({
612         position: 'absolute',
613         top:      '20px',
614         left:     ($('#BookReader').attr('clientWidth')-400)/2 + 'px',
615         width:    '400px',
616         padding:  "20px",
617         border:   "3px double #999999",
618         zIndex:   3,
619         textAlign: 'center',
620         backgroundColor: bgColor,
621         color: textColor
622     }).appendTo('#BookReader');
623
624     this.setPopupMsg(msg, resolution);
625
626 }
627
628 OLAuth.prototype.setPopupMsg = function(msg, resolution) {
629     this.popup.innerHTML = ['<p><strong>', msg, '</strong></p><p>', resolution, '</p>'].join('\n');
630 }
631
632 OLAuth.prototype.initCallback = function(obj) {
633     if (false == obj.success) {
634         $(this.popup).css({
635             backgroundColor: "#fff",
636             color: "#000"
637         });
638
639         this.setPopupMsg(obj.msg, obj.resolution);
640         return;
641     }
642     
643     //user is authenticated
644     this.setCookie(obj.token);
645     this.olConnect = true;
646     this.startPolling();    
647     br.init();
648 }
649
650 OLAuth.prototype.callback = function(obj) {
651     if (false == obj.success) {
652         this.showPopup("#fff", "#000", obj.msg, obj.resolution);
653         clearInterval(this.poller);
654         this.ttsPoller = null;
655     } else {
656         this.olConnect = true;
657         this.setCookie(obj.token);
658     }
659 }
660
661 OLAuth.prototype.setCookie = function(value) {
662     var date = new Date();
663     date.setTime(date.getTime()+(10*60*1000));  //10 min expiry
664     var expiry = date.toGMTString();
665     var cookie = 'loan-'+br.bookId+'='+value;
666     cookie    += '; expires='+expiry;
667     cookie    += '; path=/; domain=.archive.org;';
668     document.cookie = cookie;
669     
670     //refresh the br-loan uuid cookie with current expiry, if needed
671     if (false !== this.loanUUID) {
672         cookie = 'br-loan-'+br.bookId+'='+this.loanUUID;
673         cookie    += '; expires='+expiry;
674         cookie    += '; path=/; domain=.archive.org;';
675         document.cookie = cookie;
676     }
677 }
678
679 OLAuth.prototype.startPolling = function () {    
680     var self = this;
681     this.poller=setInterval(function(){
682         if (!self.olConnect) {
683           self.showPopup("#f00", "#fff", 'Connection error', 'The BookReader cannot reach Open Library. This might mean that you are offline or that Open Library is down. Please check your Internet connection or try again later.');
684           clearInterval(self.poller);
685           self.ttsPoller = null;        
686         } else {
687           self.olConnect = false;
688           //be sure to add random param to authUrl to avoid stale cache
689           var authUrl = self.authUrl+'?rand='+Math.random();
690           if (false !== self.loanUUID) {
691               authUrl += '&loan='+self.loanUUID
692           }
693           if (false !== self.loanToken) {
694               authUrl += '&token='+self.loanToken
695           }
696
697           $.ajax({url:authUrl, dataType:'jsonp', jsonpCallback:'olAuth.callback'});
698         }
699     },300000);   //five minute interval
700 }
701
702 br.cleanupMetadata();
703 if (br.olAuth) {
704     var olAuth = new OLAuth();
705     olAuth.init();
706 } else {
707     br.init();
708 }
709 <?
710
711
712 function BRFatal($string) {
713     // log error
714     ?>
715     
716     if (typeof(archive_analytics) != 'undefined') {
717         var values = {
718             'bookreader': 'fatal',
719             'description': "<? echo $string; ?>",
720             'itemid': "<? echo $_REQUEST['id']; ?>",
721             'server': "<? echo $_REQUEST['server']; ?>",
722             'request_uri': "<? echo $_SERVER["REQUEST_URI"]; ?>"
723         }
724         
725         if (document.referrer == '') {
726             values['referrer'] = '-';
727         } else {
728             values['referrer'] = document.referrer;
729         }
730         
731         var qs = archive_analytics.format_bug(values);
732
733         var error_img = new Image(100,25);
734         error_img.src = archive_analytics.img_src + "?" + qs;
735     }
736
737     alert("<? echo $string;?>");
738     
739     <?
740     
741     die(-1);
742 }
743
744 // Returns true if a page should be added based on it's information in
745 // the metadata
746 function shouldAddPage($page) {
747     // Return false only if the page is marked addToAccessFormats false.
748     // If there is no assertion we assume it should be added.
749     if (isset($page->addToAccessFormats)) {
750         if ("false" == strtolower(trim($page->addToAccessFormats))) {
751             return false;
752         }
753     }
754     
755     return true;
756 }
757
758 // Returns { 'imageFormat' => , 'archiveFormat' => '} given a sub-item prefix and loaded xml data
759 function findImageStack($subPrefix, $filesData) {
760
761     // $$$ The order of the image formats determines which will be returned first
762     $imageFormats = array('JP2' => 'jp2', 'TIFF' => 'tif', 'JPEG' => 'jpg');
763     $archiveFormats = array('ZIP' => 'zip', 'Tar' => 'tar');
764     $imageGroup = implode('|', array_keys($imageFormats));
765     $archiveGroup = implode('|', array_keys($archiveFormats));
766     // $$$ Currently only return processed images
767     $imageStackRegex = "/Single Page (Processed) (${imageGroup}) (${archiveGroup})/";
768         
769     foreach ($filesData->file as $file) {        
770         if (strpos($file['name'], $subPrefix) === 0) { // subprefix matches beginning
771             if (preg_match($imageStackRegex, $file->format, $matches)) {
772             
773                 // Make sure we have a regular image stack
774                 $imageFormat = $imageFormats[$matches[2]];
775                 if (strpos($file['name'], $subPrefix . '_' . $imageFormat) === 0) {            
776                     return array('imageFormat' => $imageFormat,
777                                  'archiveFormat' => $archiveFormats[$matches[3]],
778                                  'imageStackFile' => $file['name']);
779                 }
780             }
781         }
782     }
783     
784     return array('imageFormat' => 'unknown', 'archiveFormat' => 'unknown', 'imageStackFile' => 'unknown');
785         
786 }
787
788 ?>
789