Remove use of global br object in Open Library record callbacks. Fix issue on IE8...
[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 self = this; // closure
379     
380     var jsonURL = self.olHost + '/query.json?type=/type/edition&*=&ocaid=' + self.bookId;
381     $.ajax({
382         url: jsonURL,
383         success: function(data) {
384             if (data && data.length > 0) {
385                 callback(self, data[0]);
386             } else {
387                 // try sourceid
388                 jsonURL = self.olHost + '/query.json?type=/type/edition&*=&source_records=ia:' + self.bookId;
389                 $.ajax({
390                     url: jsonURL,
391                     success: function(data) {
392                         if (data && data.length > 0) {
393                             callback(self, data[0]);
394                         }
395                     },
396                     dataType: 'jsonp'
397                 });
398             }
399         },
400         dataType: 'jsonp'
401     });
402 }
403
404 br.buildInfoDiv = function(jInfoDiv) {
405     // $$$ it might make more sense to have a URL on openlibrary.org that returns this info
406
407     var escapedTitle = BookReader.util.escapeHTML(this.bookTitle);
408     var domainRe = /(\w+\.(com|org))/;
409     var domainMatch = domainRe.exec(this.bookUrl);
410     var domain = this.bookUrl;
411     if (domainMatch) {
412         domain = domainMatch[1];
413     }
414        
415     // $$$ cover looks weird before it loads
416     jInfoDiv.find('.BRfloatCover').append([
417                     '<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('')
418     );
419
420     jInfoDiv.find('.BRfloatMeta').append([
421                     // $$$ description
422                     //'<p>Published ', this.bookPublished,
423                     //, <a href="Open Library Publisher Page">Publisher name</a>',
424                     //'</p>',
425                     //'<p>Written in <a href="Open Library Language page">Language</a></p>',
426                     '<h3>Other Formats</h3>',
427                     '<ul class="links">',
428                         '<li><a href="http://www.archive.org/download/', this.bookId, '/', this.subPrefix, '.pdf">PDF</a><span>|</span></li>',
429                         '<li><a href="http://www.archive.org/download/', this.bookId, '/', this.subPrefix, '_djvu.txt">Plain Text</a><span>|</span></li>',
430                         '<li><a href="http://www.archive.org/download/', this.bookId, '/', this.subPrefix, '_daisy.zip">DAISY</a><span>|</span></li>',
431                         '<li><a href="http://www.archive.org/download/', this.bookId, '/', this.subPrefix, '.epub">ePub</a><span>|</span></li>',
432                         '<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>',
433                     '</ul>',
434                     '<p class="moreInfo"><span></span>More information on <a href="'+ this.bookUrl + '">' + domain + '</a>  </p>'].join('\n'));
435                     
436     jInfoDiv.find('.BRfloatFoot').append([
437                 '<span>|</span>',                
438                 '<a href="http://openlibrary.org/contact" class="problem">Report a problem</a>',
439     ].join('\n'));
440                 
441     if (domain == 'archive.org') {
442         jInfoDiv.find('.BRfloatMeta p.moreInfo span').css(
443             {'background': 'url(http://www.archive.org/favicon.ico) no-repeat', 'width': 22, 'height': 18 }
444         );
445     }
446     
447     jInfoDiv.find('.BRfloatTitle a').attr({'href': this.bookUrl, 'alt': this.bookTitle}).text(this.bookTitle);
448     var bookPath = (window.location + '').replace('#','%23');
449     jInfoDiv.find('a.problem').attr('href','http://openlibrary.org/contact?path=' + bookPath);
450
451 }
452
453 br.pageW =  [
454             <?
455             $i=0;
456             foreach ($scanData->pageData->page as $page) {
457                 if (shouldAddPage($page)) {
458                     if(0 != $i) echo ",";   //stupid IE
459                     echo "{$page->cropBox->w}";
460                     $i++;
461                 }
462             }
463             ?>
464             ];
465
466 br.pageH =  [
467             <?
468             $totalHeight = 0;
469             $i=0;            
470             foreach ($scanData->pageData->page as $page) {
471                 if (shouldAddPage($page)) {
472                     if(0 != $i) echo ",";   //stupid IE                
473                     echo "{$page->cropBox->h}";
474                     $totalHeight += intval($page->cropBox->h/4) + 10;
475                     $i++;
476                 }
477             }
478             ?>
479             ];
480 br.leafMap = [
481             <?
482             $i=0;
483             foreach ($scanData->pageData->page as $page) {
484                 if (shouldAddPage($page)) {
485                     if(0 != $i) echo ",";   //stupid IE
486                     echo "{$page['leafNum']}";
487                     $i++;
488                 }
489             }
490             ?>    
491             ];
492
493 br.pageNums = [
494             <?
495             $i=0;
496             foreach ($scanData->pageData->page as $page) {
497                 if (shouldAddPage($page)) {
498                     if(0 != $i) echo ",";   //stupid IE                
499                     if (array_key_exists('pageNumber', $page) && ('' != $page->pageNumber)) {
500                         echo "'{$page->pageNumber}'";
501                     } else {
502                         echo "null";
503                     }
504                     $i++;
505                 }
506             }
507             ?>    
508             ];
509             
510       
511 br.numLeafs = br.pageW.length;
512
513 br.bookId   = '<?echo $id;?>';
514 br.zip      = '<?echo $imageStackFile;?>';
515 br.subPrefix = '<?echo $subPrefix;?>';
516 br.server   = '<?echo $server;?>';
517 br.bookTitle= '<?echo preg_replace("/\'/", "\\'", $metaData->title);?>';
518 br.bookPath = '<?echo $subItemPath;?>';
519 br.bookUrl  = '<?echo "http://www.archive.org/details/$id";?>';
520 br.imageFormat = '<?echo $imageFormat;?>';
521 br.archiveFormat = '<?echo $archiveFormat;?>';
522
523 <?
524
525 # Load some values from meta.xml
526 if ('' != $metaData->{'page-progression'}) {
527   echo "br.pageProgression = '" . $metaData->{"page-progression"} . "';\n";
528 } else {
529   // Assume page progression is Left To Right
530   echo "br.pageProgression = 'lr';\n";
531 }
532
533 $useOLAuth = false;
534 $protected = false;
535 foreach ($metaData->xpath('//collection') as $collection) {
536     if('browserlending' == $collection) {
537         $useOLAuth = true;
538         $protected = true;
539     }
540 }
541
542 echo "br.olHost = 'http://openlibrary.org'\n";
543 #echo "br.olHost = 'http://ol-mang:8080'\n";
544
545 if ($useOLAuth) {
546     echo "br.olAuth = true;\n";
547 } else {
548     echo "br.olAuth = false;\n";
549 }
550
551 if ($protected) {
552     echo "br.protected = true;\n";
553 }
554
555 # Special cases
556 if ('bandersnatchhsye00scarrich' == $id) {
557     echo "br.mode     = 2;\n";
558     echo "br.auto     = true;\n";
559 }
560
561 ?>
562
563 // Check for config object
564 // $$$ change this to use the newer params object
565 if (typeof(brConfig) != 'undefined') {
566     if (typeof(brConfig["ui"]) != 'undefined') {
567         br.ui = brConfig["ui"];
568     }
569
570     if (brConfig['mode'] == 1) {
571         br.mode = 1;
572         if (typeof(brConfig['reduce'] != 'undefined')) {
573             br.reduce = brConfig['reduce'];
574         }
575     } else if (brConfig['mode'] == 2) {
576         br.mode = 2;      
577     }
578 } // brConfig
579
580
581 function OLAuth() {
582     this.authUrl = br.olHost + '/ia_auth/' + br.bookId;
583     this.olConnect = false;
584     this.loanUUID = false;
585     this.permsToken = false;
586     
587     var cookieRe = /;\s*/;
588     var cookies = document.cookie.split(cookieRe);
589     var length = cookies.length;
590     var i;
591     for (i=0; i<length; i++) {
592         if (0 == cookies[i].indexOf('br-loan-' + br.bookId)) {
593             this.loanUUID = cookies[i].split('=')[1];
594         }
595         if (0 == cookies[i].indexOf('loan-' + br.bookId)) {
596             this.permsToken = cookies[i].split('=')[1];
597         }
598     }
599
600     return this;
601 }
602
603 OLAuth.prototype.init = function() {
604     var htmlStr =  'Checking loan status with Open Library';
605
606     this.showPopup("#F0EEE2", "#000", htmlStr, 'Please wait as we check the status of this book...');
607     var authUrl = this.authUrl+'?rand='+Math.random();
608     if (false !== this.loanUUID) {
609         authUrl += '&loan='+this.loanUUID
610     }
611     if (false !== this.permsToken) {
612         authUrl += '&token='+this.permsToken
613     }
614     $.ajax({url:authUrl, dataType:'jsonp', jsonpCallback:'olAuth.initCallback'});
615 }
616
617 OLAuth.prototype.showPopup = function(bgColor, textColor, msg, resolution) {
618     this.popup = document.createElement("div");
619     $(this.popup).css({
620         position: 'absolute',
621         top:      '50px',
622         left:     ($('#BookReader').attr('clientWidth')-400)/2 + 'px',
623         width:    '400px',
624         padding:  "15px",
625         border:   "3px double #999999",
626         zIndex:   3,
627         textAlign: 'center',
628         backgroundColor: bgColor,
629         color: textColor
630     }).appendTo('#BookReader');
631
632     this.setPopupMsg(msg, resolution);
633
634 }
635
636 OLAuth.prototype.setPopupMsg = function(msg, resolution) {
637     this.popup.innerHTML = ['<p><strong>', msg, '</strong></p><p>', resolution, '</p>'].join('\n');
638 }
639
640 OLAuth.prototype.initCallback = function(obj) {
641     if (false == obj.success) {
642         $(this.popup).css({
643             backgroundColor: "#fff",
644             color: "#000"
645         });
646
647         this.setPopupMsg(obj.msg, obj.resolution);
648         return;
649     }
650     
651     //user is authenticated
652     this.setCookie(obj.token);
653     this.olConnect = true;
654     this.startPolling();    
655     br.init();
656 }
657
658 OLAuth.prototype.callback = function(obj) {
659     if (false == obj.success) {
660         this.showPopup("#F0EEE2", "#000", obj.msg, obj.resolution);
661         clearInterval(this.poller);
662         this.ttsPoller = null;
663     } else {
664         this.olConnect = true;
665         this.setCookie(obj.token);
666     }
667 }
668
669 OLAuth.prototype.setCookie = function(value) {
670     var date = new Date();
671     date.setTime(date.getTime()+(10*60*1000));  //10 min expiry
672     var expiry = date.toGMTString();
673     var cookie = 'loan-'+br.bookId+'='+value;
674     cookie    += '; expires='+expiry;
675     cookie    += '; path=/; domain=.archive.org;';
676     document.cookie = cookie;
677     this.permsToken = value;
678     
679     //refresh the br-loan uuid cookie with current expiry, if needed
680     if (false !== this.loanUUID) {
681         cookie = 'br-loan-'+br.bookId+'='+this.loanUUID;
682         cookie    += '; expires='+expiry;
683         cookie    += '; path=/; domain=.archive.org;';
684         document.cookie = cookie;
685     }
686 }
687
688 OLAuth.prototype.deleteCookies = function() {
689     var date = new Date();
690     date.setTime(date.getTime()-(24*60*60*1000));  //one day ago
691     var expiry = date.toGMTString();
692     var cookie = 'loan-'+br.bookId+'=""';
693     cookie    += '; expires='+expiry;
694     cookie    += '; path=/; domain=.archive.org;';
695     document.cookie = cookie;
696     
697     cookie = 'br-loan-'+br.bookId+'=""';
698     cookie    += '; expires='+expiry;
699     cookie    += '; path=/; domain=.archive.org;';
700     document.cookie = cookie;
701 }
702
703 OLAuth.prototype.startPolling = function () {    
704     var self = this;
705     this.poller=setInterval(function(){
706         if (!self.olConnect) {
707           self.showPopup("#F0EEE2", "#000", '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 and refresh this page or try again later.');
708           clearInterval(self.poller);
709           self.ttsPoller = null;        
710         } else {
711           self.olConnect = false;
712           //be sure to add random param to authUrl to avoid stale cache
713           var authUrl = self.authUrl+'?rand='+Math.random();
714           if (false !== self.loanUUID) {
715               authUrl += '&loan='+self.loanUUID
716           }
717           if (false !== self.permsToken) {
718               authUrl += '&token='+self.permsToken
719           }
720
721           $.ajax({url:authUrl, dataType:'jsonp', jsonpCallback:'olAuth.callback'});
722         }
723     },300000);   //five minute interval
724 }
725
726 br.cleanupMetadata();
727 if (br.olAuth) {
728     var olAuth = new OLAuth();
729     olAuth.init();
730 } else {
731     br.init();
732 }
733 <?
734
735
736 function BRFatal($string) {
737     // log error
738     ?>
739     
740     if (typeof(archive_analytics) != 'undefined') {
741         var values = {
742             'bookreader': 'fatal',
743             'description': "<? echo $string; ?>",
744             'itemid': "<? echo $_REQUEST['id']; ?>",
745             'server': "<? echo $_REQUEST['server']; ?>",
746             'request_uri': "<? echo $_SERVER["REQUEST_URI"]; ?>"
747         }
748         
749         if (document.referrer == '') {
750             values['referrer'] = '-';
751         } else {
752             values['referrer'] = document.referrer;
753         }
754         
755         var qs = archive_analytics.format_bug(values);
756
757         var error_img = new Image(100,25);
758         error_img.src = archive_analytics.img_src + "?" + qs;
759     }
760
761     alert("<? echo $string;?>");
762     
763     <?
764     
765     die(-1);
766 }
767
768 // Returns true if a page should be added based on it's information in
769 // the metadata
770 function shouldAddPage($page) {
771     // Return false only if the page is marked addToAccessFormats false.
772     // If there is no assertion we assume it should be added.
773     if (isset($page->addToAccessFormats)) {
774         if ("false" == strtolower(trim($page->addToAccessFormats))) {
775             return false;
776         }
777     }
778     
779     return true;
780 }
781
782 // Returns { 'imageFormat' => , 'archiveFormat' => '} given a sub-item prefix and loaded xml data
783 function findImageStack($subPrefix, $filesData) {
784
785     // $$$ The order of the image formats determines which will be returned first
786     $imageFormats = array('JP2' => 'jp2', 'TIFF' => 'tif', 'JPEG' => 'jpg');
787     $archiveFormats = array('ZIP' => 'zip', 'Tar' => 'tar');
788     $imageGroup = implode('|', array_keys($imageFormats));
789     $archiveGroup = implode('|', array_keys($archiveFormats));
790     // $$$ Currently only return processed images
791     $imageStackRegex = "/Single Page (Processed) (${imageGroup}) (${archiveGroup})/";
792         
793     foreach ($filesData->file as $file) {        
794         if (strpos($file['name'], $subPrefix) === 0) { // subprefix matches beginning
795             if (preg_match($imageStackRegex, $file->format, $matches)) {
796             
797                 // Make sure we have a regular image stack
798                 $imageFormat = $imageFormats[$matches[2]];
799                 if (strpos($file['name'], $subPrefix . '_' . $imageFormat) === 0) {            
800                     return array('imageFormat' => $imageFormat,
801                                  'archiveFormat' => $archiveFormats[$matches[3]],
802                                  'imageStackFile' => $file['name']);
803                 }
804             }
805         }
806     }
807     
808     return array('imageFormat' => 'unknown', 'archiveFormat' => 'unknown', 'imageStackFile' => 'unknown');
809         
810 }
811
812 ?>
813