PageSourceSearch

https://www.saintcloud.fr/themes/stcloud_radix/dflip/js/dflip.js?v=11.4.7

js saintcloud.fr collected 2026-10-02 08:38:55 UTC 294,559 bytes, 8,900 lines download raw bytes

vendor: 5,340 bytes, lines 1-169
1/**
2 * @preserve
3 * Plugin Name: dflip
4 * Description: dflip - 3D & 2D FlipBook
5 *
6 * Author: Deepak Ghimire
7 * Author URI: http://codecanyon.net/user/dearhive?ref=dearhive
8 */
9
10'use strict';
11
12var DFLIP = DFLIP || {};
13
14// old fallback
15// use DFLIP instead of PRESENTATION as of v 1.1
16var PRESENTATION = DFLIP;
17
18(function dFlip(DFLIP, $) {
19
20  DFLIP.version = "1.5.6";
21
22  DFLIP.PAGE_MODE = {SINGLE: 1, DOUBLE: 2, AUTO: null};
23  DFLIP.SINGLE_PAGE_MODE = {ZOOM: 1, BOOKLET: 2, AUTO: null};
24  DFLIP.CONTROLSPOSITION = {HIDDEN: 'hide', TOP: 'top', BOTTOM: 'bottom'};
25  DFLIP.DIRECTION = {LTR: 1, RTL: 2};
26  DFLIP.LINK_TARGET = {NONE: 0, SELF: 1, BLANK: 2, PARENT: 3, TOP: 4};
27
28  DFLIP.CORNERS = {TL: "tl", TR: "tr", BL: "bl", BR: "br", L: "l", R: "r", NONE: null};
29
30  DFLIP.SOURCE_TYPE = {IMAGE: "image", PDF: "pdf", HTML: "html"};
31  DFLIP.DISPLAY_TYPE = {WEBGL: "3D", HTML: "2D"};
32  DFLIP.PAGE_SIZE = {AUTO: 0, SINGLE: 1, DOUBLEINTERNAL: 2};
33
34
35  //defaults settings
36  var defaults = DFLIP.defaults = {
37
38    //sets if to use 3d or not (true|false)
39    webgl: true,
40    //if you want to turn of shadow in 3d set it to false
41    webglShadow: true,
42
43    // if enable sound at start (true|false)
44    soundEnable: true,
45    search: false,
46
47    // height of the container
48    // value(eg: 320) or percentage (eg: '50%')
49    // calculaton limit: minimum 320, max window height
50    height: 'auto',
51
52    // set to true to show outline on open (true|false)
53    autoEnableOutline: false,
54
55    // set to true to show thumbnail on open (true|false)
56    autoEnableThumbnail: false,
57
58    // set to true if PDF inbuilt outline is to be removed (true|false)
59    overwritePDFOutline: false,
60
61    // enableDownload of PDF files (true|false)
62    enableDownload: true,
63
64    // duration of page turn in milliseconds
65    duration: 800,
66
67    //direction of flipbook
68    //DFLIP.DIRECTION.LTR or 1	for left to right(default),
69    //DFLIP.DIRECTION.RTL or 2	for right to left,
70    direction: DFLIP.DIRECTION.LTR,
71
72    //set as
73    //DFLIP.PAGE_MODE.AUTO	 				for auto-detect(default),
74    //DFLIP.PAGE_MODE.SINGLE or 1 			for singleview,
75    //DFLIP.PAGE_MODE.DOUBLE or 2 			for doubleview,
76    pageMode: DFLIP.PAGE_MODE.AUTO,
77
78    //set as
79    //DFLIP.SINGLE_PAGE_MODE.AUTO	 				for auto-detect(default),
80    //DFLIP.SINGLE_PAGE_MODE.ZOOM or 1 				for normal zoom single view,
81    //DFLIP.SINGLE_PAGE_MODE.BOOKLET or 2 			for Booklet mode,
82    singlePageMode: DFLIP.SINGLE_PAGE_MODE.AUTO,
83
84    //color value in hexadecimal
85    backgroundColor: "#fff",
86
87    forceFit: true, //very rare usage leave it as true unless page are not fitting wrong...
88    transparent: false, //true or false
89    hard: "none", //possible values are "hard", "none", "cover"
90    openPage: 1, //the pagenumber where the book should open
91
92    annotationClass: "",
93
94    autoPlay: false,
95    autoPlayDuration: 5000,
96    autoPlayStart: false,
97
98    // texture settings
99    maxTextureSize: 1600,	//max page size to be rendered. for pdf files only
100    minTextureSize: 256,	//min page size to be rendered. for pdf files only
101    rangeChunkSize: 524288,
102
103    // icons for the buttons
104    icons: {
105      'altnext': 'ti-angle-right',
106      'altprev': 'ti-angle-left',
107      'next': 'ti-angle-right',
108      'prev': 'ti-angle-left',
109      'end': 'ti-angle-double-right',
110      'start': 'ti-angle-double-left',
111      'share': 'ti-sharethis',
112      'help': 'ti-help-alt',
113      'more': 'ti-more-alt',
114      'download': 'ti-download',
115      'zoomin': 'ti-zoom-in',
116      'zoomout': 'ti-zoom-out',
117      'fullscreen': 'ti-fullscreen',
118      'fitscreen': 'ti-arrows-corner',
119      'thumbnail': 'ti-layout-grid2',
120      'outline': 'ti-menu-alt',
121      'close': 'ti-close',
122      'search': 'ti-search',
123      'doublepage': 'ti-book',
124      'singlepage': 'ti-file',
125      'sound': 'ti-volume',
126      'facebook': 'ti-facebook',
127      'google': 'ti-google',
128      'twitter': 'ti-twitter-alt',
129      'mail': 'ti-email',
130      'play': 'ti-control-play',
131      'pause': 'ti-control-pause'
132    },
133
134    // TRANSLATION text to be displayed
135    text: {
136
137      toggleSound: "Activer / Désactiver le son",
138      toggleThumbnails: "Basculer les vignettes",
139      toggleOutline: "Basculer le marque-page",
140      previousPage: "Page précédente",
141      nextPage: "Page suivante",
142      toggleFullscreen: "Basculer en plein écran",
143      zoomIn: "Zoomer",
144      zoomOut: "Dézoomer",
145      toggleHelp: "Basculer sur l'aide",
146
147      singlePageMode: "Mode page unique",
148      doublePageMode: "Mode double page",
149      downloadPDFFile: "Télécharger le fichier PDF",
150      gotoFirstPage: "Aller à la première page",
151      gotoLastPage: "Aller à la dernière page",
152      play: "Activer la lecture automatique",
153      pause: "Mettre en pause la lecture",
154
155      share: "Partager"
156    },
157
158    //valid controlnames:
159    //altPrev,pageNumber,altNext,outline,thumbnail,zoomIn,zoomOut,fullScreen,share
160    //more,download,pageMode,startPage,endPage,sound
161    allControls: "altPrev,pageNumber,altNext,play,outline,thumbnail,zoomIn,zoomOut,fullScreen,share,download,search,more,pageMode,startPage,endPage,sound",
162    moreControls: "download,pageMode,startPage,endPage,sound",
163    hideControls: "",
164
165    controlsPosition: DFLIP.CONTROLSPOSITION.BOTTOM,
166    paddingTop: 30,
167    paddingLeft: 20,
168    paddingRight: 20,
169    paddingBottom: 30,
170    enableAnalytics: false,
171
172    //set if the zoom changes on mouse scroll (true|false)
173    scrollWheel: true,
174
175    // callbacks
176    onCreate: function (flipBook) {
177      // after flip book is created is fired
178    },
179    onCreateUI: function (flipBook) {
180      // after ui created event is fired
181    },
182    onFlip: function (flipBook) {
183      // after flip event is fired
184    },
185    beforeFlip: function (flipBook) {
186      // before flip event is fired
187    },
188    onReady: function (flipBook) {
189      // after flip book is completely loaded
190    },
191
192    zoomRatio: 1.5,
193    pageSize: DFLIP.PAGE_SIZE.AUTO,
194
195    /**
196     * NON-OPTIONS AREA
197     * These options are not supposed to be sent from options variable
198     */
199    /**
200     * dependency URLS (NON-OPTION):
201     * Do not set them as options,
202     * Refer to advance-examples
203     */
204    //(NON-OPTION) source link for PDF.JS file
205    pdfjsSrc: "js/libs/pdf.min.js",
206    //(NON-OPTION) source link for PDFcompatibility.JS file
207    pdfjsCompatibilitySrc: "js/libs/compatibility.js",
208    //(NON-OPTION) source link for PDF.WORKER.JS file
209    pdfjsWorkerSrc: "js/libs/pdf.worker.min.js",
210    //(NON-OPTION) source link for THREE.JS file
211    threejsSrc: "js/libs/three.min.js",
212    //(NON-OPTION) source link for MOCKUP.JS file
213    mockupjsSrc: "js/libs/mockup.min.js",
214    //(NON-OPTION) File path to the trun sound
215    soundFile: "sound/turn2.mp3",
216    imagesLocation: "images",
217    imageResourcesPath: "images/pdfjs/",
218    cMapUrl: "cmaps/", //it's quite wierd how cmaps don't work properly with relative urls like others.. but is relative to pdf.min.js path
219
220    //(NON-OPTION) developer parameters
221    enableDebugLog: false,
222    canvasToBlob: false,//as of 1.2.9 canvas are better optimized and secure
223    enableAnnotation: true,
224    pdfRenderQuality: 0.90,
225
226
227    /**
228     * Let them be, change at your risk
229     */
230    // if texture fallback override is required
231    // note: if set to anything other than "blank" the first page is changed
232    // recommended : "blank"
233    textureLoadFallback: "blank", //"images/textures/white.jpg",
234    // controls the flexibility of the paper more value for more flexiblilty
235    stiffness: 3,
236    // minTopOffset: 30,
237    // link to the images file that you want as background.
238    // supported files are jpgs,png. smaller files are preffered for performance
239    backgroundImage: "",//"images/textures/el.jpg",
240    // or any number like 5, 500. recommended: "auto"
241
242    pageRatio: null, 		//equals to width/height
243
244    pixelRatio: window.devicePixelRatio || 1,
245    thumbElement: 'div',
246
247    /*3D settings*/
248    spotLightIntensity: 0.22,
249    ambientLightColor: "#fff",
250    ambientLightIntensity: 0.8,
251    shadowOpacity: 0.15,
252
253    linkTarget: DFLIP.LINK_TARGET.BLANK
254  };
255
256  var has3d = 'WebKitCSSMatrix' in window
257    || (document.body && 'MozPerspective' in document.body.style),
258    hasMouse = 'onmousedown' in window,
259    hasTouch = 'ontouchstart' in window;
260
261  var userAgent = navigator.userAgent;
262
263  var utils = DFLIP.utils = {
264
265    drag: {
266      left: 0,
267      right: 1,
268      none: -1
269    },
270    mouseEvents: (hasMouse)
271                 ? {type: "mouse", start: "mousedown", move: "mousemove", end: "mouseup"}
272                 : {type: "touch", start: "touchstart", move: "touchmove", end: "touchend"},
273
274    html: {
275      div: "<div/>",
276      img: "<img/>",
277      a: "<a>",
278      input: "<input type='text'/>"
279    },
280    //functions or so
281    toRad: function (deg) {
282      return deg * Math.PI / 180;
283    },
284    isset: function (check, fallback) {
285      return check == null ? fallback : check;
286    },
287    isnull: function (variable) {
288      return variable == null || variable == null;
289    },
290    toDeg: function (rad) {
291      return rad * 180 / Math.PI;
292    },
293    transition: function (hasTransition, duration) {
294      return hasTransition ? duration / 1000 + "s ease-out" : "0s none";
295    },
296    hasCompatibility: function () {
297      var compatible = false;
298      if (window.dFlipLocation != null) {
299        if (window.dFlipLocation.indexOf('lip-lit') > 0)
300          compatible = true;
301      }
302      return compatible;
303    },
304    scrollIntoView: function (element, reference, align) {
305      reference = reference || element.parentNode;
306      reference.scrollTop = element.offsetTop - reference.offsetTop +
307        (align === false ? element.offsetHeight - reference.offsetHeight : 0);
308      reference.scrollLeft = element.offsetLeft - reference.offsetLeft;
309    },
310    display: function (hasDisplay) {
311      return hasDisplay ? "block" : "none";
312    },
313
314    resetTranslate: function () {
315      return translateStr(0, 0);
316    },
317
318    translateStr: function (x, y) {
319      return has3d ? ' translate3d(' + x + 'px,' + y + 'px, 0px) ' : ' translate(' + x + 'px, ' + y + 'px) ';
320    },
321    httpsCorrection: function (url) {
322      var location = window.location;
323      if (location.href.indexOf("https://") > -1 && url.indexOf(location.hostname) > -1) {
324        url = url.replace("http://", "https://");
325      }
326      if (location.href.indexOf("http://") > -1 && url.indexOf(location.hostname) > -1) {
327        url = url.replace("https://", "http://");
328      }
329      return url;
330    },
331    resetBoxShadow: function () {
332      return "rgba(0, 0, 0, 0) 0px 0px 20px";
333    },
334
335    rotateStr: function (deg) {
336      return ' rotateZ(' + deg + 'deg) ';
337    },
338
339    bg: function (src) {
340      return '#fff' + bgImage(src);
341    },
342
343    bgImage: function (src) {
344      return (src == null || src == "blank" ? '' : ' url(' + src + ')');
345    },
346
347    src: function (src) {
348      return (src != null ? '' + src + '' : '');
349    },
350
351    limitAt: function (x, min, max) {
352      return x < min ? min : x > max ? max : x;
353    },
354
355    distOrigin: function (x, y) {
356      return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
357    },
358
359    distPoints: function (x1, y1, x2, y2) {
360      return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
361    },
362    calculateScale: function (startTouches, endTouches) {
363      var startDistance = distPoints(startTouches[0].x, startTouches[0].y, startTouches[1].x, startTouches[1].y),
364        endDistance = distPoints(endTouches[0].x, endTouches[0].y, endTouches[1].x, endTouches[1].y);
365      return endDistance / startDistance;
366    },
367    /**
368     * Calculates the average of multiple vectors (x, y values)
369     */
370    getVectorAvg: function (vectors) {
371      return {
372        x: vectors.map(function (v) {
373          return v.x;
374        }).reduce(utils.sum) / vectors.length,
375        y: vectors.map(function (v) {
376          return v.y;
377        }).reduce(utils.sum) / vectors.length
378      };
379    },
380    sum: function (a, b) {
381      return a + b;
382    },
383    /**
384     * Returns the touches of an event relative to the container offset
385     * @param event
386     * @return array touches
387     */
388    getTouches: function (event, position) {
389      position = position || {left: 0, top: 0};
390      return Array.prototype.slice.call(event.touches).map(function (touch) {
391        return {
392          x: touch.pageX - position.left,
393          y: touch.pageY - position.top
394        };
395      });
396    },
397
398    angleByDistance: function (distance, fullWidth) {
399      var h = fullWidth / 2;
400      var d = limitAt(distance, 0, fullWidth);
401
402      return d < h
403             ? toDeg(Math.asin(d / h))
404             : 90 + toDeg(Math.asin((d - h) / h));
405
406    },
407
408    log: function (args) {
409      if (defaults.enableDebugLog == true && window.console)
410        console.log(args);
411    },
412    lowerPowerOfTwo: function (value) {
413      return Math.pow(2, Math.floor(Math.log(value) / Math.LN2));
414    },
415    nearestPowerOfTwo: function (value, max) {
416      return Math.min(max || 2048, Math.pow(2, Math.ceil(Math.log(value) / Math.LN2)));
417    },
418    zoomStops: function (value, zoomRatio, ceil, min, max) {
419      if (min == null) min = 256;
420      if (max == null) max = 2048;
421      //Math.pow(2, Math.ceil(Math.log(value) / Math.LN2));
422
423      var factor = Math.log(value / min) / Math.log(zoomRatio);
424
425      return min * Math.pow(zoomRatio, ceil == null ? Math.round(factor) : (ceil == true ? Math.ceil(factor)
426                                                                                         : Math.floor(factor)));
427    },
428
429    extendOptions: function (defaults, options) {
430      return $.extend(true, {}, defaults, options);
431    },
432    getFullscreenElement: function () {
433      return document.fullscreenElement
434        || document.mozFullScreenElement
435        || document.webkitFullscreenElement
436        || document.msFullscreenElement
437    },
438    hasFullscreenEnabled: function () {
439      return document.fullscreenEnabled
440        || document.mozFullScreenEnabled
441        || document.webkitFullscreenEnabled
442        || document.msFullscreenEnabled
443    },
444    getBasePage: function (pageNumber) {
445      return Math.floor(pageNumber / 2) * 2;
446    },
447
448    loadResources: function loadResources(resourceTag, src, callback) {
449      var doc = document,
450        element = doc.createElement(resourceTag),
451        refElement = doc.getElementsByTagName(resourceTag)[0];
452
453      element.async = true;
454      if (callback) {
455        element.addEventListener('load', function (e) {
456          callback(null, e);
457        }, false);
458      }
459
460      element.src = src;
461
462      refElement.parentNode.insertBefore(element, refElement);
463    },
464    getScript: function (source, callback, errorCallback) {
465      var script = document.createElement('script');
466      var prior = document.body.getElementsByTagName('script')[0];
467      script.async = 1;
468      script.setAttribute("data-cfasync", false);
469      if (prior != null) {
470        prior.parentNode.insertBefore(script, prior);
471        prior = null;
472      }
473      else { //sometimes if script are loaded in head and no scripts are present in body
474        document.body.appendChild(script);
475      }
476
477      function load(_, isAbort) {
478        if (script != null) { //IE 10 doesn't regard
479          if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState)) {
480            //console.log("aborted loading :" + source);
481            script.onload = script.onreadystatechange = null;
482            script = null;
483            script = null;
484            if (!isAbort) {
485              if (callback) callback();
486              callback = null;
487              errorCallback = null;
488            }
489
490          }
491        }
492      }
493
494      script.addEventListener("load", load, false);
495      script.addEventListener("readystatechange", load, false);
496      script.addEventListener("complete", load, false);
497
498      if (errorCallback) {
499        script.addEventListener("error", errorCallback, false);
500      }
501      //script.onload = script.onreadystatechange = load;
502
503      script.src = source + (prefix.dom == "MS" ? ("?" + Math.random(1)) : "");
504    },
505    isHardPage: function (config, pageNumber, pageCount, isBooklet) {
506      if (config != null) {
507
508        // var config = this.hardConfig;
509
510        if (config == "cover") {
511          return pageNumber == 0 || (isBooklet && pageNumber == 1)  //front cover is 0
512            || pageNumber == (Math.floor(pageCount / (isBooklet ? 1 : 2)) - (isBooklet ? 0 : 1)); //start with 0 so 1 minus
513        }
514        else if (config == "all") {
515          return true;
516        }
517        else {
518          var baseTest = ("," + config + ",").indexOf("," + (pageNumber * 2 + 1) + ",") > -1;
519          var nextTest = ("," + config + ",").indexOf("," + (pageNumber * 2 + 2) + ",") > -1;
520          return baseTest || nextTest;
521
522        }
523      }
524      return false;
525    },
526    fixMouseEvent: function (event) {
527
528
529      if (event) {
530        var originalEvent = event.originalEvent || event;
531
532        //noinspection JSUnresolvedVariable
533        if (originalEvent.changedTouches && originalEvent.changedTouches.length > 0) {
534          var _event = $.event.fix(event);
535          //noinspection JSUnresolvedVariable
536          var touch = originalEvent.changedTouches[0];
537          _event.clientX = touch.clientX;
538          _event.clientY = touch.clientY;
539          _event.pageX = touch.pageX;
540          _event.touches = originalEvent.touches;
541          _event.pageY = touch.pageY;
542          _event.movementX = touch.movementX;
543          _event.movementY = touch.movementY;
544          return _event;
545        }
546        else {
547          return event;
548        }
549      }
550      else {
551        return event;
552      }
553
554    },
555
556    //self Execution
557    hasWebgl: (function () {
558      try {
559        var canvas = document.createElement('canvas');
560        //noinspection JSUnresolvedVariable
561        return !!(window.WebGLRenderingContext && (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')));
562      } catch (e) {
563        return false;
564      }
565    })(),
566    isBookletMode: function (book) {
567      return book.pageMode == DFLIP.PAGE_MODE.SINGLE && book.singlePageMode == DFLIP.SINGLE_PAGE_MODE.BOOKLET
568    },
569    isRTLMode: function (book) {
570      return book.direction == DFLIP.DIRECTION.RTL
571    },
572    isMobile: (function () {
573      var check = false;
574      (function (a) {
575        if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true
576      })(userAgent || navigator.vendor || window.opera);
577      return check;
578    })(),
579    isIOS: /(iPad|iPhone|iPod)/g.test(userAgent),
580    isSafari: /constructor/i.test(window.HTMLElement) || (function (p) {
581      return p.toString() === "[object SafariRemoteNotification]";
582    })(!window['safari'] || safari.pushNotification),
583    prefix: (function () {
584      var styles = window.getComputedStyle(document.documentElement, ''),
585        pre = (Array.prototype.slice
586          .call(styles)
587          .join('')
588          .match(/-(moz|webkit|ms)-/))[1],
589        dom = ('WebKit|Moz|MS').match(new RegExp('(' + pre + ')', 'i'))[1];
590      return {
591        dom: dom,
592        lowercase: pre,
593        css: '-' + pre + '-',
594        js: pre[0].toUpperCase() + pre.substr(1)
595      };
596    })(),
597
598    __extends: function (child, parent) {
599      for (var key in parent)
600        if (parent.hasOwnProperty(key)) child[key] = parent[key];
601
602      function Ctor() {
603        this.constructor = child;
604      }
605
606      Ctor.prototype = parent.prototype;
607      child.prototype = new Ctor();
608      child.__super = parent.prototype;
609      return child;
610    }
611
612  };
613
614  //caching the utils
615
616  var SOURCE_TYPE = DFLIP.SOURCE_TYPE,
617    DISPLAY_TYPE = DFLIP.DISPLAY_TYPE,
618
619    drag = utils.drag,
620    mouseEvents = utils.mouseEvents,
621    html = utils.html,
622    isset = utils.isset,
623    isnull = utils.isnull,
624
625    toRad = utils.toRad,
626    toDeg = utils.toDeg,
627    transition = utils.transition,
628    translateStr = utils.translateStr,
629    resetBoxShadow = utils.resetBoxShadow,
630    rotateStr = utils.rotateStr,
631
632    bg = utils.bg,
633    bgImage = utils.bgImage,
634    src = utils.src,
635
636    limitAt = utils.limitAt,
637    distOrigin = utils.distOrigin,
638    distPoints = utils.distPoints,
639    angleByDistance = utils.angleByDistance,
640    log = utils.log,
641    nearestPowerOfTwo = utils.nearestPowerOfTwo,
642    extendOptions = utils.extendOptions,
643    getBasePage = utils.getBasePage,
644    getScript = utils.getScript,
645    fixMouseEvent = utils.fixMouseEvent,
646    prefix = utils.prefix,
647    isBookletMode = utils.isBookletMode,
648    isRTLMode = utils.isRTLMode,
649    isMobile = utils.isMobile,
650    hasWebgl = utils.hasWebgl,
651    isSafari = utils.isSafari,
652    isIOS = utils.isIOS,
653    __extends = utils.__extends;
654
655  // Support: IE<11, Chrome<21, Android<4.4, Safari<6
656  (function checkSetPresenceInImageData() {
657    // IE < 11 will use window.CanvasPixelArray which lacks set function.
658    if (window.CanvasPixelArray) {
659      if (typeof window.CanvasPixelArray.prototype.set !== 'function') {
660        window.CanvasPixelArray.prototype.set = function (arr) {
661          for (var i = 0, ii = this.length; i < ii; i++) {
662            this[i] = arr[i];
663          }
664        };
665      }
666    }
667    else {
668      // Old Chrome and Android use an inaccessible CanvasPixelArray prototype.
669      // Because we cannot feature detect it, we rely on user agent parsing.
670      var polyfill = false, versionMatch;
671      if (isSafari) {
672        versionMatch = userAgent.match(/Version\/([0-9]+)\.([0-9]+)\.([0-9]+) Safari\//);
673        // Safari < 6 lacks the set function.
674        polyfill = versionMatch && parseInt(versionMatch[1]) < 6;
675      }
676
677      if (polyfill) {
678        var contextPrototype = window.CanvasRenderingContext2D.prototype;
679        var createImageData = contextPrototype.createImageData;
680        contextPrototype.createImageData = function (w, h) {
681          var imageData = createImageData.call(this, w, h);
682          imageData.data.set = function (arr) {
683            for (var i = 0, ii = this.length; i < ii; i++) {
684              this[i] = arr[i];
685            }
686          };
687          return imageData;
688        };
689        // this closure will be kept referenced, so clear its vars
690        contextPrototype = null;
691      }
692    }
693  })();
694
695  // Support: IE<10, Android<4.0, iOS
696  (function checkRequestAnimationFrame() {
697    function fakeRequestAnimationFrame(callback) {
698      window.setTimeout(callback, 20);
699    }
700
701    if ('requestAnimationFrame' in window) {
702      return;
703    }
704    window.requestAnimationFrame =
705      window.mozRequestAnimationFrame ||
706      window.webkitRequestAnimationFrame ||
707      fakeRequestAnimationFrame;
708  })();
709
710  // Checking if the typed arrays are supported
711  // Support: iOS<6.0 (subarray), IE<10, Android<4.0
712  (function checkTypedArrayCompatibility() {
713    if (typeof Uint8Array !== 'undefined') {
714      // Support: iOS<6.0
715      if (typeof Uint8Array.prototype.subarray === 'undefined') {
716        Uint8Array.prototype.subarray = function subarray(start, end) {
717          return new Uint8Array(this.slice(start, end));
718        };
719        Float32Array.prototype.subarray = function subarray(start, end) {
720          return new Float32Array(this.slice(start, end));
721        };
722      }
723
724      // Support: Android<4.1
725      if (typeof Float64Array === 'undefined') {
726        window.Float64Array = Float32Array;
727      }
728      return;
729    }
730
731    function subarray(start, end) {
732      return new TypedArray(this.slice(start, end));
733    }
734
735    function setArrayOffset(array, offset) {
736      if (arguments.length < 2) {
737        offset = 0;
738      }
739      for (var i = 0, n = array.length; i < n; ++i, ++offset) {
740        this[offset] = array[i] & 0xFF;
741      }
742    }
743
744    function TypedArray(arg1) {
745      var result, i, n;
746      if (typeof arg1 === 'number') {
747        result = [];
748        for (i = 0; i < arg1; ++i) {
749          result[i] = 0;
750        }
751      }
752      else if ('slice' in arg1) {
753        result = arg1.slice(0);
754      }
755      else {
756        result = [];
757        for (i = 0, n = arg1.length; i < n; ++i) {
758          result[i] = arg1[i];
759        }
760      }
761
762      result.subarray = subarray;
763      result.buffer = result;
764      result.byteLength = result.length;
765      result.set = setArrayOffset;
766
767      if (typeof arg1 === 'object' && arg1.buffer) {
768        result.buffer = arg1.buffer;
769      }
770      return result;
771    }
772
773    window.Uint8Array = TypedArray;
774    window.Int8Array = TypedArray;
775
776    // we don't need support for set, byteLength for 32-bit array
777    // so we can use the TypedArray as well
778    window.Uint32Array = TypedArray;
779    window.Int32Array = TypedArray;
780    window.Uint16Array = TypedArray;
781    window.Float32Array = TypedArray;
782    window.Float64Array = TypedArray;
783  })();
784
785  var extendDFlipOptions = function (options) {
786    return $.extend(true, {}, defaults, options);
787  };
788
789  //Creates ui for the flipbook
790  var createUI = function (container, object) {
791
792      var uiClass = "df-ui";
793      var wrapperClass = "df-ui-wrapper";
794      var buttonClass = uiClass + "-" + "btn";
795      var isRTL = isRTLMode(object.target);
796      var ui = object.ui = $(html.div, {'class': uiClass});
797      var options = object.options;
798
799      ui.dispose = function () {
800        container.find("." + buttonClass).each(function () {
801          $(this).off();
802        });
803        help.off();
804        next.off();
805        prev.off();
806        play.off();
807        zoom.off();
808        zoomIn.off();
809        zoomOut.off();
810        page.off();
811        sound.off();
812        more.off();
813        fullScreen.off();
814        fit.off();
815        share.off();
816        start.off();
817        end.off();
818        pageModeButton.off();
819        altPrev.off();
820        altNext.off();
821        thumbnail.off();
822        outline.off();
823
824        controls.remove();
825        sizeControls.remove();
826        prev.remove();
827        next.remove();
828        zoom.remove();
829        if (ui.shareBox) {
830          if (ui.shareBox.dispose)
831            ui.shareBox.dispose();
832          ui.shareBox = null;
833        }
834        document.removeEventListener('keyup', onKeyUp, false);
835        window.removeEventListener('click', closeMoreOptions, false);
836        ui.update = null;
837        object = null;
838      };
839
840      var validPage = function (pageNumber) {
841
842        if (isNaN(pageNumber)) pageNumber = object.target._activePage;
843        else if (pageNumber < 1) pageNumber = 1;
844        else if (pageNumber > object.target.pageCount) pageNumber = object.target.pageCount;
845        return pageNumber;
846
847      };
848
849      var next = ui.next = $(html.div, {
850
851        class: buttonClass + " " + uiClass + "-next " + options.icons['next'],
852        title: isRTL ? options.text.previousPage : options.text.nextPage,
853        html: "<span>" + options.text.nextPage + "</span>"
854
855      }).on("click", function () {
856        object.next();
857      });
858
859      var prev = ui.prev = $(html.div, {
860
861        class: buttonClass + " " + uiClass + "-prev " + options.icons['prev'],
862        title: isRTL ? options.text.nextPage : options.text.previousPage,
863        html: "<span>" + options.text.previousPage + "</span>"
864
865      }).on("click", function () {
866
867        object.prev();
868
869      });
870      var play = $(html.div, {
871
872        class: buttonClass + " " + uiClass + "-play " + options.icons['play'],
873        title: options.text.play,
874        html: "<span>" + options.text.play + "</span>"
875
876      }).on("click", function () {
877        var el = $(this);
878        object.setAutoPlay(!el.hasClass(options.icons['pause']));
879
880      });
881      if (options.autoPlay == true) {
882        ui.play = play;
883        object.setAutoPlay(options.autoPlayStart);
884      }
885      var zoom = $(html.div, {
886        class: wrapperClass + " " + uiClass + "-zoom"
887      });
888
889      var zoomIn = ui.zoomIn = $(html.div, {
890
891        class: buttonClass + " " + uiClass + "-zoomin " + options.icons['zoomin'],
892        title: options.text.zoomIn,
893        html: "<span>" + options.text.zoomIn + "</span>"
894
895      }).on("click", function () {
896
897        object.zoom(1);
898        ui.update();
899        if (object.target.startPoint && object.target.pan)
900          object.target.pan(object.target.startPoint);
901
902      });
903
904      var zoomOut = ui.zoomOut = $(html.div, {
905
906        class: buttonClass + " " + uiClass + "-zoomout " + options.icons['zoomout'],
907        title: options.text.zoomOut,
908        html: "<span>" + options.text.zoomOut + "</span>"
909
910      }).on("click", function () {
911        object.zoom(-1);
912        ui.update();
913        if (object.target.startPoint && object.target.pan)
914          object.target.pan(object.target.startPoint);
915      });
916      zoom.append(zoomIn).append(zoomOut);
917
918      var page = ui.pageNumber = $(html.div, {
919
920        class: buttonClass + " " + uiClass + "-page",
921
922      }).on("change", function () {
923
924        var pageNumber = parseInt((ui.pageInput.val()), 10);
925
926        pageNumber = validPage(pageNumber);
927        object.gotoPage(pageNumber);
928
929      }).on("keyup", function (event) {
930
931        if (event.keyCode == 13) {
932          var pageNumber = parseInt((ui.pageInput.val()), 10);
933
934          pageNumber = validPage(pageNumber);
935          if (pageNumber !== validPage(object.target._activePage || object._activePage))
936            object.gotoPage(pageNumber);
937        }
938
939      });
940
941      ui.pageInput = $('<input id="df_book_page_number" type="text"/>').appendTo(page);
942      ui.pageLabel = $('<label for="df_book_page_number"/>').appendTo(page);
943
944      var sizeControls = $(html.div, {
945        class: wrapperClass + " " + uiClass + "-size"
946      });
947
948      var help = $(html.div, {
949        class: buttonClass + " " + uiClass + "-help " + options.icons['help'],
950        title: options.text.toggleHelp,
951        html: "<span>" + options.text.toggleHelp + "</span>"
952      }).on("click", function () {
953
954      });
955
956
957      //Sound Button
958      var sound = ui.sound = $(html.div, {
959
960        class: buttonClass + " " + uiClass + "-sound " + options.icons['sound'],
961        title: options.text.toggleSound,
962        html: "<span>" + options.text.toggleSound + "</span>"
963
964      }).on("click", function () {
965
966        options.soundEnable = !options.soundEnable;
967        ui.updateSound();
968
969      });
970
971      //Updates sound on click of sound button
972      ui.updateSound = function () {
973
974        if (options.soundEnable == false || options.soundEnable == 'false')
975          sound.addClass("disabled");
976        else
977          sound.removeClass("disabled");
978
979      };
980
981      //immediate check
982      ui.updateSound();
983
984      //Search button
985      //closes searchoptions container
986      function closeSearchOptions(event) {
987        ui.search.removeClass("df-active");
988      }
989
990      if (typeof options.source == 'string' && options.search == true) {
991        var search = ui.search = $(html.div, {
992
993          class: buttonClass + " " + uiClass + "-search " + options.icons['search']
994
995        }).on("click", function (event) {
996          if (!search.hasClass("df-active")) {
997            $(this).addClass("df-active");
998            event.stopPropagation();
999          }
1000        });
1001
1002
1003        //register a click event on window to close the searchoptions
1004        window.addEventListener('click', closeSearchOptions, false);
1005
1006        //search container that holds the searchoptions
1007        var searchContainer = $(html.div, {
1008          class: "search-container"
1009        });
1010        search.append(searchContainer);
1011      }
1012
1013      //More button
1014      var more = ui.more = $(html.div, {
1015
1016        class: buttonClass + " " + uiClass + "-more " + options.icons['more']
1017
1018      }).on("click", function (event) {
1019        if (!more.hasClass("df-active")) {
1020          $(this).addClass("df-active");
1021          event.stopPropagation();
1022        }
1023      });
1024
1025      //closes moreoptions container
1026      function closeMoreOptions(event) {
1027        more.removeClass("df-active");
1028      }
1029
1030      //register a click event on window to close the moreoptions
1031      window.addEventListener('click', closeMoreOptions, false);
1032
1033      //more container that holds the moreoptions
1034      var moreContainer = $(html.div, {
1035        class: "more-container"
1036      });
1037      more.append(moreContainer);
1038
1039      if (typeof options.source == 'string' && options.enableDownload == true) {
1040        var downloadClass = buttonClass + " " + uiClass + "-download " + options.icons['download'];
1041        var download = ui.download = $('<a download target="_blank" class="' + downloadClass + '"><span>' + options.text.downloadPDFFile + '</span></a>');
1042        download.attr("href", options.source).attr("title", options.text.downloadPDFFile);
1043        //moreContainer.append(download);
1044      }
1045
1046      var fullscreenEnabled = utils.hasFullscreenEnabled();
1047
1048      if (!fullscreenEnabled) {
1049        container.addClass("df-custom-fullscreen");
1050      }
1051
1052      ui.switchFullscreen = function () {
1053
1054        var fullscreenElement = utils.getFullscreenElement();
1055
1056        var container = object.container[0];
1057
1058        if (ui.isFullscreen != true) {
1059
1060          object.container.addClass("df-fullscreen");
1061          if (container.requestFullscreen) {
1062            container.requestFullscreen();
1063          }
1064          else if (container.msRequestFullscreen) {
1065            container.msRequestFullscreen();
1066          }
1067          else if (container.mozRequestFullScreen) {
1068            container.mozRequestFullScreen();
1069          }
1070          else if (container.webkitRequestFullscreen) {
1071            container.webkitRequestFullscreen();
1072          }
1073
1074          ui.isFullscreen = true
1075
1076        }
1077        else {
1078
1079          object.container.removeClass("df-fullscreen");
1080          ui.isFullscreen = false;
1081
1082          if (document.exitFullscreen) {
1083            document.exitFullscreen();
1084          }
1085          else if (document.msExitFullscreen) {
1086            document.msExitFullscreen();
1087          }
1088          else if (document.mozCancelFullScreen) {
1089            document.mozCancelFullScreen();
1090          }
1091          else if (document.webkitExitFullscreen) {
1092            document.webkitExitFullscreen();
1093          }
1094
1095        }
1096
1097        if (!utils.hasFullscreenEnabled()) {
1098          setTimeout(function () {
1099            object.resize();
1100          }, 50);
1101        }
1102      };
1103
1104      var fullScreen = ui.fullScreen = $(html.div, {
1105
1106        class: buttonClass + " " + uiClass + "-fullscreen " + options.icons['fullscreen'],
1107        title: options.text.toggleFullscreen,
1108        html: "<span>" + options.text.toggleFullscreen + "</span>"
1109
1110      }).on("click", ui.switchFullscreen);
1111
1112      var fit = ui.fit = $(html.div, {
1113
1114        class: buttonClass + " " + uiClass + "-fit " + options.icons['fitscreen']
1115
1116      }).on("click", function () {
1117
1118        $(this).toggleClass("df-button-fit-active");
1119
1120      });
1121      sizeControls.append(fullScreen);
1122
1123      var controls = $(html.div, {
1124        class: wrapperClass + " " + uiClass + "-controls"
1125      });
1126
1127      var shareBox = ui.shareBox = new DFLIP.Share(container, options);
1128
1129      var share = ui.share = $(html.div, {
1130
1131        class: buttonClass + " " + uiClass + "-share " + options.icons['share'],
1132        title: options.text.share,
1133        html: "<span>" + options.text.share + "</span>"
1134
1135      }).on("click", function (event) {
1136        if (ui.shareBox.isOpen == true)
1137          ui.shareBox.close();
1138        else {
1139          ui.shareBox.update(object.getURLHash());
1140          ui.shareBox.show();
1141        }
1142      });
1143
1144      var start = ui.startPage = $(html.div, {
1145
1146        class: buttonClass + " " + uiClass + "-start " + (isRTL ? options.icons['end'] : options.icons['start']),
1147        title: options.text.gotoFirstPage,
1148        html: "<span>" + options.text.gotoFirstPage + "</span>"
1149
1150      }).on("click", function () {
1151
1152        object.start();
1153
1154      });
1155
1156
1157      var end = ui.endPage = $(html.div, {
1158
1159        class: buttonClass + " " + uiClass + "-end " + (isRTL ? options.icons['start'] : options.icons['end']),
1160        title: options.text.gotoLastPage,
1161        html: "<span>" + options.text.gotoLastPage + "</span>"
1162
1163      }).on("click", function () {
1164
1165        object.end();
1166
1167      });
1168
1169      var pageModeButton = ui.pageMode = $(html.div, {
1170
1171        class: buttonClass + " " + uiClass + "-pagemode " + options.icons['singlepage'],
1172        html: "<span>" + options.text.singlePageMode + "</span>"
1173
1174      }).on("click", function () {
1175
1176        var el = $(this);
1177        object.setPageMode(!el.hasClass(options.icons['doublepage']));
1178
1179      });
1180
1181
1182      object.setPageMode(object.target.pageMode == DFLIP.PAGE_MODE.SINGLE)
1183      //moreContainer.append(pageModeButton).append(start).append(end).append(sound);
1184
1185      var altPrev = ui.altPrev = $(html.div, {
1186
1187        class: buttonClass + " " + uiClass + "-prev" + " " + uiClass + "-alt " + options.icons['prev'],
1188        title: isRTL ? options.text.nextPage : options.text.previousPage,
1189        html: "<span>" + options.text.previousPage + "</span>"
1190
1191      }).on("click", function () {
1192        object.prev();
1193      });
1194
1195      var altNext = ui.altNext = $(html.div, {
1196
1197        class: buttonClass + " " + uiClass + "-next" + " " + uiClass + "-alt " + options.icons['next'],
1198        title: isRTL ? options.text.previousPage : options.text.nextPage,
1199        html: "<span>" + options.text.nextPage + "</span>"
1200
1201      }).on("click", function () {
1202        object.next();
1203      });
1204
1205      var thumbnail = ui.thumbnail = $(html.div, {
1206
1207        class: buttonClass + " " + uiClass + "-thumbnail " + options.icons['thumbnail'],
1208        title: options.text.toggleThumbnails,
1209        html: "<span>" + options.text.toggleThumbnails + "</span>"
1210
1211      }).on("click", function () {
1212        var $this = $(this);
1213        if (object.target.thumbContainer) {
1214          var thumbContainer = object.target.thumbContainer;
1215          thumbContainer.toggleClass("df-sidemenu-visible");
1216          $this.toggleClass("df-active");
1217        }
1218        else {
1219          object.contentProvider.initThumbs();
1220          $this.toggleClass("df-active");
1221        }
1222        if ($this.hasClass("df-active")) {
1223          $this.siblings(".df-active").trigger("click");
1224        }
1225        ui.update(true);
1226      });
1227
1228      var outline = ui.outline = $(html.div, {
1229
1230        class: buttonClass + " " + uiClass + "-outline " + options.icons['outline'],
1231        title: options.text.toggleOutline,
1232        html: "<span>" + options.text.toggleOutline + "</span>"
1233
1234      }).on("click", function () {
1235        var $this = $(this);
1236        if (object.target.outlineContainer) {
1237          var outlineContainer = object.target.outlineContainer;
1238          $this.toggleClass("df-active");
1239          outlineContainer.toggleClass("df-sidemenu-visible");
1240          if ($this.hasClass("df-active")) {
1241            $this.siblings(".df-active").trigger("click");
1242          }
1243          ui.update(true);
1244        }
1245      });
1246
1247      /**
1248       * Controls position and pplace ment is determined by options.moreControls and options.hideControls
1249       */
1250      var allControls = options.allControls.replace(/ /g, '').split(','),
1251        moreControls = "," + options.moreControls.replace(/ /g, '') + ",",
1252        hideControls = "," + options.hideControls.replace(/ /g, '') + ",";
1253
1254      var moreControlsArray = moreControls.split(',');
1255
1256      for (var controlCount = 0; controlCount < allControls.length; controlCount++) {
1257        //if hidden skip
1258        var controlName = allControls[controlCount];
1259        if (hideControls.indexOf("," + controlName + ",") < 0) { //not found in hide list
1260          var control = ui[controlName];
1261          if (control != null) {
1262            if (moreControls.indexOf("," + controlName + ",") > -1 && controlName !== 'more' && controlName !== 'pageNumber') {//found in more controls
1263              moreContainer.append(control);
1264            }
1265            else {
1266              controls.append(control);
1267            }
1268          }
1269        }
1270      }
1271
1272      container.append(controls).append(prev).append(next).append(zoom);
1273
1274      var ctrlDown = false, shiftDown = false, altDown = false;
1275      var shiftKey = 16, ctrlKey = 17, altKey = 18, sKey = 83, vKey = 86, cKey = 67, eKey = 69, gKey = 71, nKey = 78,
1276        oKey = 79, deleteKey = 46, rightKey = 39, leftKey = 37, escKey = 27;
1277
1278      document.addEventListener('keyup', onKeyUp, false);
1279
1280      function onKeyUp(event) {
1281        switch (event.keyCode) {
1282          case escKey:
1283            if (ui.isFullscreen == true) ui.fullScreen.trigger("click");
1284            break;
1285          case shiftKey:
1286            shiftDown = false;
1287            break;
1288          case ctrlKey:
1289            ctrlDown = false;
1290            break;
1291          case altKey:
1292            altDown = false;
1293            break;
1294          case leftKey:
1295            object.prev();
1296            break;
1297          case rightKey:
1298            object.next();
1299            break;
1300          default:
1301            break;
1302        }
1303        //log(event.keyCode);
1304      }
1305
1306      ui.update = function (resize) {
1307        log("ui update");
1308        var target = object.target;
1309
1310        var pageNumber = validPage(target._activePage || object._activePage);
1311        var pageCount = target.pageCount || object.pageCount;
1312
1313        var isRTL = target.direction == DFLIP.DIRECTION.RTL,
1314          isStart = (pageNumber == 1 || pageNumber == 0),
1315          isEnd = pageNumber == pageCount;
1316
1317        ui.next.show();
1318        ui.prev.show();
1319        ui.altNext.removeClass("disabled");
1320        ui.altPrev.removeClass("disabled");
1321
1322        if ((isStart && !isRTL) || (isEnd && isRTL)) {
1323          ui.prev.hide();
1324          ui.altPrev.addClass("disabled");
1325        }
1326        if ((isEnd && !isRTL) || (isStart && isRTL)) {
1327          ui.next.hide();
1328          ui.altNext.addClass("disabled");
1329        }
1330
1331        ui.pageInput.val(pageNumber);
1332        ui.pageLabel.html((pageNumber) + "/" + pageCount);
1333
1334
1335        if (container.find(".df-sidemenu-visible").length > 0) {
1336          container.addClass("df-sidemenu-open");
1337        }
1338        else {
1339          container.removeClass("df-sidemenu-open");
1340        }
1341        if (resize == true)
1342          object.resize();
1343
1344        if (target.contentProvider.zoomScale == target.contentProvider.maxZoom) {
1345          ui.zoomIn.addClass("disabled");
1346        }
1347        else {
1348          ui.zoomIn.removeClass("disabled");
1349        }
1350
1351        if (target.contentProvider.zoomScale == 1) {
1352          ui.zoomOut.addClass("disabled");
1353        }
1354        else {
1355          ui.zoomOut.removeClass("disabled");
1356        }
1357
1358      };
1359
1360      if (object.target != null) {
1361        object.target.ui = ui;
1362      }
1363
1364      if (options.onCreateUI != null)
1365        options.onCreateUI(object);
1366    }
1367  ;
1368
1369  var PreviewStage = null;
1370  //later updated via RegisterMockupObjects in case 3d is requested
1371
1372  //Registers necessary mockup object when required
1373  function RegisterMockupObjects() {
1374
1375    PreviewStage = (function (_super) {
1376      __extends(PreviewStage, _super);
1377
1378      function PreviewStage(parameters) {
1379        parameters = parameters || {};
1380        var _this = this;
1381        _super.call(this, parameters);
1382        _this.options = parameters;
1383        _this.canvas = $(_this.renderer.domElement).addClass("df-3dcanvas");
1384        _this.container = parameters.container;
1385        _this.container.append(_this.canvas);
1386        //_this.container.height(parameters.height);
1387        _this.type = "PreviewStage";
1388        _this.mouse = new THREE.Vector2();
1389        _this.raycaster = new THREE.Raycaster();
1390
1391        _this.camera.position.set(0, 20, 600);
1392        _this.camera.lookAt(new THREE.Vector3(0, 0, 0));
1393
1394        //shadows are zigzap due to shadow camera position
1395        _this.spotLight.position.set(-220, 330, 550);
1396
1397        _this.spotLight.castShadow = isMobile ? false : parameters.webglShadow;
1398        //_this.spotLight.shadowDarkness = 0.6;
1399        if (_this.spotLight.shadow) {
1400          _this.spotLight.shadow.bias = -0.0008;
1401        }
1402        _this.spotLight.intensity = isset(parameters.spotLightIntensity, defaults.spotLightIntensity);
1403        _this.ambientLight.color = new THREE.Color(isset(parameters.ambientLightColor, defaults.ambientLightColor));
1404        _this.ambientLight.intensity = isset(parameters.ambientLightIntensity, defaults.ambientLightIntensity);
1405
1406        var material = new THREE.ShadowMaterial();
1407        material.opacity = isset(parameters.shadowOpacity, defaults.shadowOpacity);
1408
1409        _this.ground.material = material;
1410        _this.ground.position.z = -2;
1411
1412        //Restrict right left camera movement.
1413        _this.orbitControl.maxAzimuthAngle = 0;
1414        _this.orbitControl.minAzimuthAngle = 0;
1415
1416        _this.orbitControl.minPolarAngle = Math.PI / 2;
1417        _this.orbitControl.maxPolarAngle = 2.2;
1418
1419        //_this.orbitControl.maxPolarAngle = 10;
1420        _this.orbitControl.mouseButtons.ORBIT = THREE.MOUSE.RIGHT;
1421        _this.orbitControl.mouseButtons.PAN = -1;
1422        _this.orbitControl.maxDistance = 5000;
1423        _this.orbitControl.minDistance = 50;
1424        _this.orbitControl.noZoom = true;
1425
1426        _this.selectiveRendering = true;
1427
1428        _this.orbitControl.zoomSpeed = 5;
1429
1430        _this.orbitControl.keyPanSpeed = 0;
1431        _this.orbitControl.center.set(0, 0, 0);
1432        _this.orbitControl.update();
1433
1434        _this.swipe_threshold = isMobile ? 15 : 20;
1435
1436        var cssRenderer = _this.cssRenderer = new THREE.CSS3DRenderer();
1437        $(cssRenderer.domElement).css({
1438          position: "absolute",
1439          top: 0,
1440          pointerEvents: "none"
1441        }).addClass("df-3dcanvas df-csscanvas");
1442        _this.container[0].appendChild(cssRenderer.domElement);
1443
1444        var cssScene = _this.cssScene = new THREE.Scene();
1445
1446        var divLeftDOM = document.createElement("div");
1447        divLeftDOM.className = "df-page-content df-page-content-left";
1448
1449        var divRightDOM = document.createElement("div");
1450        divRightDOM.className = "df-page-content df-page-content-right";
1451
1452        var divLeft = cssScene.divLeft = new THREE.CSS3DObject(divLeftDOM);
1453        var divRight = cssScene.divRight = new THREE.CSS3DObject(divRightDOM);
1454        cssScene.add(divLeft);
1455        cssScene.add(divRight);
1456
1457        _this.resizeCallback = function () {
1458          cssRenderer.setSize(_this.canvas.width(), _this.canvas.height());
1459        };
1460
1461        function requestRender() {
1462          _this.renderRequestPending = true;
1463        }
1464
1465        window.addEventListener(mouseEvents.move, requestRender, false);
1466
1467        window.addEventListener('keyup', requestRender, false);
1468
1469
1470        _this.dispose = function () {
1471
1472          _this.clearChild();
1473          _this.render();
1474
1475          window.removeEventListener(mouseEvents.move, requestRender, false);
1476
1477          if (_this.options.scrollWheel == true) {
1478            _this.container[0].removeEventListener('mousewheel', onMouseWheel, false);
1479            _this.container[0].removeEventListener('DOMMouseScroll', onMouseWheel, false); // firefox
1480          }
1481
1482          window.removeEventListener('keyup', requestRender, false);
1483
1484          _this.renderer.domElement.removeEventListener("mousemove", editor_mouseMove, false);
1485          _this.renderer.domElement.removeEventListener("touchmove", editor_mouseMove, false);
1486
1487          _this.renderer.domElement.removeEventListener("mousedown", editor_mouseDown, false);
1488          _this.renderer.domElement.removeEventListener("touchstart", editor_mouseDown, false);
1489          _this.renderer.domElement.removeEventListener("mouseup", editor_mouseUp, false);
1490          _this.renderer.domElement.removeEventListener("touchend", editor_mouseUp, false);
1491
1492
1493          _this.canvas.remove();
1494
1495          cssRenderer.domElement.parentNode.removeChild(cssRenderer.domElement);
1496
1497          cssRenderer = null;
1498
1499          _this.renderCallback = null;
1500          _this.renderCallback = null;
1501          _this.orbitControl.dispose();
1502          _this.orbitControl = null;
1503
1504
1505          _this.renderer.dispose();
1506
1507          _this.cancelRAF();
1508        };
1509
1510        _this.renderCallback = function () {
1511          if (TWEEN.getAll().length > 0)
1512            _this.renderRequestPending = true;
1513          TWEEN.update();
1514          cssRenderer.render(cssScene, _this.camera)
1515        };
1516
1517        var onMouseWheel = function (event) {
1518          var delta = 0;
1519
1520          if (event.wheelDelta != null) { // WebKit / Opera / Explorer 9
1521
1522            delta = event.wheelDelta;
1523
1524          }
1525          else if (event.detail != null) { // Firefox
1526
1527            delta = -event.detail;
1528
1529          }
1530          if (delta) {
1531            var currentZoom = _this.previewObject.contentProvider.zoomScale;
1532            if ((delta > 0 && currentZoom == 1)
1533              || (delta < 0 && currentZoom > 1)) {
1534              event.preventDefault();
1535            }
1536            _this.previewObject.zoom(delta > 0 ? 1 : -1);
1537          }
1538
1539          requestRender();
1540        };
1541
1542        var editor_mouseMove = function (event) {
1543
1544          _this.renderRequestPending = true;
1545          event = fixMouseEvent(event);
1546          if (_this.isMouseDown && event.movementX != 0 && event.movementY != 0) {
1547            _this.isMouseMoving = true;
1548          }
1549          if (event.touches != null && event.touches.length == 2 && _this.startTouches != null) {
1550            //return;
1551            // _this.startTouches = event.touches;
1552            _this.zoomDirty = true;
1553            var touchCenter = utils.getVectorAvg(utils.getTouches(event, _this.container.offset())),
1554              newScale = utils.calculateScale(_this.startTouches, utils.getTouches(event)),
1555              scale = newScale / _this.lastScale;
1556
1557            var zoom = _this.previewObject.contentProvider.zoomScale,
1558              x = touchCenter.x,
1559              y = touchCenter.y;
1560
1561            _this.camera.position.z = _this.originalZ / (newScale);
1562            _this.lastScale = newScale;
1563
1564            _this.lastZoomCenter = touchCenter;
1565            event.preventDefault();
1566            return;
1567          }
1568          if (_this.isMouseDown == true && _this.previewObject.contentProvider.zoomScale == 1) {
1569            //check if swipe has happened
1570
1571            var swipe_dist = event.pageX - _this.lastPos,
1572              swipe_time = performance.now() - _this.lastTime;
1573
1574            //$("body > p").html(swipe_dist);
1575
1576            if (Math.abs(swipe_dist) > _this.swipe_threshold) {
1577              //swipe has triggered
1578              //_this.dragPage.pendingPoint = point;
1579              if (swipe_dist < 0) {
1580                _this.target.next();
1581              }
1582              else {
1583                _this.target.prev();
1584              }
1585              event.preventDefault();
1586              _this.isMouseDown = false;
1587            }
1588            _this.lastPos = event.pageX;
1589            _this.lastTime = performance.now();
1590
1591          }
1592        };
1593
1594        var editor_mouseDown = function (event) {
1595          event = fixMouseEvent(event);
1596          if (event.touches != null && event.touches.length == 2 && _this.startTouches == null) {
1597            _this.startTouches = utils.getTouches(event);
1598            _this.lastScale = 1;
1599            _this.originalZ = _this.camera.position.z * 1;
1600          }
1601          document.activeElement.blur();
1602          _this.mouseValue = event.pageX + "," + event.pageY;
1603          _this.isMouseMoving = false;
1604          _this.isMouseDown = true;
1605          _this.lastPos = event.pageX;
1606          _this.lastTime = performance.now();
1607        };
1608
1609        var editor_click = function (event) {
1610          _this.isMouseDown = false;
1611          //bail out if it's not left click
1612          if (event.button !== 0) return this;
1613          var mouseValue = event.pageX + "," + event.pageY;
1614
1615          if (_this.isMouseMoving) {
1616
1617          }
1618          else if (mouseValue == _this.mouseValue) {
1619            event = event || window.event;
1620            event = $.event.fix(event);
1621
1622            var mouse = _this.mouse, raycaster = _this.raycaster;
1623            mouse.x = ((event.offsetX) / _this.canvas.innerWidth()) * 2 - 1;
1624            mouse.y = 1 - ((event.offsetY) / _this.canvas.innerHeight()) * 2;
1625
1626            raycaster.setFromCamera(mouse, _this.camera);
1627
1628            var intersects = raycaster.intersectObjects(_this.target instanceof MOCKUP.Bundle
1629                                                        ? _this.target.children : [_this.target], true);
1630
1631            if (intersects.length > 0) {
1632
1633              var object, objectCount = 0;
1634              do {
1635                object = intersects[objectCount] != null ? intersects[objectCount].object : null;
1636                //bookStage.clickFace = intersects[objectCount].face;
1637                objectCount++;
1638              } while ((object instanceof THREE.BoxHelper || !(object instanceof MOCKUP.Paper) || object.isFlipping == true) && objectCount < intersects.length);
1639
1640              //if (object.parent instanceof  MOCKUP.Bundle) {
1641              //    object = object.parent;
1642              //}
1643
1644              if (object.userData.object != null) {
1645
1646                // helper
1647
1648                //bookStage.selectObject(object.userData.object);
1649
1650              }
1651              else {
1652
1653                if (object.angles[1] > 90) {
1654                  if (object.isEdge != true) _this.target.next();
1655                }
1656                else {
1657                  if (object.isEdge != true) _this.target.prev();
1658                }
1659
1660              }
1661
1662            }
1663            else {
1664
1665              //bookStage.selectObject(null);
1666
1667            }
1668          }
1669          //bookStage.stage.render();
1670        };
1671
1672        var editor_mouseUp = function (event) {
1673          event = fixMouseEvent(event);
1674          if (event.touches != null && event.touches.length == 0) {
1675            var zoom = _this.previewObject.contentProvider.zoomScale;
1676            if (_this.zoomDirty == true) {
1677              _this.previewObject.contentProvider.zoomScale =
1678                utils.limitAt(_this.previewObject.contentProvider.zoomScale * _this.lastScale,
1679                  1, _this.previewObject.contentProvider.maxZoom);
1680              _this.previewObject.zoomValue = _this.previewObject.contentProvider.zoomScale * 1;
1681              //_this.previewObject.zoom(_this.lastScale < 1 ? -1 : 1);
1682              //console.log(_this.previewObject.contentProvider.zoomScale * _this.lastScale,_this.previewObject.contentProvider.maxZoom)
1683              //_this.previewObject.pendingZoom = true;
1684              _this.previewObject.resize();
1685              _this.zoomDirty = false;
1686            }
1687
1688            _this.lastScale = null;
1689            _this.startTouches = null;
1690          }
1691          if (event.touches != null && event.touches.length > 1) return;
1692          editor_click(event);
1693        };
1694        //if (MOCKUP.mode !== MOCKUP.MODE.PLUGIN) {
1695
1696        //_this.renderer.domElement.addEventListener('click', editor_click, false);
1697        //bookStage.renderer.domElement.addEventListener('dblclick', editor_dblclick, false);
1698        _this.renderer.domElement.addEventListener("mousemove", editor_mouseMove, false);
1699        _this.renderer.domElement.addEventListener("touchmove", editor_mouseMove, false);
1700
1701        _this.renderer.domElement.addEventListener("mousedown", editor_mouseDown, false);
1702        _this.renderer.domElement.addEventListener("touchstart", editor_mouseDown, false);
1703        _this.renderer.domElement.addEventListener("mouseup", editor_mouseUp, false);
1704        _this.renderer.domElement.addEventListener("touchend", editor_mouseUp, false);
1705        if (_this.options.scrollWheel == true) {
1706          _this.container[0].addEventListener('mousewheel', onMouseWheel, false);
1707          _this.container[0].addEventListener('DOMMouseScroll', onMouseWheel, false); // firefox
1708        }
1709
1710        //}
1711
1712        $(_this.renderer.domElement).css({display: "block"});
1713
1714        $(window).trigger("resize");
1715
1716        return this;
1717      }
1718
1719      PreviewStage.prototype.width = function () {
1720        return this.container.width();
1721      };
1722
1723      PreviewStage.prototype.height = function () {
1724        return this.container.height();
1725      };
1726
1727      return PreviewStage;
1728
1729    })(MOCKUP.Stage);
1730    MOCKUP.PreviewStage = PreviewStage;
1731
1732    var BookPaper = (function (_super) {
1733      __extends(BookPaper, _super);
1734
1735      function BookPaper(parameters, stage) {
1736        parameters = parameters || {};
1737        parameters.folds = 1;
1738        _super.call(this, parameters, stage);
1739        this.angle = 0;
1740        this.isFlipping = false;
1741        this.material.materials[5].transparent = true;
1742        this.material.materials[4].transparent = true;
1743        this.type = "BookPaper";
1744      }
1745
1746      BookPaper.prototype.tween = function (oldAngle, newAngle) {
1747        var page = this;
1748        var epsilon = 0.00001;
1749        page.originalStiff = page.stiffness;
1750        var oldTarget = page.newStiffness;
1751        var isBooklet = isBookletMode(page.parent);
1752        //console.log(page.stiffness);
1753        var diff = newAngle - oldAngle;//170 -5 == 165 :  5-170 = -165
1754
1755        var isRight = oldAngle > 90;
1756        var isRTL = page.parent.direction == DFLIP.DIRECTION.RTL;
1757        page.init = {
1758          angle: oldAngle,
1759          angle2: (oldAngle < 90 ? 0 : 180),
1760          stiff: page.originalStiff,
1761          index: (isRight && !isRTL) || (!isRight && isRTL) ? 1 : 0
1762        };
1763        page.first = {
1764          angle: oldAngle + diff / 4,
1765          angle2: (oldAngle < 90 ? 90 : 90),
1766          stiff: page.originalStiff,
1767          index: (isRight && !isRTL) || (!isRight && isRTL) ? 1 : 0.25
1768        };
1769        page.mid = {
1770          angle: oldAngle + diff * 2 / 4,
1771          angle2: (oldAngle < 90 ? 135 : 45),
1772          stiff: page.newStiffness,
1773          index: (isRight && !isRTL) || (!isRight && isRTL) ? 0.5 : 0.5
1774        };
1775        page.mid2 = {
1776          angle: oldAngle + diff * 3 / 4,
1777          angle2: (oldAngle < 90 ? 180 : 0),
1778          stiff: page.newStiffness,
1779          index: (isRight && !isRTL) || (!isRight && isRTL) ? 0.25 : 1
1780        };
1781        page.end = {
1782          angle: newAngle,
1783          angle2: (oldAngle < 90 ? 180 : 0),
1784          stiff: page.newStiffness,
1785          index: (isRight && !isRTL) || (!isRight && isRTL) ? 0 : 1
1786        };
1787
1788        //console.log(page.init, page.first, page.mid, page.end);
1789        page.isFlipping = true;
1790
1791        var update = function (tween, event) {
1792
1793          page.angles[1] = tween.angle;
1794          page.angles[4] = page.isHard ? tween.angle : tween.angle2;
1795          if (page.isHard == true) {
1796            page.stiffness = 0;
1797          }
1798          else {
1799            page.stiffness = tween.stiff / (oldTarget + epsilon) * (page.newStiffness + epsilon);
1800            page.stiffness = isNaN(page.stiffness) ? 0 : tween.stiff;
1801          }
1802          if (isBooklet) {
1803            page.material.materials[5].opacity = page.material.materials[4].opacity = tween.index;
1804            page.castShadow = (isRight && !isRTL) || (!isRight && isRTL) ? tween.index > 0.5 : tween.index > 0.5;
1805          }
1806          //check if any sibling is flipping and their stiff is more that this
1807
1808          page.updateAngle(true);
1809
1810        };
1811
1812        if (isBooklet && ((!isRight && !isRTL) || (isRight && isRTL))) {
1813          page.material.materials[5].opacity = page.material.materials[4].opacity = 0;
1814          page.castShadow = false;
1815        }
1816
1817        page.currentTween = new TWEEN.Tween(page.init)
1818          .to({
1819            angle: [page.first.angle, page.mid.angle, page.mid2.angle, page.end.angle],
1820            angle2: [page.first.angle2, page.mid.angle2, page.mid2.angle2, page.end.angle2],
1821            stiff: [page.first.stiff, page.mid.stiff, page.mid2.stiff, page.end.stiff],
1822            index: [page.first.index, page.mid.index, page.mid2.index, page.end.index]
1823          }, page.parent.duration)
1824          .onUpdate(function (event) {
1825            update(this, event);
1826          }).easing(TWEEN.Easing.Sinusoidal.Out)
1827          .onComplete(function (event) {
1828            page.stiffness = page.newStiffness;
1829            page.updateAngle();
1830            page.material.materials[5].opacity = page.material.materials[4].opacity = 1;
1831            page.castShadow = true;
1832            page.isFlipping = false;
1833            if (page.parent && page.parent.refresh)
1834              page.parent.refresh();
1835            //console.log(page.stiffness);
1836          }).start();
1837
1838      };
1839
1840      return BookPaper;
1841    })(MOCKUP.FlexBoxPaper);
1842    MOCKUP.BookPaper = BookPaper;
1843
1844    var Book = (function (_super) {
1845      __extends(Book, _super);
1846
1847      function Book(parameters, stage) {
1848
1849        parameters = parameters || {};
1850        parameters.segments = parameters.segments || 50;
1851        this.pageCount = parameters.pageCount;
1852
1853        this.height = parameters.height;
1854        this.width = parameters.width;
1855
1856        //correcting page count as multiple of 2
1857        this.pageCount = (this.pageCount == 1 ? this.pageCount : Math.
1857ceil(this.pageCount / 2) * 2);
1858
1859        this.direction = parameters.direction || DFLIP.DIRECTION.LTR;
1860
1861        this.startPage = 1;
1862        this.endPage = this.pageCount;
1863
1864        this.stackCount = parameters.stackCount || 6;// = 15;
1865        this.materials = [];
1866
1867        _super.call(this, parameters, stage);
1868        this.angles = [0, 0, 0, 0, 0, 0];
1869        this.stiffness = parameters.stiffness == null ? 1.5 : parameters.stiffness; //so that 0 can be set
1870        this.hardConfig = parameters.hard; //hard is not that good in 3d
1871        this._activePage = parameters.openPage || this.startPage;
1872
1873        this.createStack(parameters);
1874        this.pageMode = parameters.pageMode || ((isMobile || this.pageCount <= 2) ? DFLIP.PAGE_MODE.SINGLE
1875                                                                                  : DFLIP.PAGE_MODE.DOUBLE);
1876
1877        this.singlePageMode = parameters.singlePageMode || (isMobile ? DFLIP.SINGLE_PAGE_MODE.BOOKLET
1878                                                                     : DFLIP.SINGLE_PAGE_MODE.ZOOM);
1879
1880
1881        this.type = "Book";
1882
1883      }
1884
1885      Book.prototype.getPageByNumber = function (pageNumber) {
1886        var relativePageNumber = isBookletMode(this) ? (isRTLMode(this) ? pageNumber + 1 : pageNumber)
1887                                                     : Math.floor((pageNumber - 1) / 2);
1888        return this.getObjectByName(relativePageNumber.toString());
1889      };
1890
1891      Book.prototype.isPageHard = function (pageNumber) {
1892
1893        return utils.isHardPage(this.hardConfig, pageNumber, this.pageCount);
1894
1895      };
1896
1897      Book.prototype.activePage = function (pageNumber) {
1898        if (pageNumber == null) return this._activePage;
1899        this.gotoPage(pageNumber);
1900      };
1901
1902      Book.prototype.gotoPage = function (pageNumber) {
1903        pageNumber = parseInt(pageNumber, 10);
1904        this._activePage = pageNumber;
1905        if (this.autoPlay == true) {
1906          this.previewObject.setAutoPlay(this.autoPlay);
1907        }
1908        this.updatePage(pageNumber);
1909        if (this && this.thumblist && this.thumblist.review)
1910          this.thumblist.review();
1911      };
1912
1913
1914      Book.prototype.moveBy = function (step) {
1915        var nextPage = this._activePage + step;
1916        nextPage = limitAt(nextPage, this.startPage, this.endPage);
1917        if (this.firstFlipped != true) {
1918          this.previewObject.analytics({
1919            eventAction: "First Page Flip",
1920            options: this.previewObject.options
1921          });
1922          this.firstFlipped = true;
1923        }
1924        this.gotoPage(nextPage);
1925      };
1926
1927      Book.prototype.next = function (step) {
1928        if (step == null)
1929          step =
1930            (this.direction == DFLIP.DIRECTION.RTL)
1931            ? -this.pageMode : this.pageMode;
1932
1933        this.moveBy(step);
1934      };
1935
1936      Book.prototype.prev = function (step) {
1937        if (step == null)
1938          step =
1939            (this.direction == DFLIP.DIRECTION.RTL)
1940            ? this.pageMode : -this.pageMode;
1941
1942        this.moveBy(step);
1943      };
1944
1945      Book.prototype.updateAngle = function () {
1946
1947        var startAngle = this.angles[1];
1948        var endAngle = this.angles[4];
1949
1950        var spreadAngle = endAngle - startAngle;
1951        var stacks = this.stackCount;
1952
1953        for (var _stackCount = 0; _stackCount < stacks; _stackCount++) {
1954          var clone = this.children[_stackCount];
1955          //start from angle[1] and end at angles[4]
1956          clone.angles[1] = startAngle + _stackCount * spreadAngle / (stacks * 100);
1957          clone.stiffness = this.stiffness;//_stackCount/stacks;
1958          clone.updateAngle();
1959        }
1960
1961      };
1962
1963      Book.prototype.refresh = function () {
1964        this.updatePage(this._activePage);
1965        if (this.flipCallback != null) this.flipCallback();
1966      };
1967
1968
1969      Book.prototype.updatePage = function (pageNumber) {
1970        // this.contentProvider.setLoading(pageNumber, true);
1971        var isRTL = (this.direction == DFLIP.DIRECTION.RTL),
1972          isBooklet = isBookletMode(this),
1973          newBaseNumber = getBasePage(pageNumber);
1974
1975        var pageDivisor = isBooklet ? 1 : 2;
1976
1977        pageNumber = Math.floor((pageNumber / pageDivisor));
1978
1979        if (isRTL) pageNumber = this.pageCount / pageDivisor - pageNumber;
1980
1981        var oldBaseNumber = this.oldBaseNumber || 0;
1982        var pageCount = this.pageCount / pageDivisor;
1983        var stackCount = this.stackCount;
1984        var angleShift = 0.02;
1985        var depth = 0.4;
1986        var stiffFactor = isBooklet ? 0
1987                                    : (0.5 - Math.abs(pageCount / 2 - pageNumber) / pageCount) / this.stiffness;
1988        var positionFactor = 1;//(stiffFactor +width);
1989        // var centre = Math.floor(stackCount / 2);
1990        var midPoint = Math.floor(stackCount / 2);//pageNumber < centre ? pageNumber //starting center pages
1991        // : ((pageCount - pageNumber > centre) ? centre //other pages
1992        //: (pageNumber + centre - pageCount)) ;//remainig center page
1993        //console.log(midPoint);
1994
1995        //var targetIndex = midPoint;
1996        //if(midPoint == centre) {
1997        /*This sitaution is good when there is icrement or decrement by 1*/
1998        var isLeft = false;
1999        if (oldBaseNumber > pageNumber) {
2000          isLeft = true;
2001          this.children[stackCount - 1].skipFlip = true;
2002          this.children.unshift(this.children.pop());
2003
2004          // this.contentProvider.setLoading(pageNumber, true);
2005        }
2006        else if (oldBaseNumber < pageNumber) {
2007          this.children[0].skipFlip = true;
2008          this.children.push(this.children.shift());
2009
2010          // this.contentProvider.setLoading(pageNumber, true);
2011        }
2012
2013        var remainingPages = (pageCount - pageNumber);
2014        var stackDepth = (5) / pageCount;
2015        var leftDepth = stackDepth * pageNumber / 2;
2016        var rightDepth = stackDepth * remainingPages / 2;
2017        var maxDepth = (leftDepth < rightDepth ? rightDepth : leftDepth);
2018        //maxDepth = maxDepth > 5 ? 5: maxDepth;
2019        for (var _pageCount = 0; _pageCount < stackCount; _pageCount++) {
2020          var page = this.children[_pageCount];//this.getObjectByName("page"+_pageCount);//this.children[_pageCount];
2021
2022          var color = page.color;
2023          var oldAngle = page.angles[1];
2024          var newAngle;
2025          var relativePageNumber = pageNumber - midPoint + _pageCount;
2026          if (isRTL) relativePageNumber = isBooklet ? this.pageCount - relativePageNumber
2027                                                    : Math.floor(this.pageCount / 2) - relativePageNumber - 1;
2028
2029          var isHard = page.isHard = this.isPageHard(relativePageNumber);
2030          var oldName = page.name;
2031
2032
2033          //Sizing
2034          page.isEdge = false; //true;
2035          if (_pageCount == 0) {
2036            page.depth = leftDepth < depth ? depth : leftDepth;
2037          }
2038          else if (_pageCount == stackCount - 1) {
2039            page.depth = rightDepth < depth ? depth : rightDepth;
2040          }
2041          else {
2042            page.depth = depth;
2043            page.isEdge = false;
2044          }
2045          if (page.isFlipping == true) {
2046            page.depth = depth;
2047          }
2048          page.position.x = 0;
2049
2050          var leftAngle = angleShift * _pageCount,
2051            rightAngle = 180 - angleShift * (_pageCount - midPoint) + angleShift * _pageCount;
2052
2053          if (_pageCount < midPoint) {
2054            page.newStiffness = isHard || this.stiffness == 0 ? 0 : stiffFactor / (pageNumber / pageCount) / 4;
2055            newAngle = leftAngle;
2056            page.position.z = maxDepth - (-_pageCount + midPoint) * depth;//(pageNumber < pageCount / 2)
2057            if (isLeft == true) page.position.z -= depth;
2058
2059          }
2060          else {
2061            newAngle = rightAngle;
2062            page.newStiffness = isHard || this.stiffness == 0 ? 0
2063                                                              : stiffFactor / (Math.abs(pageCount - pageNumber) / pageCount) / 4;
2064            page.position.z = (maxDepth - (-stackCount + _pageCount + midPoint + 1) * depth) - page.depth;//(pageNumber < pageCount / 2)
2065
2066          }
2067
2068          if (page.isFlipping == false) {
2069
2070            if (Math.abs(oldAngle - newAngle) > 20 && page.skipFlip == false) {
2071              page.depth = depth;
2072              //we need predicted stiffness so that there is no overlap issues
2073              var predicted = page.stiffness;
2074
2075              if (oldAngle > newAngle) {//left
2076                predicted = stiffFactor / (Math.abs(pageCount - pageNumber) / pageCount) / 4;
2077              }
2078              else {//right
2079                predicted = stiffFactor / (pageNumber / pageCount) / 4;
2080              }
2081              page.position.z += depth;//((_pageCount < midPoint) ? 0 : depth) * 2;/// 2;
2082
2083              page.stiffness = isNaN(predicted) ? page.stiffness : predicted;
2084              page.updateAngle(true);
2085              page.targetStiffness = isHard ? 0 : (_pageCount < pageNumber)
2086                                                  ? stiffFactor / (Math.abs(pageCount - pageNumber) / pageCount) / 4
2087                                                  : stiffFactor / (pageNumber / pageCount) / 4;
2088
2089              page.targetStiffness = isHard ? 0 : (isNaN(page.targetStiffness) ? page.stiffness : page.targetStiffness);
2090
2091              page.isFlipping = true;
2092
2093              page.tween(oldAngle, newAngle);
2094
2095              if (this.preFlipCallback != null)
2096                this.preFlipCallback();
2097            }
2098            else {
2099              page.skipFlip = false;
2100              page.newStiffness = isNaN(page.newStiffness) ? 0 : page.newStiffness;
2101              if (page.angles[1] != newAngle || page.stiffness != page.newStiffness || page.depth != page.oldDepth) {
2102                page.angles[1] = page.angles[4] = newAngle;
2103                page.stiffness = page.newStiffness;
2104                page.updateAngle(true);
2105              }
2106              else {
2107                //console.log("skipped");
2108              }
2109            }
2110          }
2111
2112          page.visible = isBooklet
2113                         ? (isRTL
2114
2115                            ? (_pageCount < midPoint || page.isFlipping)
2116                            : (_pageCount >= midPoint || page.isFlipping))
2117
2118                         : ((relativePageNumber >= 0 && relativePageNumber < pageCount) || (isBooklet && relativePageNumber == pageCount));
2119
2120
2121          if (this.requestPage != null) {
2122            page.name = relativePageNumber.toString();
2123            if (page.name != oldName) {
2124
2125              page.textureLoaded = false;
2126              page.frontImage(defaults.textureLoadFallback);
2127              page.frontPageStamp = "-1";
2128              page.frontTextureLoaded = false;
2129              page.thumbLoaded = false;
2130
2131              // if (!isBooklet) {
2132              page.backImage(defaults.textureLoadFallback);
2133              page.backPageStamp = "-1";
2134              page.backTextureLoaded = false;
2135              // }
2136              this.requestPage();
2137            }
2138          }
2139
2140          //if (isBooklet && _pageCount < midPoint && page.isFlipping == false)
2141          //	page.visible = false;
2142
2143          page.oldDepth = page.depth;
2144          var xPos = Math.abs(page.geometry.boundingBox.max.x) < Math.abs(page.geometry.boundingBox.min.x)
2145                     ? page.geometry.boundingBox.max.x : page.geometry.boundingBox.min.x;
2146          page.position.x = (page.isEdge == true && page.isFlipping == false) ? ((_pageCount < midPoint)
2147                                                                                 ? xPos : -xPos) : 0;
2148        }
2149        //$(".quick-hint").html(pageNumber);
2150        //console.log("leftDepth:" + leftDepth, "rightDepth:" + rightDepth, "midPoint:" + midPoint, "oldBaseNumber:" + oldBaseNumber, "pageNumber:" + pageNumber);
2151        this.oldBaseNumber = pageNumber;
2152
2153        if (this.updatePageCallback != null)
2154          this.updatePageCallback();
2155
2156      };
2157      //if (window.flipBook != null)flipBook.book.refresh();
2158      //book.activePage(book.activePage());
2159      Book.prototype.createCover = function (parameters) {
2160        parameters.width = parameters.width * 2;
2161        this.cover = new MOCKUP.BiFold(parameters);
2162        this.add(this.cover);
2163      };
2164
2165      Book.prototype.createStack = function (parameters) {
2166
2167        var colors = "red,green,blue,yellow,orange,black".split(",");
2168
2169        for (var _stackCount = 0; _stackCount < this.stackCount; _stackCount++) {
2170          parameters.angles = [, this.stackCount - _stackCount];//[1] = (this.stackCount - _stackCount);
2171          parameters.stiffness = (this.stackCount - _stackCount) / 100;
2172
2173          var clone = new MOCKUP.BookPaper(parameters);
2174          clone.angles[1] = 180;
2175          //clone.name = "page" + _stackCount;
2176          clone.index = _stackCount;
2177          clone.updateAngle();
2178          clone.textureReady = false;
2179          clone.textureRequested = false;
2180          this.add(clone);
2181          clone.color = colors[_stackCount];
2182          //for (var _count = 0; _count < 4; _count++) {
2183          //    clone.material.materials[_count].color = new THREE.Color(THREE.ColorKeywords[colors[_stackCount]]);
2184          //}
2185          clone.position.z = -1 * _stackCount;// * (this.mainObject.depth * 1.05);
2186        }
2187      };
2188
2189
2190      Book.prototype.shininess = function (shininess) {
2191        if (shininess == null) {
2192          return this.mainObject.shininess();
2193        }
2194        else {
2195          this.mainObject.shininess(shininess);
2196        }
2197      };
2198
2199      Book.prototype.bumpScale = function (bumpScale) {
2200        if (bumpScale == null) {
2201          return this.mainObject.bumpScale();
2202        }
2203        else {
2204          this.mainObject.bumpScale(bumpScale);
2205        }
2206      };
2207
2208
2209      Book.prototype.frontImage = function (frontImage) {
2210        if (frontImage == null) {
2211          return this.mainObject.frontImage();
2212        }
2213        else {
2214          this.mainObject.frontImage(frontImage);
2215        }
2216      };
2217
2218
2219      Book.prototype.backImage = function (backImage) {
2220        if (backImage == null) {
2221          return this.mainObject.backImage();
2222        }
2223        else {
2224          this.mainObject.backImage(backImage);
2225        }
2226      };
2227
2228      return Book;
2229    })(MOCKUP.Bundle);
2230    MOCKUP.Book = Book;
2231
2232  }
2233
2234  //base object of flipbook or other trifold objects
2235  var PreviewObject = (function (_super) {
2236
2237    function PreviewObject(parameters) {
2238      parameters = parameters || {};
2239      //_super.call(this, parameters);
2240      this.type = "PreviewObject";
2241      var _this = this;
2242
2243      _this.zoomValue = 1;
2244
2245      function resizeDelay() {
2246        setTimeout(function () {
2247          _this.resize()
2248        }, 50);
2249      }
2250
2251      window.addEventListener("resize", resizeDelay, false);
2252
2253      this.sound = document.createElement("audio");
2254      this.sound.setAttribute("src", parameters.soundFile + "?ver=" + DFLIP.version);
2255      this.sound.setAttribute("type", "audio/mpeg");
2256
2257      this.autoPlayFunction = function () {
2258        if (_this && _this.target.autoPlay) {
2259          if (_this.target.direction == DFLIP.DIRECTION.RTL)
2260            _this.target.prev();
2261          else
2262            _this.target.next();
2263        }
2264      };
2265      //this.pageMode = DFLIP.PAGE_MODE.DOUBLE;
2266      this.dispose = function () {
2267
2268        clearInterval(this.autoPlayTimer);
2269        this.autoPlayTimer = null;
2270        this.autoPlayFunction = null;
2271
2272        //complete any tweens left.
2273        if (this.target && this.target.children) {
2274          for (var count = 0; count < this.target.children.length; count++) {
2275            var page = this.target.children[count];
2276            if (page && page.currentTween) page.currentTween.stop();
2277          }
2278        }
2279        //first dispose internal objects
2280        if (this.zoomTween) {
2281          if (this.zoomTween.stop) this.zoomTween.stop();
2282          this.zoomTween = null;
2283        }
2284        if (this.container && this.container.info && this.container.info.remove)
2285          this.container.info.remove();
2286
2287        if (this.target && this.target.dispose)
2288          this.target.dispose();
2289        this.target = null;
2290
2291        if (this.stage && this.stage.dispose)
2292          this.stage.dispose();
2293        this.stage = null;
2294
2295        //if (this.target && this.target.outlineContainer) this.target.outlineContainer.remove();
2296
2297        if (this.ui && this.ui.dispose)
2298          this.ui.dispose();
2299        this.ui = null;
2300
2301        if (this.contentProvider && this.contentProvider.dispose)
2302          this.contentProvider.dispose();
2303        this.contentProvider = null;
2304
2305        window.removeEventListener("resize", resizeDelay);
2306
2307      };
2308    }
2309
2310    PreviewObject.prototype = {
2311
2312      start: function () {
2313
2314        this.target.gotoPage(this.target.startPage);
2315
2316      },
2317
2318      end: function () {
2319        this.target.gotoPage(this.target.endPage);
2320      },
2321
2322      next: function () {
2323
2324      },
2325
2326      prev: function () {
2327
2328      },
2329      getPageTextContent: function (pageIndex) {
2330        return this.contentProvider.pdfDocument.getPage(pageIndex + 1).then(function (page) {
2331          return page.getTextContent({normalizeWhitespace: true});
2332        });
2333      },
2334      calculateSize: function (containerHeight, stageWidth, maxHeight, paddingHeight, paddingWidth, isAutoHeight, pageRatio, isSingle) {
2335        var stageHeight = containerHeight;
2336        var stageInnerWidth = stageWidth - paddingWidth;
2337        var stageInnerHeight = stageHeight - paddingHeight;
2338
2339        var autoWidth = Math.ceil(isSingle ? stageInnerWidth : stageInnerWidth / (2));
2340
2341        var autoHeight = autoWidth / pageRatio; // Height when page auto fits
2342        var refHeight = null;
2343
2344        if (isAutoHeight) {
2345          //Incase the value is auto height find the autoheight for flipbook
2346          refHeight = Math.min(autoHeight, maxHeight - paddingHeight);
2347          stageHeight = refHeight;
2348        }
2349        else {
2350          refHeight = Math.min(stageInnerHeight, maxHeight - paddingHeight);
2351        }
2352
2353        //check if book fits by width
2354        var isWide = autoHeight > refHeight;
2355        var width, height;
2356        if (isWide) {
2357          height = refHeight;
2358          width = Math.floor(height * pageRatio);
2359        }
2360        else {
2361          width = autoWidth;
2362          height = Math.ceil(autoWidth / pageRatio);
2363        }
2364        if (isAutoHeight) {
2365          stageHeight = Math.max(height + paddingHeight, 320);
2366        }
2367        return {
2368          stageHeight: stageHeight,
2369          isWide: isWide,
2370          height: height,
2371          width: width
2372        };
2373      },
2374      zoom: function (delta) {
2375
2376        this.pendingZoom = true;
2377        this.zoomDelta = delta;
2378
2379        this.resize();
2380        this.ui.update();
2381      },
2382
2383      resize: function () {
2384
2385        var _this = this;
2386
2387        if (_this.target == null ||
2388          _this.target.ui == null ||
2389          _this.target.contentProvider == null ||
2390          _this.target.contentProvider.viewport == null ||
2391          _this.target.stage == null)
2392          return;
2393
2394        if (this.ui && this.ui.isFullscreen == true && utils.hasFullscreenEnabled() == true && utils.getFullscreenElement() == null) {
2395          this.ui.switchFullscreen();
2396        }
2397
2398        //Variable Caches
2399        var target = _this.target,
2400          container = _this.container,
2401          options = _this.options,
2402          stage = target.stage,
2403          contentProvider = target.contentProvider,
2404          pageRatio = contentProvider.pageRatio,
2405          zoomViewport = contentProvider.zoomViewport,
2406          isRTL = isRTLMode(target),
2407          is3d = target.mode !== "css",
2408          isLandScape = contentProvider.pageRatio > 1,
2409          isAutoHeight = this.ui.isFullscreen == true ? false : options.height === "auto",
2410          isWide, height, width, cameraZ, fov, zoom, maxZoom,
2411          sideShift = container.hasClass("df-sidemenu-open") ? 220 : 0,
2412          isSingle = this.target.pageMode == DFLIP.PAGE_MODE.SINGLE;
2413
2414
2415        //checking if the responsive width according to container
2416        var containerWidth = container.width();
2417        if (containerWidth < 400) {//rather than responsive lets use
2418          _this.container.addClass("df-xs");
2419        }
2420        else {
2421          _this.container.removeClass("df-xs");
2422        }
2423
2424        var controlsHeight = container.find(".df-ui-controls").height();
2425        var paddingTop = options.paddingTop + (options.controlsPosition == DFLIP.CONTROLSPOSITION.TOP
2426                                               ? controlsHeight : 0),
2427          paddingRight = options.paddingRight,
2428          paddingBottom = options.paddingBottom + (options.controlsPosition == DFLIP.CONTROLSPOSITION.BOTTOM
2429                                                   ? controlsHeight : 0),
2430          paddingLeft = options.paddingLeft;
2431
2432        paddingTop = isNaN(paddingTop) ? 0 : limitAt(paddingTop, 0, paddingTop),
2433          paddingBottom = isNaN(paddingBottom) ? 0 : limitAt(paddingBottom, 0, paddingBottom),
2434          paddingLeft = isNaN(paddingLeft) ? 0 : limitAt(paddingLeft, 0, paddingLeft),
2435          paddingRight = isNaN(paddingRight) ? 0 : limitAt(paddingRight, 0, paddingRight);
2436
2437        var paddingHeight = paddingTop + paddingBottom,
2438          paddingWidth = paddingLeft + paddingRight;
2439
2440        //containerHeight, containerWidth, controlsHeight above
2441        var stageWidth = containerWidth - sideShift; //if sideMenu for thumbnails is open?
2442
2443        /*SIZE CALCULATION*/
2444        //checking if the container height is more than the window height
2445        container.height(options.height);
2446        var maxHeight = $(window).height();
2447
2448        var containerHeight = Math.min(container.height(), maxHeight);
2449
2450        var sizes = _this.calculateSize(containerHeight, stageWidth, maxHeight, paddingHeight, paddingWidth, isAutoHeight, pageRatio, isSingle);
2451
2452        if (isAutoHeight) {
2453          containerHeight = stageHeight = _this.calculateSize(containerHeight, stageWidth + sideShift, maxHeight, paddingHeight, paddingWidth, isAutoHeight, pageRatio, isSingle).stageHeight;
2454        }
2455        else {
2456          containerHeight = stageHeight = sizes.stageHeight;
2457        }
2458
2459        container.height(containerHeight);//setting twice for failsafe
2460
2461
2462        var stageHeight = containerHeight;
2463
2464
2465        var stageInnerWidth = stageWidth - paddingWidth,
2466          stageInnerHeight = stageHeight - paddingHeight;
2467
2468        width = Math.floor(isSingle ? stageInnerWidth : stageInnerWidth / 2);
2469        height = Math.floor(width / pageRatio);
2470
2471        //check if book fits by width
vendor: 4,412 bytes, lines 2472-2575
2472        isWide = height > stageInnerHeight;
2473        if (isWide) {
2474          height = stageInnerHeight;
2475          width = height * pageRatio;
2476        }
2477
2478        /*ZOOM CALCULATION*/
2479        //update maxZoom for current Stage Dimension
2480        maxZoom = contentProvider.maxZoom = contentProvider.zoomViewport.height / height;
2481
2482        //set to 1 if unset initally
2483        if (_this.zoomValue == null) _this.zoomValue = 1;
2484        if (contentProvider.zoomScale == null) contentProvider.zoomScale = 1;
2485
2486        if (_this.pendingZoom == true && _this.zoomDelta != null) {
2487
2488          var delta = _this.zoomDelta, predictedIndex, currentMaxDimension = Math.max(height, width);
2489
2490          _this.zoomValue = _this.zoomDelta > 0 ? _this.zoomValue * _this.options.zoomRatio
2491                                                : _this.zoomValue / _this.options.zoomRatio;
2492          _this.zoomValue = limitAt(_this.zoomValue, 1, maxZoom);
2493
2494          if (_this.zoomValue == 1) {
2495            contentProvider.zoomScale = 1;
2496          }
2497          else {
2498            /*
2499                        predictedIndex = height * _this.zoomValue;
2500                        //zoomStops matches the contentProvider internal calcuation and prediction stops so that the texture size won't differ
2501                        predictedIndex = utils.zoomStops(predictedIndex, _this.options.zoomRatio, _this.zoomDelta > 0, Math.max(width, height));
2502                        contentProvider.zoomScale = limitAt(predictedIndex / currentMaxDimension, 1, maxZoom);
2503            */
2504            contentProvider.zoomScale = limitAt(_this.zoomValue, 1, maxZoom);
2505          }
2506
2507        }
2508
2509        zoom = contentProvider.zoomScale;
2510
2511        //Update Image CacheSize Index
2512        contentProvider.checkViewportSize(width, height, zoom);
2513
2514        if (contentProvider.contentSourceType == SOURCE_TYPE.PDF) {
2515          //recalculation is required for pixel shift issue only if the source is PDF
2516          width = contentProvider.imageViewport.width / zoom;
2517          height = contentProvider.imageViewport.height / zoom;
2518        }
2519
2520        if (contentProvider.zoomScale != 1) {
2521          this.target.container.addClass("df-zoom-enabled");
2522        }
2523
2524        var zoomWidth = target.zoomWidth = Math.floor(width * zoom),
2525          zoomHeight = target.zoomHeight = Math.floor(height * zoom);
2526        var zoomFullWidth = zoomWidth * 2;
2527
2528        if (is3d) {
2529
2530          //zoomHeight is equal to target.height (normally 300) so relative calculation is required
2531          var proportion = zoomHeight / target.height,
2532            aspect = stageWidth / stageHeight;
2533          var relativeHeight = zoom * (height + paddingHeight) / proportion,
2534            relativeWidth = zoom * (width * (isSingle ? 1 : 2) + paddingWidth) / proportion;
2535
2536          var focusSize = isWide ? relativeHeight : relativeWidth / aspect;
2537          stage.resizeCanvas(stageWidth, stageHeight);
2538
2539          cameraZ = 1 / (2 * Math.tan(Math.PI * stage.camera.fov * 0.5 / 180) / (focusSize / zoom)) + 2.2;
2540
2541          stage.camera.updateProjectionMatrix();
2542
2543          stage.renderRequestPending = true;
2544
2545          //pixel value to stage position value
2546
2547          var shift = (paddingTop - paddingBottom) * (target.height / height) / zoom / 2;
2548
2549          //put a check if the existing gap is enough
2550          // _this.target.position.y = shift;
2551          // stage.cssScene.position.y = _this.target.position.y;
2552
2553          var _reset = contentProvider.zoomScale == 1;
2554          if (stage.camera.position.z !== cameraZ && _this.pendingZoom == true) { //avoid recreating the tween if the target is same as before
2555            if (_this.zoomTween != null)
2556              _this.zoomTween.stop();
2557            _this.zoomTween = new TWEEN.Tween({
2558              campos: stage.camera.position.z,
2559              otx: stage.orbitControl.target.x,
2560              oty: stage.orbitControl.target.y,
2561              otz: stage.orbitControl.target.z
2562            }).delay(0)
2563              .to({
2564                  campos: cameraZ,
2565                  otx: 0,
2566                  oty: shift,
2567                  otz: 0
2568                },
2569                100)
2570              .onUpdate(function () {
2571                stage.camera.position.z = this.campos;
2572                if (_reset) {
2573                  stage.camera.position.y = this.oty;
2574                  stage.orbitControl.target = new THREE.Vector3(this.otx, this.oty, this.otz);
2575                }
2576                stage.orbitControl.update();
2577              }).easing(TWEEN.Easing.Linear.None)
2578              .onComplete(function () {
2579                stage.camera.position.z = cameraZ;
2580                if (contentProvider.zoomScale == 1) {
2581                  stage.camera.position.set(0, shift, cameraZ);
2582                  stage.orbitControl.target = new THREE.Vector3(0, shift, 0);
2583                }
2584                stage.orbitControl.update();
2585              })
2586              .start();
2587          }
2588          else {
2589            if (contentProvider.zoomScale == 1) {
2590              stage.camera.position.set(0, shift, cameraZ);
2591              stage.orbitControl.target = new THREE.Vector3(0, shift, 0);
2592            }
2593            /*else {
2594              stage.camera.position.z = cameraZ;
2595            }*/
2596            stage.orbitControl.update();
2597          }
2598
2599          stage.orbitControl.update();
2600          stage.orbitControl.mouseButtons.ORBIT = zoom != 1 ? -1 : THREE.MOUSE.RIGHT;
2601          stage.orbitControl.mouseButtons.PAN = zoom != 1 ? THREE.MOUSE.LEFT : -1;
2602
2603        }
2604        else {
2605
2606          target.pageWidth = Math.round(width);
2607          target.fullWidth = target.pageWidth * 2;
2608          target.height = Math.round(height);
2609
2610          var shiftHeight = target.shiftHeight = Math.round(limitAt((zoomHeight - stageHeight + paddingHeight) / 2, 0, zoomHeight)),
2611            shiftWidth = target.shiftWidth = Math.round(limitAt((zoomFullWidth - stageWidth + paddingWidth) / 2, 0, zoomFullWidth));
2612
2613          if (zoom == 1) {
2614            target.left = 0;
2615            target.top = 0;
2616          }
2617          target.stage.css({
2618            top: -shiftHeight,
2619            bottom: -shiftHeight,
2620            right: -shiftWidth + (isRTL ? sideShift : 0),
2621            left: -shiftWidth + (isRTL ? 0 : sideShift),
2622            paddingTop: paddingTop,
2623            paddingRight: paddingRight,
2624            paddingBottom: paddingBottom,
2625            paddingLeft: paddingLeft,
2626            transform: "translate3d(" + target.left + "px," + target.top + "px,0)"
2627          });
2628          target.stageHeight = stage.height();
2629
2630          target.wrapper.css({
2631            width: zoomFullWidth,
2632            height: zoomHeight,
2633            marginTop: (containerHeight - zoomHeight - paddingHeight) > 0
2634                       ? (containerHeight - paddingHeight - zoomHeight) / 2
2635                       : 0
2636          });
2637
2638          var wrapperSize = Math.floor((distOrigin(width, height)) * zoom);
2639
2640          target.stage.find(".df-page-wrapper").width(wrapperSize).height(wrapperSize);
2641
2642          target.stage.find(".df-book-page, .df-page-front , .df-page-back, .df-page-fold-inner-shadow").height(zoomHeight).width(zoomWidth);
2643
2644        }
2645
2646        _this.checkCenter({type: "resize"});
2647
2648        if (contentProvider.zoomScale == 1) {
2649          this.target.container.removeClass("df-zoom-enabled");
2650        }
2651
2652        if (target.thumblist) {
2653          target.thumblist.reset($(target.thumblist.container).height());
2654        }
2655
2656        _this.pendingZoom = false;
2657
2658      },
2659
2660      playSound: function () {
2661        try {
2662          if (this.options && this.options.soundEnable == true) {
2663            this.sound.currentTime = 0;
2664            this.sound.play();
2665          }
2666        } catch (error) {
2667
2668        }
2669      },
2670
2671      setPageMode: function (isSingle) {
2672        if (isSingle == true) {
2673          this.ui.pageMode.addClass(this.options.icons['doublepage']);
2674          this.ui.pageMode.html("<span>" + this.options.text.doublePageMode + "</span>");
2675          this.ui.pageMode.attr("title", this.options.text.doublePageMode);
2676          this.target.pageMode = DFLIP.PAGE_MODE.SINGLE;
2677        }
2678        else {
2679          this.ui.pageMode.removeClass(this.options.icons['doublepage']);
2680          this.ui.pageMode.html("<span>" + this.options.text.singlePageMode + "</span>");
2681          this.ui.pageMode.attr("title", this.options.text.singlePageMode);
2682          this.target.pageMode = DFLIP.PAGE_MODE.DOUBLE;
2683        }
2684
2685        if (this.target && this.target.singlePageMode == DFLIP.SINGLE_PAGE_MODE.BOOKLET) {
2686          this.target.reset();
2687        }
2688
2689        this.resize();
2690      },
2691      setAutoPlay: function (isPlay) {
2692        if (this.options.autoPlay) {
2693          isPlay = isPlay == true;
2694          var text = isPlay ? this.options.text.pause : this.options.text.play;
2695          this.ui.play.toggleClass(this.options.icons['pause'], isPlay);
2696          this.ui.play.html("<span>" + text + "</span>");
2697          this.ui.play.attr("title", text);
2698
2699          clearInterval(this.autoPlayTimer);
2700          if (isPlay) {
2701            this.autoPlayTimer = setInterval(this.autoPlayFunction, this.options.autoPlayDuration);
2702          }
2703
2704          this.target.autoPlay = isPlay;
2705        }
2706      },
2707      height: function (height) {
2708        if (height == null) {
2709          return this.container.height();
2710        }
2711        else {
2712          this.options.height = height;
2713          this.container.height(height);
2714          this.resize();
2715        }
2716      },
2717      /**
2718       *checks whether the book is closed and needs to be centered
2719       */
2720      checkCenter: function (options) {
2721
2722        options = options == null ? {} : options;
2723        this.centerType = this.centerType || "start";
2724        var target = this.target;
2725        var singleShift = 0, left = 0, right = 0;
2726        var basePage = utils.getBasePage(target._activePage);
2727        var isEven = target._activePage % 2 == 0;
2728        var isRTL = target.direction == DFLIP.DIRECTION.RTL;
2729        var isSingle = target.pageMode == DFLIP.PAGE_MODE.SINGLE,
2730          isBooklet = isSingle && target.singlePageMode == DFLIP.SINGLE_PAGE_MODE.BOOKLET;
2731        var stageWidth = target.stage.width(),
2732          width;
2733
2734        if (target.mode == 'css') {
2735          width = target.wrapper.width();
2736          //calculate the excess shift required for correction in case width is too small
2737          singleShift = Math.max((width - stageWidth) / 2, 0);
2738
2739          left = -width / 4;
2740          right = width / 4;
2741
2742          if (basePage == 0 || isBooklet) {
2743            target.wrapper.css({
2744              left: isSingle
2745                    ? isRTL ? right - singleShift : left - singleShift
2746                    : isRTL ? right : left
2747            });
2748            target.shadow.css({width: '50%', left: isRTL ? 0 : '50%', transitionDelay: ''});
2749          }
2750          else if (basePage == target.pageCount) {
2751            target.wrapper.css({
2752              left: isSingle
2753                    ? isRTL ? left - singleShift : right - singleShift
2754                    : isRTL ? left : right
2755            });
2756            target.shadow.css({width: '50%', left: isRTL ? '50%' : 0, transitionDelay: ''});
2757          }
2758          else {
2759            target.wrapper.css({
2760              left: isSingle
2761                    ? isRTL
2762                      ? (isEven ? left - singleShift : right - singleShift)
2763                      : (isEven ? right - singleShift : left - singleShift)
2764                    : 0
2765            });
2766            target.shadow.css({
2767              width: '100%',
2768              left: 0,
2769              transitionDelay: (parseInt(target.duration, 10) + 50) + 'ms'
2770            });
2771          }
2772
2773          target.wrapper.css({transition: options.type == "resize" ? "none" : ""});
2774
2775        }
2776        else if (target.stage != null) {
2777          var init = target.position.x, end;
2778          singleShift = target.width / 4;
2779          width = target.width;
2780          left = -width / 2;
2781          right = width / 2;
2782
2783          if (basePage == 0 || isBooklet) {
2784            end = isRTL ? right : left;
2785          }
2786          else if (basePage == target.pageCount) {
2787            end = isRTL ? left : right;
2788          }
2789          else {
2790            end = isSingle
2791                  ? isRTL
2792                    ? (isEven ? left : right)
2793                    : (isEven ? right : left)
2794                  : 0;
2795          }
2796          //create a centertween
2797          if (end !== this.centerEnd) { //avoid recreating the tween if the target is same as before
2798            this.centerTween = new TWEEN.Tween({x: init}).delay(0)
2799              .to({x: end}, target.duration)
2800              .onUpdate(function () {
2801                target.position.x = this.x;
2802                target.stage.cssScene.position.x = this.x;
2803              }).easing(target.ease)
2804              .start();
2805            this.centerEnd = end;
2806
2807          }
2808        }
2809        // log("checkcenter at : " + left);
2810      },
2811
2812      width: function (width) {
2813        if (width == null) {
2814          return this.container.width();
2815        }
2816        else {
2817          this.options.width = width;
2818          this.container.width(width);
2819          this.resize();
2820        }
2821      }
2822
2823    };
2824
2825    return PreviewObject;
2826
2827  })({});
2828
2829  DFLIP.PreviewObject = PreviewObject;
2830
2831  //contentprovider that handles the source of book
2832  var ContentProvider = (function (_super) {
2833    __extends(ContentProvider, _super);
2834
2835
2836    function ContentProvider(contentSource, callback, parameters, flipbook) {
2837
2838      parameters = parameters || {};
2839
2840      var _this = this;
2841
2842      _this.contentRawSource = contentSource || [defaults.textureLoadFallback];
2843      _this.contentSource = _this.contentRawSource;
2844      _this.contentSourceType = null;
2845      _this.minDimension = parameters.minTextureSize || 256;
2846      _this.maxDimension = parameters.maxTextureSize || 2048;
2847      _this.pdfRenderQuality = parameters.pdfRenderQuality || DFLIP.defaults.pdfRenderQuality;
2848      _this.flipbook = flipbook;
2849      _this.waitPeriod = 50;
2850      _this.maxLength = 297;
2851      _this.enableDebug = false;
2852      _this.zoomScale = 1;
2853      _this.maxZoom = 2;
2854      _this.options = parameters;
2855      _this.outline = parameters.outline;
2856      _this.links = parameters.links;
2857      _this.html = parameters.html;
2858      _this.isCrossOrigin = parameters.isCrossOrigin;
2859
2860      _this.normalViewport = {
2861        height: 297,
2862        width: 210,
2863        scale: 1
2864      };
2865      _this.viewport = {
2866        height: 297,
2867        width: 210,
2868        scale: 1
2869      };
2870      _this.imageViewport = {
2871        height: 297,
2872        width: 210,
2873        scale: 1
2874      };
2875      _this.bookSize = {
2876        height: 297,
2877        width: 210
2878      }
2879      _this.zoomViewport = {
2880        height: 297,
2881        width: 210
2882      };
2883
2884      _this.thumbsize = 128;
2885      _this.cacheIndex = 256; //index of bigger dimension height or width
2886      _this.cache = [];
2887
2888      _this.pageRatio = parameters.pageRatio || _this.viewport.width / _this.viewport.height;
2889
2890      //texture load control so that it wont delay the transition
2891      _this.textureLoadTimeOut = null;
2892
2893      _this.type = "TextureLibrary";
2894
2895      if (Array === _this.contentSource.constructor || Array.isArray(_this.contentSource) || _this.contentSource instanceof Array) {
2896
2897        //case of images and html content
2898        _this.contentSourceType = SOURCE_TYPE.IMAGE;
2899        _this.pageCount = _this.contentSource.length;
2900
2901        //_this.setLoading(1, true);
2902
2903        // Make in memory copy of image to avoid css issues
2904        $("<img/>")
2905          .attr("src", _this.contentSource[0])
2906          .on('load', (function () {
2907            _this.viewport.height = this.height;
2908            _this.viewport.width = this.width;
2909
2910            _this.pageRatio = _this.viewport.width / _this.viewport.height;
2911            _this.bookSize = {
2912              width: (_this.pageRatio > 1 ? 1 : _this.pageRatio) * _this.maxLength,
2913              height: _this.maxLength / (_this.pageRatio < 1 ? 1 : _this.pageRatio)
2914            };
2915            _this.zoomViewport = {
2916              width: (_this.pageRatio > 1 ? 1 : _this.pageRatio) * _this.maxDimension,
2917              height: _this.maxDimension / (_this.pageRatio < 1 ? 1 : _this.pageRatio)
2918            };
2919
2920            _this.linkService = new PDFLinkService();
2921
2922            $(this).off();
2923
2924            if (_this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL) {
2925              _this.pageCount = _this.contentSource.length * 2 - 2;
2926              if (_this.options.webgl == true)
2927                _this.requiresImageTextureScaling = true;
2928            }
2929
2930            if (callback != null) {
2931              callback(_this);
2932              callback = null;
2933            }
2934            //_this.setLoading(1);
2935
2936            //console.log(_this.zoomViewport);
2937            log(this.height + ":" + this.width);
2938            //pic_real_width = this.width;   // Note: $(this).width() will not
2939            //pic_real_height = this.height; // work for in memory images.
2940            //moved to set target function
2941            //_this.
2942            // ();
2943
2944
2945          }));
2946
2947      }
2948      else if (typeof _this.contentSource == 'string' || _this.contentSource instanceof String) { //case of link to pdf file
2949
2950        //region Check if file isbase64 or normal
2951        var checkSource = function () {
2952          if (_this.contentSource.indexOf(".base64") > 1) {
2953            $.ajax({
2954              url: _this.contentSource,
2955              xhrFields: {
2956                onprogress: function (e) {
2957                  if (e.lengthComputable) {
2958                    var percentage = 100 * e.loaded / e.total;
2959                    _this.updateInfo("Loading PDF " + percentage.toString().split(".")[0] + "% ...");
2960                  }
2961                }
2962              },
2963              success: function (response) {
2964                _this.options.docParameters = {data: atob(response)};
2965                processSource();
2966              }
2967            });
2968          }
2969          else {
2970            processSource();
2971          }
2972        }
2973        //endregion
2974
2975        var processSource = function () {
2976          if (_this) {
2977            //configurePDFJS(PDFJS);
2978            PDFJS.workerSrc = defaults.pdfjsWorkerSrc;
2979
2980            _this.contentSourceType = SOURCE_TYPE.PDF;
2981            //PDFJS.disableWorker = true;
2982            PDFJS.disableAutoFetch = true;
2983            PDFJS.disableStream = true;
2984            if (isSafari || isIOS || _this.options.disableFontFace == true) {
2985              PDFJS.disableFontFace = isSafari || isIOS || _this.options.disableFontFace == true;
2986            }
2987            PDFJS.imageResourcesPath = defaults.imageResourcesPath;
2988            PDFJS.cMapUrl = defaults.cMapUrl;
2989            PDFJS.cMapPacked = !0;
2990            PDFJS.externalLinkTarget = _this.options.linkTarget;
2991
2992            var loading = _this.loading = PDFJS.getDocument(_this.options.docParameters ? _this.options.docParameters
2993                                                                                        : {
2994                url: utils.httpsCorrection(contentSource),
2995                rangeChunkSize: isNaN(_this.options.rangeChunkSize) ? 524288 : _this.options.rangeChunkSize
2996              });
2997
2998            loading.then(function sourceLoaded(pdf) {
2999
3000                _this.pdfDocument = pdf;
3001                pdf.getPage(1).then(function (page) {
3002                  _this.normalViewport = page.getViewport(1);
3003                  _this.viewport = page.getViewport(1);
3004                  _this.viewport.height = _this.viewport.height / 10;
3005                  _this.viewport.width = _this.viewport.width / 10;
3006
3007                  _this.pageRatio = _this.viewport.width / _this.viewport.height;
3008
3009                  _this.bookSize = {
3010                    width: (_this.pageRatio > 1 ? 1 : _this.pageRatio) * _this.maxLength,
3011                    height: _this.maxLength / (_this.pageRatio < 1 ? 1 : _this.pageRatio)
3012                  };
3013
3014                  _this.zoomViewport = {
3015                    width: (_this.pageRatio > 1 ? 1 : _this.pageRatio) * _this.maxDimension,
3016                    height: _this.maxDimension / (_this.pageRatio < 1 ? 1 : _this.pageRatio)
3017                  };
3018
3019                  _this.refPage = page;
3020
3021                  //console.log(_this.zoomViewport);
3022
3023                  //check if intenal pages are of double sizes.
3024                  if (pdf.numPages > 1) {
3025                    pdf.getPage(2).then(function (page) {
3026                      if (_this.options.pageSize == DFLIP.PAGE_SIZE.AUTO) {
3027                        var _viewport = page.getViewport(1);
3028                        //Update: doing width check gives false alarm if the internal pages are of different sizes yet follow same aspect ratio
3029                        //if (_viewport.width > _this.normalViewport.width * 1.5) {
3030                        var _pageRatio = _viewport.width / _viewport.height;
3031                        if (_pageRatio > _this.pageRatio * 1.5) {
3032                          _this.options.pageSize = DFLIP.PAGE_SIZE.DOUBLEINTERNAL;
3033                          _this.pageCount = pdf.numPages * 2 - 2;
3034                        }
3035                        else {
3036                          _this.options.pageSize = DFLIP.PAGE_SIZE.SINGLE;
3037                        }
3038                      }
3039                      if (callback != null) {
3040                        callback(_this);
3041                        callback = null;
3042                      }
3043                    });
3044                  }
3045                  else {
3046                    if (callback != null) {
3047                      callback(_this);
3048                      callback = null;
3049                    }
3050                  }
3051
3052                });
3053                _this.linkService = new PDFLinkService();
3054                _this.linkService.setDocument(pdf, null);
3055
3056                //moved to set target function
3057                //_this.initThumbs();
3058                _this.pageCount = pdf.numPages;
3059                _this.contentSource = pdf;
3060
3061              },
3062              function loadingError(error) {
3063                if (_this) {
3064                  var cors = "", tmp = document.createElement('a');
3065                  tmp.href = _this.contentSource;
3066
3067                  if (tmp.hostname !== window.location.hostname)
3068                    cors = "CROSS ORIGIN!! ";
3069
3070                  _this.updateInfo(cors + "Cannot access file!  " + _this.contentSource);
3071                }
3072              });
3073
3074            loading.onProgress = function getDocumentProgress(progressData) {
3075              if (_this) {
3076                var percentage = 100 * progressData.loaded / progressData.total;
3077                if (isNaN(percentage)) {
3078                  if (progressData && progressData.loaded) {
3079                    _this.updateInfo("Loading PDF " + (Math.ceil(progressData.loaded / 10000) / 100).toString() + "MB ...");
3080                  }
3081                  else {
3082                    _this.updateInfo("Loading PDF ...");
3083                  }
3084                }
3085                else {
3086                  _this.updateInfo("Loading PDF " + percentage.toString().split(".")[0] + "% ...");
3087                }
3088              }
3089            };
3090          }
3091        };
3092        var checkCORS = function () {
3093          if (_this) {
3094            defaults.pdfjsWorkerSrc += "?ver=" + DFLIP.version;
3095
3096            _this.updateInfo("Loading PDF Worker ...");
3097            var tmp = document.createElement('a');
3098            tmp.href = defaults.pdfjsWorkerSrc;
3099
3100            if (tmp.hostname !== window.location.hostname) {
3101              _this.updateInfo("Loading PDF Worker CORS ...");
3102              $.ajax({
3103                url: defaults.pdfjsWorkerSrc,
3104                cache: true,
3105                success: function (data) {
3106                  defaults.pdfjsWorkerSrc = DFLIP.createObjectURL(data, "text/javascript");
3107                  checkSource();
3108                }
3109              });
3110            }
3111            else {
3112              checkSource();
3113            }
3114          }
3115        };
3116        if (window.PDFJS == null) {
3117          if (_this) {
3118            _this.updateInfo("Loading PDF Service ...");
3119
3120            getScript(defaults.pdfjsSrc + "?ver=" + DFLIP.version, function () {
3121
3122              if (typeof define === 'function' && define.amd && window.requirejs) {
3123                _this.updateInfo("Loading PDF Service (require) ...");
3124                require.config({paths: {'pdfjs-dist/build/pdf.worker': defaults.pdfjsWorkerSrc.replace(".js", "")}});
3125                require(['pdfjs-dist/build/pdf'], function (pdf) {
3126                  checkCORS();
3127                });
3128              }
3129              else {
3130                checkCORS();
3131              }
3132            }, function () {
3133              _this.updateInfo("Unable to load PDF service..");
3134            });
3135
3136          }
3137        }
3138        else {
3139
3140          checkSource();
3141        }
3142
3143      }
3144      else {
3145        console.error("Unknown source type. Please check documentation for help");
3146      }
3147
3148      this.dispose = function () {
3149        if (_this.loading && _this.loading.destroy) {
3150          _this.loading.destroy();
3151        }
3152        _this.loading = null;
3153        if (_this.textureLoadTimeOut) {
3154          clearTimeout(_this.textureLoadTimeOut);
3155          _this.textureLoadTimeOut = null;
3156        }
3157        if (this.targetObject) {
3158          if (this.targetObject.thumbContainer && this.targetObject.thumbContainer.remove)
3159            this.targetObject.thumbContainer.remove();
3160          if (this.targetObject.outlineContainer && this.targetObject.outlineContainer.remove)
3161            this.targetObject.outlineContainer.remove();
3162          if (this.targetObject.dispose) this.targetObject.dispose();
3163          this.targetObject.processPage = null;
3164          this.targetObject.requestPage = null;
3165          if (this.targetObject.container && this.targetObject.container.off)
3166            this.targetObject.container.off();
3167
3168        }
3169        if (this.pdfDocument && this.pdfDocument.destroy) this.pdfDocument.destroy();
3170        if (this.linkService && this.linkService.dispose) this.linkService.dispose();
3171        if (this.outlineViewer && this.outlineViewer.dispose) this.outlineViewer.dispose();
3172        if (this.thumblist && this.thumblist.dispose) {
3173          this.thumblist.review = null;
3174          this.thumblist.dispose();
3175        }
3176
3177        this.activeThumb = null;
3178        this.targetObject = null;
3179        this.pdfDocument = null;
3180        this.linkService = null;
3181        this.outlineViewer = null;
3182        this.thumblist = null;
3183        _this = null;
3184      };
3185      return this;
3186    }
3187
3188    ContentProvider.prototype.updateInfo = function (info) {
3189      if (this.flipbook && this.flipbook.updateInfo) {
3190        this.flipbook.updateInfo(info);
3191      }
3192    };
3193
3194    ContentProvider.prototype.initThumbs = function () {
3195
3196      var _this = this;
3197      if (_this.cache[_this.thumbsize] == null) _this.cache[_this.thumbsize] = [];
3198      var thumbLoadTimeOut;
3199      var review = function () {
3200        clearTimeout(thumbLoadTimeOut);
3201        thumbLoadTimeOut = setTimeout(function () {
3202
3203          thumbLoadTimeOut = setTimeout(reviewThumbs, _this.waitPeriod / 2);
3204
3205        }, _this.waitPeriod);
3206      };
3207
3208      var reviewThumbs = function () {
3209        var requestCount = 0;
3210        if (Date.now() - _this.thumblist.lastScrolled < 100) {
3211          requestCount = 1;
3212        }
3213        else {
3214          _this.targetObject.container.find(".df-thumb-container .df-vrow").each(function () {
3215            var thumb = $(this);
3216            if (!thumb.hasClass("df-thumb-loaded")) {
3217              requestCount++;
3218              var id = $(this).attr("id").replace("df-thumb", "");
3219              _this.getPage(id, review, true);
3220              thumb.addClass("df-thumb-loaded");
3221              return false;
3222            }
3223          });
3224          if (requestCount == 0) {
3225            clearTimeout(thumbLoadTimeOut);
3226          }
3227        }
3228
3229        if (requestCount > 0) {
3230          review();
3231        }
3232        //move to thumb if thumb is on
3233        if (_this.activeThumb != _this.targetObject._activePage) {
3234          var thumbVisible = _this.targetObject.thumbContainer != null && _this.targetObject.thumbContainer.hasClass("df-sidemenu-visible");
3235
3236          if (thumbVisible) {
3237            var wrapper = _this.thumblist.container;
3238            var cScroll = wrapper.scrollTop,
3239              cHeight = wrapper.getBoundingClientRect().height;
3240
3241            var thumb = _this.targetObject.thumbContainer.find("#df-thumb" + _this.targetObject._activePage);
3242            if (thumb.length > 0) {//TODO direct jumps won't work..
3243              _this.targetObject.thumbContainer.find(".df-selected").removeClass("df-selected");
3244              thumb.addClass("df-selected");
3245              //js calculation
3246              thumb = thumb[0];
3247
3248              //updated with custmscrollinto view since inbuilt causes page movement
3249              if (cScroll + cHeight < thumb.offsetTop + thumb.scrollHeight)
3250                utils.scrollIntoView(thumb, null, false);
3251              else if (cScroll > thumb.offsetTop)
3252                utils.scrollIntoView(thumb);
3253
3254              _this.activeThumb = _this.targetObject._activePage;
3255            }
3256            else {
3257              $(wrapper).scrollTop(_this.targetObject._activePage * 124);
3258              review();
3259            }
3260          }
3261        }
3262      };
3263
3264      _this.thumblist = _this.targetObject.thumblist = new ThumbList({
3265        //w: 128 * _this.viewport.width/_this.viewport.height,
3266        h: 500,
3267        addFn: function (row) {
3268
3269        },
3270        scrollFn: review,
3271        itemHeight: 128,
3272        totalRows: _this.pageCount,
3273        generatorFn: function (row) {
3274          var el = document.createElement("div");
3275          var pageNumber = row + 1;
3276          el.id = "df-thumb" + pageNumber;
3277          var elText = document.createElement("div");
3278          elText.innerHTML = pageNumber;
3279          el.appendChild(elText);
3280          //el.style.position = "absolute";
3281          //el.callback = function_this.getPage(pageNumber,null,true);
3282          return el;
3283        }
3284      });
3285
3286      _this.thumblist.lastScrolled = Date.now();
3287      _this.thumblist.review = review;
3288      review();
3289
3290      //_this.thumblist.container.classList.add('thumb-container');
3291      var thumbContainer = $('<div>').addClass("df-thumb-container df-sidemenu-visible df-sidemenu");
3292      thumbContainer.append($(_this.thumblist.container).addClass("df-thumb-wrapper"));
3293      _this.targetObject.thumbContainer = thumbContainer;
3294      _this.targetObject.container.append(thumbContainer);
3295
3296      var sideMenuClose = $(html.div, {
3297        class: "df-ui-btn df-ui-sidemenu-close ti-close"
3298      });
3299      thumbContainer.append(sideMenuClose);
3300      _this.thumblist.reset($(_this.thumblist.container).height());
3301      _this.targetObject.container.on('click', '.df-thumb-container .df-vrow', function (e) {
3302        e.stopPropagation();
3303        var id = $(this).attr("id").replace("df-thumb", "");
3304        _this.targetObject.gotoPage(parseInt(id, 10));
3305      });
3306    };
3307
3308    ContentProvider.prototype.initOutline = function () {
3309      var _this = this;
3310      var outlineContainer = $('<div>').addClass("df-outline-container df-sidemenu");
3311      var outlineWrapper = $('<div>').addClass("df-outline-wrapper");
3312
3313      var sideMenuClose = $(html.div, {
3314        class: "df-ui-btn df-ui-sidemenu-close ti-close"
3315      });
3316
3317      outlineContainer.append(sideMenuClose).append(outlineWrapper);
3318      _this.targetObject.container.append(outlineContainer);
3319      _this.targetObject.outlineContainer = outlineContainer;
3320
3321      _this.outlineViewer = new BookMarkViewer({
3322        container: outlineWrapper[0],
3323        linkService: _this.linkService,
3324        outlineItemClass: "df-outline-item",
3325        outlineToggleClass: "df-outline-toggle",
3326        outlineToggleHiddenClass: "df-outlines-hidden"
3327      });
3328
3329      function processOutline(outline) {
3330
3331        if (_this.options.overwritePDFOutline == true) {
3332          outline = [];
3333        }
3334        outline = outline || [];
3335
3336        if (_this.outline) {
3337          for (var count = 0; count < _this.outline.length; count++) {
3338            _this.outline[count].custom = true;
3339            if (outline) outline.push(_this.outline[count]);
3340          }
3341          /*                    _this.outline.forEach(function(v) {
3342           //v.custom = true;
3343           this.push(v);
3344           }, this);
3345           outline.push(_this.outline)*/
3346        }
3347        if (outline.length === 0 && _this.targetObject.ui.outline != null) {
3348          _this.targetObject.ui.outline.hide();
3349        }
3350
3351        _this.outlineViewer.render({outline: outline});
3352      }
3353
3354      if (_this.pdfDocument) {
3355        _this.pdfDocument.getOutline().then(function (outline) {
3356          processOutline(outline);
3357        });
3358      }
3359      else {
3360        processOutline([]);
3361      }
3362
3363      if (_this.options.autoEnableOutline == true) {
3364        _this.targetObject.ui.outline.trigger("click");
3365      }
3366
3367      if (_this.options.autoEnableThumbnail == true) {
3368        _this.targetObject.ui.thumbnail.trigger("click");
3369      }
3370
3371    };
3372
3373    ContentProvider.prototype.checkViewportSize = function (width, height, zoom) {
3374      var _this = this;
3375      var target = _this.targetObject;
3376      var zoomWidth = width * zoom,
3377        zoomHeight = height * zoom;
3378
3379      var oldCacheSize = _this.cacheIndex;
3380
3381      /*            var height = target.mode == "css"
3382       ? (target.container.height() - (target.stage.innerWidth() - target.stage.width()) )
3383       : target.stage.height();
3384
3385       var width = height * _this.normalViewport.width / _this.normalViewport.height;*/
3386
3387      //var zoom = _this.zoomScale != 1;
3388
3389      if (_this.contentSourceType == SOURCE_TYPE.PDF) {
3390
3391
3392        /*                _this.viewport.height = height;
3393         _this.viewport.width = width;*/
3394        _this.cacheIndex = Math.ceil(Math.max(zoomWidth, zoomHeight));
3395
3396        // if (zoom !== 1) {
3397
3398        _this.cacheIndex = Math.floor(Math.max(zoomWidth, zoomHeight));// * _this.zoomScale;//nearestPowerOfTwo(Math.max(_this.viewport.width,_this.viewport.height));
3399        // _this.cacheIndex = Math.floor(utils.zoomStops(Math.max(zoomWidth, zoomHeight), _this.options.zoomRatio, oldCacheSize < _this.cacheIndex, Math.max(width, height)));
3400
3401        // }
3402
3403        _this.cacheIndex = limitAt(_this.cacheIndex * defaults.pixelRatio, _this.minDimension, _this.maxDimension);
3404        //removed to force internal page size fit incase the internal pages are of different sizes.
3405        // _this.cacheScale = _this.cacheIndex / Math.max(_this.normalViewport.width, _this.normalViewport.height);
3406
3407        if (_this.cache[_this.cacheIndex] == null) _this.cache[_this.cacheIndex] = [];
3408
3409        if (oldCacheSize !== _this.cacheIndex) {
3410          for (var pageCount = 0; pageCount < target.children.length; pageCount++) {
3411            var page = target.children[pageCount];
3412            //page.name = '-2';
3413          }
3414          target.refresh();
3415        }
3416
3417        //if(zoom !==1){
3418        //	zoomHeight = height> width ? _this.cacheIndex : _this.cacheIndex * _this.pageRatio;
3419        //}
3420        _this.imageViewport = _this.refPage.getViewport(zoomHeight / _this.normalViewport.height);
3421        _this.viewport = (target.mode == "css") ? _this.imageViewport
3422                                                : _this.refPage.getViewport(_this.bookSize.height / _this.normalViewport.height);
3423
3424        log(_this.cacheIndex);
3425
3426        _this.annotedPage = undefined;
3427        _this.review();
3428        //_this.zoomScale = (zoom == true) ? _this.normalViewport.height * _this.viewport.scale / _this.viewport.height : 1;
3429
3430      }
3431      else {
3432        if (_this.cache[_this.cacheIndex] == null) _this.cache[_this.cacheIndex] = [];
3433        /*                _this.cacheIndex = _this.zoomScale == 1 ? limitAt(_this.cacheIndex, _this.minDimension, _this.maxDimension) : _this.maxDimension;*/
3434
3435        //_this.zoomScale = (zoom == true) ? _this.zoomViewport.height / height : 1;
3436      }
3437
3438      //_this.zoomScale = (zoom == true) ? _this.zoomViewport.height / height : 1;
3439    };
3440
3441    ContentProvider.prototype.getCache = function (index, isThumb) {
3442      return (isThumb == true)
3443             ? this.cache[this.thumbsize] == null ? null : this.cache[this.thumbsize][index]
3444             : this.cache[this.cacheIndex] == null ? null : this.cache[this.cacheIndex][index];
3445    };
3446
3447    ContentProvider.prototype.setCache = function (index, src, isThumb, cacheIndexSize) {
3448      if (isThumb == true) {
3449        if (this.cache[this.thumbsize] != null) this.cache[this.thumbsize][index] = src;
3450      }
3451      else {
3452        var cacheIndex = cacheIndexSize == null ? this.cacheIndex : cacheIndexSize;
3453        if (this.cache[cacheIndex] != null)
3454          this.cache[cacheIndex][index] = src;
3455      }
3456
3457    };
3458
3459    ContentProvider.prototype.setTarget = function (targetObject) {
3460      var _this = this;
3461      if (targetObject == null) {
3462        return this.targetObject;
3463      }
3464      else {
3465        this.targetObject = targetObject;
3466        targetObject.contentProvider = this;
3467
3468        targetObject.container.removeClass("df-loading df-init");
3469
3470        //_this.initThumbs();
3471
3472        if (_this.linkService != null) {
3473          _this.linkService.setViewer(targetObject);
3474
3475          _this.initOutline();
3476        }
3477
3478        targetObject.processPage = function (pageNumber, callback) {
3479          if (pageNumber > 0 && pageNumber <= _this.pageCount) {
3480            //log("Loading page :" + pageNumber);
3481            _this.getPage(pageNumber, callback);
3482          }
3483          else {
3484            _this.setPage(pageNumber, defaults.textureLoadFallback, callback);
3485            //log("Invalid PageNumber :" + pageNumber);
3486          }
3487        };
3488
3489        targetObject.requestPage = function () {
3490
3491          _this.review("Request");
3492
3493        };
3494
3495        if (targetObject.resize != null)
3496          targetObject.resize();
3497
3498      }
3499    };
3500
3501    ContentProvider.prototype.review = function (message) {
3502      var _this = this;
3503      message = message || "timer review";
3504      clearTimeout(_this.textureLoadTimeOut);
3505      _this.textureLoadTimeOut = setTimeout(function () {
3506
3507        _this.textureLoadTimeOut = setTimeout(_this.reviewPages, _this.waitPeriod / 2, _this, message);
3508
3509      }, _this.waitPeriod);
3510    };
3511
3512    ContentProvider.prototype.reviewPages = function (_this, message) {
3513      _this = _this || this;
3514      var target = _this.targetObject;
3515
3516      if (target == null) return;
3517
3518      var isBooklet = isBookletMode(target);
3519      if (message != null) log(message);
3520      var requiresRevisit = false;
3521      var pageCount, page;
3522
3523      for (pageCount = 0; pageCount < _this.targetObject.children.length; pageCount++) {
3524        page = target.children[pageCount];
3525        if (page.isFlipping == true) { //requires revisit
3526          requiresRevisit = true;
3527          break;
3528        }
3529      }
3530      if (requiresRevisit == false) {
3531
3532        var pageLength = target.children.length > 3 ? 3 : target.children.length;
3533        var midPoint = pageLength / 2;
3534
3535        var basePage = isBooklet ? target._activePage : getBasePage(target._activePage);
3536        _this.baseNumber = basePage;
3537
3538        if (_this.zoomScale > 1) {
3539          pageLength = 1;
3540        }
3541
3542        for (pageCount = 0; pageCount < pageLength; pageCount++) {
3543
3544          var dividend = Math.floor(pageCount / 2);
3545          var diff = pageCount % 2 == 0
3546                     ? -dividend * (isBooklet ? 1 : 2)
3547                     : (dividend == 0 ? 1 : dividend) * (isBooklet ? 1 : 2);
3548
3549          var frontPageNumber = basePage + diff,
3550            backPageNumber = basePage + diff + 1;
3551
3552          var page1 = target.getPageByNumber(frontPageNumber),
3553            page2 = target.getPageByNumber(backPageNumber),
3554            reqFrontPageStamp = frontPageNumber + "|" + _this.cacheIndex,
3555            reqBackPageStamp = backPageNumber + "|" + _this.cacheIndex;
3556
3557
3558          var requestCount = 0;
3559          if (page1 != null && page1.frontPageStamp != reqFrontPageStamp && page1.visible == true) {
3560            page1.frontTextureLoaded = false;
3561            target.processPage(frontPageNumber, function () {
3562              _this.review("Batch Call");
3563            });
3564            page1.frontPageStamp = reqFrontPageStamp;
3565            requestCount++;
3566          }
3567          if (page2 != null && page2.backPageStamp != reqBackPageStamp && page2.visible == true && !isBooklet) {
3568            page2.backTextureLoaded = false;
3569            target.processPage(backPageNumber, function () {
3570              _this.review("Batch Call");
3571            });
3572            page2.backPageStamp = reqBackPageStamp;
3573            requestCount++;
3574          }
3575
3576          //diff is 0 only at the open pages
3577          if (diff == 0 && _this.annotedPage !== basePage) {// && target.mode !== "css") {
3578            _this.getAnnotations(frontPageNumber);
3579            if (!isBooklet) _this.getAnnotations(backPageNumber);
3580            _this.annotedPage = basePage;
3581          }
3582
3583          if (requestCount > 0) {
3584            break;
3585          }
3586        }
3587        if (requestCount == 0) {
3588          if (target.mode !== "css") {
3589            _this.setLoading(basePage);
3590          }
3591          else {
3592            // _this.setLoading(basePage);
3593            // _this.setLoading(basePage + 1);
3594          }
3595        }
3596      }
3597      else {
3598        _this.review("Revisit request");
3599        if (_this.annotedPage != null && target.mode !== "css") {
3600          var baseActive = getBasePage(target._activePage);
3601          $(target.getContentLayer(baseActive)).html("");
3602          $(target.getContentLayer(baseActive + 1)).html("");
3603          _this.annotedPage = null;
3604        }
3605      }
3606
3607    };
3608
3609    ContentProvider.prototype.getPage = function (pageNumber, callbackFunction, isThumb) {
3610      var _this = this;
3611
3612      pageNumber = parseInt(pageNumber, 10);
3613      var _pageNumber = pageNumber;
3614      var source = _this.contentSource;
3615      if (pageNumber <= 0 && pageNumber >= _this.pageCount) {
3616        _this.setPage(pageNumber, defaults.textureLoadFallback, callbackFunction, isThumb);
3617      }
3618      else {
3619        if (_this.contentSourceType == SOURCE_TYPE.PDF) {
3620          if (_this.getCache(pageNumber, isThumb) != null) {
3621            _this.setPage(pageNumber, _this.getCache(pageNumber, isThumb), callbackFunction, isThumb);
3622            log("Page " + pageNumber + " loaded from cache");
3623          }
3624          else {
3625            if (isThumb !== true) _this.setLoading(pageNumber, true);
3626
3627            if (_this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL && pageNumber > 2) {
3628              _pageNumber = Math.ceil((pageNumber - 1) / 2) + 1;
3629            }
3630            source.getPage(_pageNumber, isThumb).then(function (page) {
3631              renderPage(page, pageNumber, callbackFunction, isThumb);
3632            });
3633          }
3634        }
3635        else if (_this.contentSourceType == SOURCE_TYPE.IMAGE || _this.contentSourceType == SOURCE_TYPE.HTML) {
3636          if (_this.getCache(pageNumber, isThumb) != null) {
3637            _this.setPage(pageNumber, _this.getCache(pageNumber, isThumb), callbackFunction, isThumb);
3638            log("Page " + pageNumber + " loaded from cache");
3639          }
3640          else {
3641            if (isThumb !== true) _this.setLoading(pageNumber, true);
3642
3643            if (_this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL && pageNumber > 2) {
3644              _pageNumber = Math.ceil((pageNumber - 1) / 2) + 1;
3645            }
3646
3647            //if (_this.isCrossOrigin == null) {
3648            //
3649            //	_this.setCache(pageNumber, source[_pageNumber - 1], isThumb, _this.cacheIndex);
3650            //	_this.setPage(pageNumber, source[_pageNumber - 1], callbackFunction, isThumb);
3651            //
3652            //	if (callbackFunction != null) callbackFunction();
3653            //
3654            //} else {
3655            loadImagejQuery(source[_pageNumber - 1], function (src) {
3656
3657              _this.setCache(pageNumber, src, isThumb, _this.cacheIndex);
3658              _this.setPage(pageNumber, src, callbackFunction, isThumb);
3659
3660              if (callbackFunction != null) callbackFunction();
3661
3662            }, _this.isCrossOrigin);
3663            //}
3664          }
3665
3666          //_this.setPage(pageNumber, source[pageNumber - 1], callbackFunction, isThumb);
3667        }
3668      }
3669
3670      function loadImage(src, callback, isCrossOrigin) {
3671
3672        var img = new Image;
3673
3674        img.crossOrigin = "Anonymous";
3675
3676        img.onload = function () {
3677
3678          if (isCrossOrigin == true) {
3679            var canvas = document.createElement("canvas"),
3680              ctx = canvas.getContext("2d");
3681            canvas.width = img.width;
3682            canvas.height = img.height;
3683            ctx.drawImage(img, 0, 0);
3684            //localStorage.setItem( "savedImageData", canvas.toDataURL("image/png") );
3685
3686            if (defaults.canvasToBlob == true) {
3687              canvas.toBlob(function (blob) {
3688                var src = DFLIP.createObjectURL(blob, "image/jpeg");
3689
3690                if (callback != null) callback(src);
3691
3692              }, "image/jpeg", 0.85)
3693
3694
3695            }
3696            else {
3697              if (callback != null) callback(canvas);
3698            }
3699          }
3700          else {
3701            if (callback != null) callback(src);
3702          }
3703          //$(this).off();
3704          img.onload = null;
3705          img = null;
3706
3707        };
3708
3709        img.src = src;
3710
3711        // make sure the load event fires for cached images too
3712        if (img.complete || img.complete === undefined) {
3713          img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
3714          img.src = src;
3715        }
3716
3717      }
3718
3719      function loadImagejQuery(src, callback, isCrossOrigin) {
3720        $("<img/>")
3721          .attr("src", _this.contentSource[0])
3722          .on('load', (function () {
3723
3724
3725            $(this).off();
3726
3727            if (callback != null) {
3728              callback(src);
3729              // callback = null;
3730            }
3731            //_this.setLoading(1);
3732
3733            //console.log(_this.zoomViewport);
3734            log(this.height + ":" + this.width);
3735            //pic_real_width = this.width;   // Note: $(this).width() will not
3736            //pic_real_height = this.height; // work for in memory images.
3737            //moved to set target function
3738            //_this.
3739            // ();
3740
3741
3742          }));
3743      }
3744
3745      function renderPage(page, pageNumber, callbackFunction, isThumb) {
3746
3747
3748        var forceFit = _this.options.forceFit;
3749        var isDoublePage = _this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL && pageNumber > 1 && pageNumber < _this.pageCount;
3750        var widthFix = isDoublePage && forceFit ? 2 : 1;
3751
3752        /*                var heightScale = _this.pageRatio < 1
3753         ? _this.cacheScale
3754         : _this.cacheScale / _this.pageRatio;*/
3755        //_this.cacheScale = _this.cacheIndex / Math.max(_this.normalViewport.width, _this.normalViewport.height);
3756        //scales are calculated based on perpage in case per page fitting is required.
3757        var viewport = forceFit ? page.getViewport(1) : _this.normalViewport;
3758
3759        var scale = _this.cacheIndex / Math.max(viewport.width / widthFix, viewport.height);//heightScale /_this.normalViewport.height;
3760        if (_this.webgl == true) {
3761          scale = nearestPowerOfTwo(_this.cacheIndex) / (_this.pageRatio > 1
3762                                                         ? viewport.width / widthFix : viewport.height);
3763        }
3764
3765        var canvas = document.createElement('canvas');
3766        var start = performance.now();
3767
3768        var requestedCacheSize = _this.cacheIndex;
3769
3770        var context = canvas.getContext('2d');
3771
3772        // scale = scale * defaults.pixelRatio;
3773
3774        if (isThumb == true) {
3775          scale = _this.thumbsize / _this.normalViewport.height;
3776        }
3777
3778        canvas.height = Math.round(viewport.height * scale); //causes fluctuation in value like 22.99999 as 22
3779        canvas.width = Math.round(viewport.width / widthFix * scale);
3780
3781        if (_this.targetObject.mode == 'css' && Math.abs(_this.targetObject.zoomHeight - canvas.height) < 2) {
3782          canvas.height = _this.targetObject.zoomHeight + 0; //causes fluctuation in value like 22.99999 as 22
3783          canvas.width = _this.targetObject.zoomWidth + 0;
3784        }
3785
3786        viewport = page.getViewport(scale);
3787        log("rendering " + pageNumber + " at " + canvas.width + "x" + canvas.height);
3788
3789        if (isDoublePage) {
3790          if (isRTLMode(_this.targetObject)) {
3791            if (pageNumber % 2 == 0) {
3792              viewport.transform[4] = -canvas.width;
3793            }
3794          }
3795          else {
3796            if (pageNumber % 2 == 1) {
3797              viewport.transform[4] = -canvas.width;
3798            }
3799          }
3800        }
3801        var renderContext = {
3802          canvasContext: context,
3803          viewport: viewport
3804        };
3805
3806        page.cleanupAfterRender = true;
3807        var pageRendering = page.render(renderContext);
3808
3809        pageRendering.promise.then(
3810          function () {
3811
3812            log(performance.now() - start);
3813            start = performance.now();
3814            if (isThumb == true || (_this.options.canvasToBlob == true && _this.webgl !== true)) {
3815              canvas.toBlob(function (blob) {
3816                var src = DFLIP.createObjectURL(blob, "image/jpeg");
3817                log(performance.now() - start);
3818                _this.setCache(pageNumber, src, isThumb, requestedCacheSize);
3819                _this.setPage(pageNumber, src, callbackFunction, isThumb);
3820
3821                //canvas.width = canvas.height = 1;
3822                //context.clearRect( 0, 0, canvas.width, canvas.height );
3823
3824                //page.cleanup();
3825              }, "image/jpeg", _this.pdfRenderQuality)
3826            }
3827            else {
3828              log("Setting Page " + pageNumber);
3829              _this.setPage(pageNumber, canvas, callbackFunction, isThumb);
3830            }
3831            renderContext = null;
3832          });
3833
3834      }
3835
3836    };
3837
3838    ContentProvider.prototype.getTargetPage = function (pageNumber) {
3839
3840    };
3841
3842    ContentProvider.prototype.setLoading = function (pageNumber, show) {
3843      if (this.targetObject != null) {
3844        if (this.webgl == true) {
3845          var container = this.targetObject.container;
3846          if (show == true) {
3847            if (container.isLoading !== true) {
3848              container.addClass("df-loading");
3849              container.isLoading = true;
3850              log("Loading icon at " + pageNumber + " as " + show);
3851            }
3852          }
3853          else {
3854            if (container.isLoading != null) {
3855              container.removeClass("df-loading");
3856              container.isLoading = null;
3857              log("Loading icon at " + pageNumber + " as " + show);
3858            }
3859          }
3860        }
3861        else {
3862          var contentLayer = $(this.targetObject.getContentLayer(pageNumber));
3863          if (contentLayer != null) {
3864            if (show == true) contentLayer.addClass("df-page-loading");
3865            else contentLayer.removeClass("df-page-loading");
3866            log("Loading icon at " + pageNumber + " as " + show);
3867          }
3868        }
3869      }
3870    };
3871
3872    ContentProvider.prototype.getAnnotations = function (pageNumber) {
3873      var _this = this;
3874
3875      if (_this.options.enableAnnotation == false || utils.hasCompatibility() === true) return;
3876
3877      var target = _this.targetObject;
3878
3879      pageNumber = parseInt(pageNumber, 10);
3880      var source = _this.contentSource;
3881      var contentLayer = $(target.getContentLayer(pageNumber));
3882      contentLayer.empty();
3883      if (pageNumber > 0 && pageNumber <= _this.pageCount) {
3884
3885
3886        if (_this.contentSourceType == SOURCE_TYPE.PDF) {
3887          var basePage = getBasePage(pageNumber);
3888
3889          var _pageNumber = pageNumber;
3890          if (_this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL && pageNumber > 2) {
3891            _pageNumber = Math.ceil((pageNumber - 1) / 2) + 1;
3892          }
3893
3894          source.getPage(_pageNumber).then(function (page) {
3895
3896            if (contentLayer != null && contentLayer.length > 0) {
3897              var viewport = page.getViewport(1);
3898              viewport = page.getViewport(_this.viewport.height / viewport.height);
3899              // _this.viewport
3900              _this.setupAnnotations(page, viewport, contentLayer, pageNumber);
3901
3902              /*                            //it's just resizing nothing to do with annotation fetch
3903               if (target.mode != "css") {
3904
3905               var page3d = target.getPageByNumber(pageNumber);
3906               if (page3d != null) {
3907               var isLeft = (pageNumber % 2 == 0);
3908               var width = Math.abs(page3d.geometry.boundingBox.max.x - page3d.geometry.boundingBox.min.x);
3909               var height = Math.abs(page3d.geometry.boundingBox.max.z - page3d.geometry.boundingBox.min.z);
3910
3911               var div3d = isLeft ? target.parent.cssScene.divLeft : target.parent.cssScene.divRight;
3912               if (div3d != null) {
3913               div3d.rotation.y = (isLeft ? -1 : 1 ) * Math.atan2(height, width) * 0.9;
3914               div3d.position.z = height * 0.8;
3915               div3d.position.x = (isLeft ? 1 : -1 ) * height / 2.5;
3916               $(div3d.element).css({
3917               width: width,
3918               left: isLeft ? -width / 2 : width / 2
3919               });
3920
3921               }
3922               }
3923               }*/
3924            }
3925          });
3926        }
3927
3928        //render any custom liks available for page.
3929
3930        if (_this.links != null && _this.links[pageNumber] != null) {
3931          var pageLinks = _this.links[pageNumber];
3932          for (var index = 0; index < pageLinks.length; index++) {
3933            var pageLink = pageLinks[index];
3934
3935            var annotation;
3936            if (pageLink.dest && pageLink.dest.indexOf && pageLink.dest.indexOf('[html]') == 0) {
3937              annotation = document.createElement('div');
3938              annotation.innerHTML = pageLink.dest.substr(6);
3939              annotation.className = "customHtmlAnnotation";
3940            }
3941            else {
3942              annotation = document.createElement('a');
3943              annotation.setAttribute("dest", pageLink.dest);
3944              annotation.className = "customLinkAnnotation";
3945              annotation.href = "#" + pageLink.dest;
3946              annotation.onclick = function () {
3947                var dest = this.getAttribute("dest");
3948                if (dest) {
3949                  _this.linkService.customNavigateTo(dest);
3950                }
3951                return false;
3952              };
3953
3954            }
3955            annotation.style.left = pageLink.x + "%";
3956            annotation.style.top = pageLink.y + "%";
3957
3958            annotation.style.width = pageLink.w + "%";
3959            annotation.style.height = pageLink.h + "%";
3960            contentLayer[0].appendChild(annotation);
3961          }
3962        }
3963
3964        //render any html available for page.
3965
3966        if (_this.html != null && _this.html[pageNumber] != null) {
3967          var pageHTML = _this.html[pageNumber];
3968          contentLayer.append($("<div class='customHTMLAnnotation'>").html(pageHTML));
3969        }
3970      }
3971    };
3972
3973    ContentProvider.prototype.setPage = function (pageNumber, textureSrc, callbackFunction, isThumb) {
3974      var _this = this;
3975      var target = _this.targetObject;
3976      var isRTL = isRTLMode(target);
3977      var isBooklet = isBookletMode(target);
3978      if (isThumb == true) {
3979        var page = _this.targetObject.container.find("#df-thumb" + pageNumber);
3980        //log("setting:" + pageNumber + " " + bgImage(textureSrc));
3981        page.css({
3982          backgroundImage: bgImage(textureSrc)
3983        });
3984      }
3985      else {
3986
3987        if (textureSrc == defaults.textureLoadFallback) {
3988          log("Fallback on " + pageNumber);
3989        }
3990
3991        var bookPage = target.getPageByNumber(pageNumber);
3992        if (bookPage != null) {
3993          if (
3994            (pageNumber % 2 != 0 && !isRTL) ||
3995            (pageNumber % 2 != 1 && isRTL && !isBooklet) || (isBooklet && !isRTL)
3996          ) {
3997            log(pageNumber + "rendered to back of " + bookPage.color);
3998            bookPage.backImage(textureSrc, function (object, texture) {
3999              bookPage.backTextureLoaded = true;
4000              _this.setLoading(pageNumber);
4001              if (_this.requiresImageTextureScaling && texture && pageNumber != 1 && pageNumber != _this.pageCount) {
4002                texture.repeat.x = 0.5;
4003                texture.offset.x = 0.5;
4004              }
4005              if (callbackFunction != null) callbackFunction();
4006            });
4007
4008          }
4009          else {
4010            log(pageNumber + "rendered to front of " + bookPage.color);
4011            bookPage.frontImage(textureSrc, function (object, texture) {
4012              bookPage.frontTextureLoaded = true;
4013              _this.setLoading(pageNumber);
4014              if (_this.requiresImageTextureScaling && texture && pageNumber != 1 && pageNumber != _this.pageCount) {
4015                texture.repeat.x = 0.5;
4016              }
4017              if (callbackFunction != null) callbackFunction();
4018            });
4019            //}
4020          }
4021        }
4022        else {
4023          log("Invalid set request on Page " + pageNumber);
4024        }
4025      }
4026    };
4027
4028    ContentProvider.prototype.setupAnnotations = function (page, viewport, pageDiv, pageNumber) {
4029      if (pageDiv == null || $(pageDiv).length == 0) return;
4030      var _this = this;
4031      return page.getAnnotations().then(function (annotationsData) {
4032        viewport = viewport.clone({
4033          dontFlip: true
4034        });
4035
4036        if (_this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL && pageNumber > 2 && pageNumber % 2 == 1) {
4037          //viewport.transform[4]= -viewport.scale * page.view[2]/2;
4038
4039        }
4040        else if (pageNumber == 1) {
4041
4042        }
4043        if (pageDiv == null) {
4044          return;
4045        }
4046        pageDiv = $(pageDiv);
4047        if (pageDiv.find(".annotationDiv").length == 0) {
4048          pageDiv.append($("<div class='annotationDiv'>"));
4049        }
4050        var div = pageDiv.find(".annotationDiv");
4051        div.empty();
4052        if (_this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL && pageNumber > 2 && pageNumber % 2 == 1) {
4053          //viewport.transform[4]= -viewport.scale * page.view[2]/2;
4054          div.css({left: '-100%'});
4055        }
4056        else if (pageNumber == 1) {
4057          div.css({left: ''});
4058        }
4059        /*                div.css({
4060         transform:'matrix(' + _this.viewport.transform.join(',') + ')'
4061         });*/
4062
4063        PDFJS.AnnotationLayer.render({
4064          annotations: annotationsData,
4065          div: div[0],
4066          page: page,
4067          viewport: viewport,
4068          linkService: _this.linkService
4069        });
4070
4071        if (_this.options.annotationClass && _this.options.annotationClass !== "") {
4072          div.find(" > section").addClass(_this.options.annotationClass);
4073        }
4074        if (_this.options.search == true) {
4075          // div.find(" > section").addClass("someclass");
4076          if (pageDiv.find(".textLayerDiv").length == 0) {
4077            pageDiv.append($("<div class='textLayerDiv'>"));
4078          }
4079          var div2 = pageDiv.find(".textLayerDiv");
4080
4081          page.getTextContent().then(function (textContent) {
4082            // console.log(textContent);
4083            var textLayer = new DFLIP.TextLayerBuilder({
4084              textLayerDiv: div2[0],
4085              pageIndex: null,
4086              viewport: viewport.clone({
4087                dontFlip: false
4088              })
4089            });
4090
4091            textLayer.setTextContent(textContent);
4092            textLayer.render();
4093          });
4094        }
4095      });
4096
4097    };
4098
4099    return ContentProvider;
4100  })({});
4101
4102  var PageCSS = (function () {
4103    function PageCSS(parameters) {
4104      this.angles = parameters.angles || [0, 0, 0, 0, 0, 0];
4105      this.stiffness = parameters.angles || 0.1;
4106      this.segments = parameters.segments || 1;
4107      this.canvasMode = parameters.contentSourceType !== SOURCE_TYPE.IMAGE && parameters.canvasToBlob == false;
4108      this.initDOM();
4109    }
4110
4111    function createInternals(pageSide) {
4112      var contentLayer = pageSide.contentLayer = $(html.div, {
4113        class: "df-page-content"
4114      });
4115      pageSide.append(contentLayer);
4116    }
4117
4118    PageCSS.prototype = {
4119      initDOM: function () {
4120        var element = this.element = $(html.div, {
4121          class: "df-book-page"
4122        });
4123        var wrapper = this.wrapper = $(html.div, {
4124          class: "df-page-wrapper"
4125        });
4126        var front = this.front = $(html.div, {
4127          class: "df-page-front"
4128        });
4129        var back = this.back = $(html.div, {
4130          class: "df-page-back"
4131        });
4132        var foldInnerShadow = this.foldInnerShadow = $(html.div, {
4133          class: "df-page-fold-inner-shadow"
4134        });
4135        var foldOuterShadow = this.foldOuterShadow = $(html.div, {
4136          class: "df-page-fold-outer-shadow"
4137        });
4138        this.frontIMG = new Image();
4139        this.backIMG = new Image();
4140
4141        createInternals(front, this.segments, true);
4142        createInternals(back, this.segments, false);
4143        element.append(wrapper).append(foldOuterShadow);
4144        wrapper.append(front).append(back).append(foldInnerShadow);
4145
4146      },
4147
4148      updatePoint: function (point) {
4149
4150        if (point == null) return;
4151
4152        //detect the current page
4153        var page = this.parent.dragPage != null ? this.parent.dragPage
4154                                                : point.page != null ? point.page : this;
4155
4156        //get the pageWidth and pageHeight
4157        var pageWidth = page.element.width(),
4158          pageHeight = page.element.height();
4159
4160        //the corner where the drag started
4161        var corner = this.parent.corner != null ? this.parent.corner : point.corner,
4162          corners = DFLIP.CORNERS;
4163
4164        var
4165          isRight = page.side == drag.right,
4166          isBottom = (corner == corners.BL) || (corner == corners.BR);
4167
4168        point.rx = (isRight == true)
4169                   ? pageWidth * 2 - point.x
4170                   : point.x;
4171
4172        point.ry = (isBottom == true)
4173                   ? pageHeight - point.y
4174                   : point.y;
4175
4176        var radAngle = Math.atan2(point.ry, point.rx);
4177
4178        radAngle = Math.PI / 2 - limitAt(radAngle, 0, toRad(90));
4179
4180        var correctionX = isRight
4181                          ? point.x / 2
4182                          : pageWidth - point.x / 2,
4183
4184          correctionY = point.ry / 2,
4185
4186          refLength = Math.max(0,
4187            Math.sin(radAngle - Math.atan2(correctionY, correctionX)) * distOrigin(correctionX,
4188            correctionY)),
4189
4190          foldLength = 0.5 * distOrigin(point.rx, point.ry);
4191
4192        var x = Math.round(pageWidth - refLength * Math.sin(radAngle)),
4193          y = Math.round(refLength * Math.cos(radAngle)),
4194
4195          angle = toDeg(radAngle);
4196
4197        var angle1 = isBottom
4198                     ? isRight ? 180 + (90 - angle) : 180 + angle
4199                     : isRight ? angle : 90 - angle;
4200
4201        var angle2 = isBottom
4202                     ? isRight ? 180 + (90 - angle) : angle
4203                     : isRight ? angle + 180 : angle1,
4204          angleS = isBottom
4205                   ? isRight ? 90 - angle : angle + 90
4206                   : isRight ? angle1 - 90 : angle1 + 180,
4207          x1 = isRight ? pageWidth - x : x,
4208          y1 = isBottom ? pageHeight + y : -y,
4209          x2 = isRight ? -x : x - pageWidth,
4210          y2 = isBottom ? -pageHeight - y : y;
4211
4212        var opacity = limitAt(point.distance * 0.5 / pageWidth, 0, 0.5);
4213        var foldOpacity = limitAt((pageWidth * 2 - point.rx) * 0.5 / pageWidth, 0.05, 0.3);
4214
4215        page.element.addClass("df-folding");
4216
4217        var front = isRight ? page.back : page.front;
4218        var back = isRight ? page.front : page.back;
4219        var outerShadow = page.foldOuterShadow;
4220        var innerShadow = page.foldInnerShadow;
4221        page.wrapper.css({
4222          transform: translateStr(x1, y1) + rotateStr(angle1)
4223        });
4224
4225        front.css({
4226          transform: rotateStr(-angle1) + translateStr(-x1, -y1)
4227        });
4228
4229        back.css({
4230          transform: rotateStr(angle2) + translateStr(x2, y2),
4231          boxShadow: "rgba(0, 0, 0, " + opacity + ") 0px 0px 20px"
4232        });
4233
4234        innerShadow.css({
4235          transform: rotateStr(angle2) + translateStr(x2, y2),
4236          opacity: foldOpacity / 2,
4237          backgroundImage: prefix.css + "linear-gradient( " + angleS + "deg, rgba(0, 0, 0, 0.25) , rgb(0, 0, 0) " + foldLength * 0.7 + "px, rgb(255, 255, 255) " + foldLength + "px)"
4238        });
4239
4240        outerShadow.css({
4241          //transform: rotateStr(angle - (isRight ? -180 : 0)) + translateStr(isRight ? -x : x - pageWidth, y),
4242          opacity: foldOpacity / 2,
4243          left: isRight ? "auto" : 0,
4244          right: isRight ? 0 : "auto",
4245          backgroundImage: prefix.css + "linear-gradient( " + (-angleS + 180) + "deg, rgba(0, 0, 0,0) " + foldLength / 3 + "px, rgb(0, 0, 0) " + foldLength + "px)"
4246        });
4247
4248        //$("body > p").html(JSON.stringify({
4249        //	x: Math.round(point.rx),
4250        //	y: Math.round(point.ry),
4251        //	a: Math.round(angle),
4252        //	a1: Math.round(angle1),
4253        //	cx: Math.round(correctionX),
4254        //	cy: Math.round(correctionY),
4255        //	dx: Math.round(x),
4256        //	dy: Math.round(y),
4257        //	ref: Math.round(refLength),
4258        //	dis: Math.round(distOrigin(point.x, point.y))
4259        //}));
4260      },
4261
4262      updateAngle: function (angle, isRight) {
4263
4264        var width = this.element.width() * 5;
4265
4266        //if(prefix.dom!=='MS') {
4267        this.wrapper.css({
4268          perspective: width,
4269          perspectiveOrigin: isRight == true ? "0% 50%" : "100% 50%"
4270        });
4271        //}
4272
4273        this.front.css({
4274          display: (isRight == true ? (angle <= -90 ? 'block' : 'none') : (angle < 90 ? 'block' : 'none')),
4275          transform: (prefix.dom !== 'MfS' ? "" : "perspective(" + width + "px) ")
4276            + (isRight == true ? "translateX(-100%) " : "")
4277            + "rotateY(" + ((isRight == true ? 180 : 0) + angle) + "deg)"
4278        });
4279        this.back.css({
4280          display: (isRight == true ? (angle > -90 ? 'block' : 'none') : (angle >= 90 ? 'block' : 'none')),
4281          transform: (prefix.dom !== 'MSd' ? "" : "perspective(" + width + "px) ")
4282            + (isRight == false ? "translateX(100%) " : "")
4283            + "rotateY(" + ((isRight == false ? -180 : 0) + angle) + "deg)"
4284        });
4285        //$("body > p").html(JSON.stringify({
4286        //	a: Math.round(angle)
4287        //}));
4288        return;
4289        /*if(this.angles[1] != null) {
4290         var segsb = this.back.segments;
4291         var segsf = this.front.segments;
4292         var width = this.element.width();
4293         var angle1 = this.angles[1];
4294         var angle2 = this.angles[4]/segsb.length;
4295         var step = Math.floor(width/segsb.length);
4296
4297         for (var count = 0; count < segsb.length; count++) {
4298         var segb = segsb[count];
4299         var segf = segsf[count];
4300         segb.css({
4301         transform: "rotate3d(0,1,0," + (count == 0 ? angle1 : angle2) + "deg)",
4302         //backgroundPositionX: -step * count,
4303         //backgroundSize: width + "px 100%"
4304         });
4305
4306         segf.css({
4307         transform: "rotate3d(0,1,0," + (count == 0 ? 180 + angle1 : angle2) + "deg)",
4308         //backgroundPositionX: step * (count + 1),
4309         //backgroundSize: width + "px 100%"
4310         });
4311         }
4312         }
4313         else{
4314         this.element.find(".bg-segment").css({
4315         transform: "translate3d(0px,0,0) rotate3d(0,1,0,0deg)"
4316         });
4317         }*/
4318
4319      },
4320
4321      tween: function (point) {
4322        var page = this;
4323        if (page == null || page.parent == null) return;
4324        var isBooklet = isBookletMode(page.parent);
4325        var isRight = page.side == drag.right;
4326        var isRTL = page.parent.direction == DFLIP.DIRECTION.RTL;
4327        var isBottom = page.parent.corner == DFLIP.CORNERS.BL || page.parent.corner == DFLIP.CORNERS.BR;
4328        var isMagnetic = page.magnetic == true;
4329        var travelY = isBottom ? page.parent.height : 0;
4330
4331        var init, first, mid, angle = 0;
4332
4333        var end = page.end = (page && page.animateToReset == true)
4334                             ? {x: isRight ? page.parent.fullWidth : 0, y: travelY}
4335                             : {x: isRight ? 0 : page.parent.fullWidth, y: travelY};
4336
4337        page.ease = page.isHard ? TWEEN.Easing.Quadratic.InOut : TWEEN.Easing.Linear.None;
4338
4339        var tempDuration = page.parent.duration;
4340
4341        if (page.isHard == true) {
4342
4343          if (point != null) {
4344            angle = angleByDistance(point.distance, point.fullWidth);
4345          }
4346
4347          init = page.init = {angle: angle * (isRight ? -1 : 1)};
4348          end = page.end = (page && page.animateToReset == true)
4349                           ? {angle: isRight ? 0 : -0}
4350                           : {angle: isRight ? -180 : 180};
4351
4352        }
4353        else {
4354
4355          if (point == null) {
4356
4357            init = page.init = (page && page.animateToReset == true)
4358                               ? {x: isRight ? 0 : page.parent.fullWidth, y: 0}
4359                               : {x: isRight ? page.parent.fullWidth : 0, y: 0};
4360
4361            first = page.first = {
4362              x: (isRight ? 3 : 1) * page.parent.fullWidth / 4,
4363              y: 0
4364            };
4365
4366            mid = page.mid = {x: (isRight ? 1 : 3) * page.parent.fullWidth / 4, y: 0};
4367
4368          }
4369          else {
4370
4371            init = page.init = {x: point.x, y: point.y, opacity: 1};
4372            first = page.first = {x: point.x * 3 / 4, y: point.y * 3 / 4, opacity: 1};
4373            mid = page.mid = {x: point.x / 4, y: point.y / 4, opacity: 1};
4374
4375            tempDuration = page.parent.duration * distPoints(init.x, init.y, end.x, end.y) / page.parent.fullWidth;
4376
4377            tempDuration = limitAt(tempDuration, page.parent.duration / 3, page.parent.duration);
4378
4379          }
4380        }
4381        init.index = 0;
4382        // first.index = 0;
4383        // mid.index = 0;
4384        end.index = 1;
4385        page.isFlipping = true;
4386
4387        var update = function (tween) {
4388
4389          if (page.isHard == true) {
4390            page.updateAngle(tween.angle, isRight);
4391            page.angle = tween.angle;
4392          }
4393          else {
4394            page.updatePoint({
4395              x: tween.x,
4396              y: tween.y
4397            });
4398            page.x = tween.x;
4399            page.y = tween.y;
4400          }
4401          if (isBooklet && !isMagnetic)
4402            page.element[0].style.opacity = (isRight && !isRTL) || (!isRight && isRTL)
4403                                            ? tween.index > 0.5 ? 2 * (1 - tween.index) : 1
4404                                            : tween.index < 0.5 ? 2 * tween.index : 1;
4405
4406        };
4407
4408        if (isBooklet && ((!isRight && !isRTL) || (isRight && isRTL)))
4409          page.element[0].style.opacity = 0;
4410
4411        var completeTween = page.completeTween = page.completeTween || function (skipRefresh) {
4412          page.isFlipping = false;
4413
4414          if (page.isHard == true) {
4415
4416            page.updateAngle(page.end.angle);
4417            page.back.css({display: "block"});
4418            page.front.css({display: "block"});
4419
4420          }
4421          else {
4422
4423            page.updatePoint({
4424              x: page.end.x,
4425              y: page.end.y
4426            });
4427
4428          }
4429
4430          page.element[0].style.opacity = 1;
4431
4432          if (page.animateToReset !== true) {
4433            page.side = page.side == drag.right ? drag.left : drag.right;
4434          }
4435          else
4436            page.animateToReset = null;
4437
4438          page.currentTween = null;
4439          page.pendingPoint = null;
4440          page.magnetic = false;
4441          page.parent.dragPage = null;
4442          page.parent.corner = DFLIP.CORNERS.NONE;
4443
4444          if (skipRefresh != true)
4445            page.parent.refresh();
4446
4447
4448          //log("Tween Completed");
4449        };
4450        if (page.isHard == true) {
4451          page.currentTween = new TWEEN.Tween(init).delay(0)
4452            .to(end, page.parent.duration)
4453            .onUpdate(function () {
4454              update(this);
4455            }).easing(page.ease)
4456            .onComplete(page.completeTween)
4457            .start();
4458        }
4459        else {
4460          if (point == null) {
4461            page.currentTween = new TWEEN.Tween(init).delay(0)
4462              .to(end, page.parent.duration)
4463              .onUpdate(function () {
4464                update(this);
4465              }).easing(TWEEN.Easing.Sinusoidal.Out)
4466              .onComplete(page.completeTween)
4467              .start();
4468          }
4469          else {
4470            page.currentTween = new TWEEN.Tween(init).delay(0)
4471              .to(end, tempDuration)
4472              .onUpdate(function () {
4473                update(this);
4474              }).easing(TWEEN.Easing.Sinusoidal.Out)
4475              .onComplete(page.completeTween);
4476            page.currentTween.start();
4477          }
4478        }
4479        //page.currentTween.parent= page;
4480
4481      },
4482      frontImage: function (texture, callback) {
4483        var _this = this;
4484
4485        function completed() {
4486          _this.front.css({
4487            backgroundImage: bgImage(texture)
4488          });
4489          if (callback != null) callback();
4490        }
4491
4492        if (_this.canvasMode == true) {
4493          _this.front.find(">canvas").remove();
4494          if (texture !== defaults.textureLoadFallback) {
4495            _this.front.append($(texture));
4496          }
4497          if (callback != null) callback();
4498        }
4499        else {
4500          if (texture == defaults.textureLoadFallback) {
4501            completed();
4502          }
4503          else {
4504            _this.frontIMG.onload = completed;
4505            _this.frontIMG.src = texture;
4506          }
4507        }
4508      },
4509      backImage: function (texture, callback) {
4510        var _this = this;
4511
4512        function completed() {
4513          _this.back.css({
4514            backgroundImage: bgImage(texture)
4515          });
4516          if (callback != null) callback();
4517        }
4518
4519        if (_this.canvasMode == true) {
4520          _this.back.find(">canvas").remove();
4521          if (texture !== defaults.textureLoadFallback) {
4522            _this.back.append($(texture));
4523          }
4524          if (callback != null) callback();
4525        }
4526        else {
4527          if (texture == defaults.textureLoadFallback) {
4528            completed();
4529          }
4530          else {
4531            _this.backIMG.onload = completed;
4532            _this.backIMG.src = texture;
4533          }
4534        }
4535
4536      },
4537      updateCSS: function (css) {
4538        this.element.css(css);
4539      },
4540      resetCSS: function () {
4541        this.wrapper.css({
4542          transform: ''
4543        });
4544
4545        this.front.css({
4546          transform: '',
4547          boxShadow: ''
4548        });
4549
4550        this.back.css({
4551          transform: '',
4552          boxShadow: ''
4553        });
4554      },
4555      clearTween: function (skipRefresh) {
4556        this.currentTween.stop();
4557        this.completeTween(skipRefresh == true);
4558        this.resetCSS();
4559      }
4560
4561    };
4562
4563    return PageCSS;
4564  })();
4565
4566  var BookCSS = (function (_super) {
4567    __extends(BookCSS, _super);
4568
4569    function updateFolding(dragPage) {
4570      dragPage.parent.container.find(".df-folding").removeClass("df-folding");
4571      dragPage.element.addClass("df-folding");
4572    }
4573
4574    function hasFlipping(book) {
4575      var hasFlipping = false;
4576      for (var pageCount = 0; pageCount < book.pages.length; pageCount++) {
4577        var page = book.pages[pageCount];
4578        if (page.isFlipping == true) {
4579          hasFlipping = true;
4580          break;
4581        }
4582      }
4583      return hasFlipping;
4584    }
4585
4586    function BookCSS(parameters, container) {
4587      //parameters = extendOptions(parameters);
4588
4589      //_super.call(this, parameters, stage);
4590      var _this = this;
4591      _this.type = "BookCSS";
4592      _this.images = parameters.images || [];
4593      _this.pageCount = parameters.pageCount || 2;
4594      //_this.segments = parameters.segments = 5;
4595
4596      _this.foldSense = 50;
4597
4598      _this.stackCount = 4;
4599      _this.mode = "css";
4600      _this.pages = [];
4601      _this.duration = parameters.duration;
4602
4603      _this.container = $(container);
4604      _this.options = parameters;
4605      _this.drag = drag.none;
4606      _this.pageCount = (_this.pageCount == 1 ? _this.pageCount : Math.ceil(_this.pageCount / 2) * 2);
4607      _this.pageMode = parameters.pageMode || ((isMobile || _this.pageCount <= 2) ? DFLIP.PAGE_MODE.SINGLE
4608                                                                                  : DFLIP.PAGE_MODE.DOUBLE);
4609
4610      _this.singlePageMode = parameters.singlePageMode || (isMobile ? DFLIP.SINGLE_PAGE_MODE.BOOKLET
4611                                                                    : DFLIP.SINGLE_PAGE_MODE.ZOOM);
4612
4613      _this.swipe_threshold = isMobile ? 15 : 50;
4614
4615      _this.direction = parameters.direction || DFLIP.DIRECTION.LTR;
4616
4617      _this.startPage = 1;
4618      _this.endPage = _this.pageCount;
4619
4620      _this._activePage = parameters.openPage || _this.startPage;
4621
4622      _this.hardConfig = parameters.hard;
4623      //var foldTime = null;
4624      has3d = 'WebKitCSSMatrix' in window || (document.body && 'MozPerspective' in document.body.style);
4625
4626      _this.animateF = function () {
4627        if (TWEEN.getAll().length > 0)
4628          TWEEN.update();
4629        else
4630          clearInterval(_this.animate);
4631      };
4632
4633      _this.init(parameters);
4634
4635      _this.skipDrag = false;
4636
4637      function checkPage(point) {
4638        if (_this.dragPage != point.page && point.page.visible == true) {
4639          _this.dragPage.clearTween(true);
4640          _this.dragPage = point.page;
4641          _this.corner = point.corner;
4642          _this.dragPage.pendingPoint = point;
4643        }
4644      }
4645
4646      var mouseMove = function (event) {
4647          //event.preventDefault();
4648          var point = _this.eventToPoint(event);
4649          if (event.touches != null && event.touches.length == 2 && _this.startTouches != null) {
4650            //return;
4651            // _this.startTouches = event.touches;
4652            _this.zoomDirty = true;
4653            var touchCenter = utils.getVectorAvg(utils.getTouches(event, _this.container.offset())),
4654              newScale = utils.calculateScale(_this.startTouches, utils.getTouches(event)),
4655              scale = newScale / _this.lastScale;
4656
4657            var zoom = _this.contentProvider.zoomScale,
4658              x = touchCenter.x,
4659              y = touchCenter.y;
4660
4661            _this.stage.css({
4662              transform: "translate3d(" + _this.left + "px," + _this.top + "px,0) scale3d(" + newScale + "," + newScale + ",1)"
4663            });
4664
4665            _this.lastScale = newScale;
4666
4667            _this.lastZoomCenter = touchCenter;
4668            event.preventDefault();
4669          }
4670
4671          if ((event.touches != null && event.touches.length > 1) || _this.startPoint == null || _this.startTouches != null) return;
4672
4673          var targetPage = _this.dragPage || point.page;
4674
4675          if (_this.contentProvider.zoomScale !== 1) {
4676            if ((event.touches != null || _this.isPanning == true)) {
4677              _this.pan(point);
4678              event.preventDefault();
4679            }
4680          }
4681          else {
4682            if (_this.skipDrag !== true) {
4683              //if (_this.cancelMouse != true) {
4684
4685              var distance = point.distance;//_this.getDistance(event);//point.x < _this.pageWidth ? point.x : _this.fullWidth - point.x;
4686
4687              if (!hasFlipping(_this)) {
4688
4689
4690                if ((_this.dragPage != null) || (point.isInside == true)) {
4691                  //$(".quick-hint").html(distance);
4692                  if (_this.dragPage != null) {
4693                    log("set mouse down move");
4694                  }
4695                  else {
4696                    point.y = limitAt(point.y, 1, _this.height - 1);
4697                    point.x = limitAt(point.x, 1, point.fullWidth - 1);
4698                  }
4699
4700                  var corner = _this.corner || point.corner;
4701                  if (targetPage.isHard) {
4702                    var isRight = corner == DFLIP.CORNERS.BR || corner == DFLIP.CORNERS.TR;
4703
4704                    var angle = angleByDistance(point.distance, point.fullWidth);
4705
4706                    targetPage.updateAngle(angle * (isRight ? -1 : 1), isRight);
4707
4708                  }
4709                  else {
4710                    targetPage.updatePoint(point, _this);
4711                  }
4712
4713                  targetPage.magnetic = true;
4714                  targetPage.magneticCorner = point.corner;
4715                  event.preventDefault();
4716                  //point.page.updatePoint(point);
4717                }
4718
4719                if (_this.dragPage == null && targetPage != null && point.isInside == false && targetPage.magnetic == true) {
4720                  targetPage.pendingPoint = point;
4721                  targetPage.animateToReset = true;
4722                  _this.corner = targetPage.magneticCorner;
4723                  _this.animatePage(targetPage);
4724                  targetPage.pendingPoint = null;
4725                  targetPage.magnetic = false;
4726                  targetPage.magneticCorner = null;
4727                }
4728
4729                if (_this.isPanning == true && _this.dragPage == null && _this.contentProvider.zoomScale == 1) {
4730                  //check if swipe has happened
4731                  //console.log(_this.lastPos - point.x,performance.now()-_this.lastTime);
4732                  var swipe_dist = point.x - _this.lastPos,
4733                    swipe_time = performance.now() - _this.lastTime;
4734                  if (Math.abs(swipe_dist) > _this.swipe_threshold) {
4735                    //swipe has triggered
4736                    //_this.dragPage.pendingPoint = point;
4737                    if (swipe_dist < 0) {
4738                      _this.next();
4739                    }
4740                    else {
4741                      _this.prev();
4742                    }
4743                    _this.drag = drag.none;
4744                    _this.isPanning = false;
4745                    event.preventDefault();
4746                  }
4747                  _this.lastPos = point.x;
4748                  _this.lastTime = performance.now();
4749
4750                }
4751              }
4752            }
4753          }
4754
4755        },
4756        mouseUp = function (event) {
4757          if (event.touches != null && event.touches.length == 0) {
4758            var zoom = _this.contentProvider.zoomScale;
4759            if (_this.zoomDirty == true) {
4760              _this.previewObject.contentProvider.zoomScale =
4761                utils.limitAt(_this.previewObject.contentProvider.zoomScale * _this.lastScale,
4762                  1, _this.previewObject.contentProvider.maxZoom);
4763              _this.previewObject.zoomValue = _this.previewObject.contentProvider.zoomScale * 1;
4764              //_this.previewObject.zoom(_this.lastScale < 1 ? -1 : 1);
4765              //console.log(_this.previewObject.contentProvider.zoomScale * _this.lastScale,_this.previewObject.contentProvider.maxZoom)
4766              //_this.previewObject.pendingZoom = true;
4767              _this.previewObject.resize();
4768              _this.zoomDirty = false;
4769            }
4770            _this.wrapper.css({
4771              transform: ""
4772            });
4773            _this.lastScale = null;
4774            _this.startTouches = null;
4775          }
4776          _this.isPanning = false;
4777          if (event.touches != null && event.touches.length > 1) return;
4778          if (_this.skipDrag !== true) {
4779            //completeFold();
4780            var point = _this.eventToPoint(event);
4781            if (_this.dragPage) {
4782              event.preventDefault();
4783
4784              /*							if (_this.animate != null) {
4785               clearInterval(_this.animate);
4786               }
4787
4788               _this.animate = setInterval(_this.animateF, 30);
4789
4790               _this.dragPage.tween(point);*/
4791
4792              //use something like pending point
4793              // detect the next page anbd call the updatepage
4794              //will be better
4795
4796              _this.dragPage.pendingPoint = point;
4797              if (point.x == _this.startPoint.x && point.y == _this.startPoint.y && point.isInside == true) {
4798
4799                if (_this.corner == DFLIP.CORNERS.BR || _this.corner == DFLIP.CORNERS.TR) {
4800                  checkPage(point);
4801                  if (_this.dragPage.isFlipping !== true)
4802                    _this.next();
4803                }
4804                else if (_this.corner == DFLIP.CORNERS.BL || _this.corner == DFLIP.CORNERS.TL) {
4805                  checkPage(point);
4806                  if (_this.dragPage.isFlipping !== true)
4807                    _this.prev();
4808                }
4809              }
4810              else if (_this.dragPage.isFlipping !== true) {
4811                if (point.distance > point.fullWidth / 2) {
4812                  if (point.x > point.fullWidth / 2)
4813                    _this.prev();
4814                  else
4815                    _this.next();
4816                }
4817                else {
4818                  _this.dragPage.animateToReset = true;
4819                  _this.animatePage(_this.dragPage);
4820                }
4821              }
4822              //_this.dragPage.animateToReset = true;
4823              if (_this.dragPage) {
4824                _this.dragPage.pendingPoint = null;
4825                _this.dragPage.magnetic = false;
4826              }
4827            }
4828            else {
4829              //detect click
4830              /*if(_this.wrapper[0].contains(event.target) && _this.contentProvider.zoomScale == 1 && point.x == _this.startPoint.x && point.y == _this.startPoint.y && point.isInsidePage && _this.startPoint.page == point.page && !point.page.isFlipping && event.srcElement.nodeName!=="A"){
4831               if(_this.startPoint.page.side ==0){
4832               _this.prev();
4833               _this.startPoint.page = null;
4834               }
4835               else{
4836               _this.next();
4837               _this.startPoint.page = null;
4838               }
4839               }*/
4840            }
4841
4842            _this.drag = drag.none;
4843
4844            //_this.dragPage = null;
4845            //_this.corner = DFLIP.CORNERS.NONE;
4846            //log("set mouse up");
4847          }
4848
4849        },
4850        mouseClick = function (event) {
4851
4852          var point = _this.eventToPoint(event);
4853
4854          var element = event.srcElement || event.originalTarget;
4855
4856          if (_this.dragPage && _this.dragPage.magnetic) return;
4857
4858          if (_this.wrapper[0].contains(event.target) && _this.contentProvider.zoomScale == 1 && point.x == _this.startPoint.x && point.y == _this.startPoint.y && point.isInsidePage && _this.startPoint.page == point.page && !point.page.isFlipping && element.nodeName !== "A") {
4859
4860            if (_this.startPoint.page.side == 0) {
4861              _this.corner = DFLIP.CORNERS.TL;
4862              _this.prev();
4863              _this.startPoint.page = null;
4864            }
4865            else {
4866              _this.corner = DFLIP.CORNERS.TR;
4867              _this.next();
4868              _this.startPoint.page = null;
4869            }
4870            _this.isPanning = false;
4871          }
4872
4873        },
4874        mouseDown = function (event) {
4875          if (event.touches != null && event.touches.length == 2 && _this.startTouches == null) {
4876            _this.startTouches = utils.getTouches(event);
4877            _this.lastScale = 1;
4878          }
4879          if ((event.touches != null && event.touches.length > 1) || (event.touches == null && event.button !== 0)) return;
4880          var point = _this.eventToPoint(event);
4881          _this.startPoint = point;
4882          _this.left = _this.left || 0;
4883          _this.top = _this.top || 0;
4884          _this.isPanning = true;
4885          _this.lastPos = point.x;
4886          _this.lastTime = performance.now();
4887
4888          if (_this.skipDrag !== true) {
4889
4890            if (point.isInside == true && !hasFlipping(_this)) {
4891              _this.startPoint = point;
4892              _this.drag = point.drag;
4893              _this.dragPage = point.page;
4894
4895              _this.corner = point.corner;
4896
4897              log(_this.corner);
4898
4899              updateFolding(_this.dragPage);
4900              //log("set mouse down");
4901              if (point.page.isHard) {
4902
4903              }
4904              else {
4905                point.page.updatePoint(point, _this);
4906              }
4907              if (point.page.name == "0") {
4908                _this.shadow.css({
4909                  width: '50%',
4910                  left: _this.direction == DFLIP.DIRECTION.RTL ? 0 : '50%',
4911                  transitionDelay: ''
4912                });
4913              }
4914              else if (point.page.name == Math.ceil(_this.pageCount / 2) - 1) {
4915                _this.shadow.css({
4916                  width: '50%',
4917                  left: _this.direction == DFLIP.DIRECTION.RTL ? '50%' : 0,
4918                  transitionDelay: ''
4919                });
4920              }
4921            }
4922          }
4923        },
4924        onMouseWheel = function (event) {
4925          var delta = 0;
4926
4927          //var zoom = _this.contentProvider.zoomScale > 1;
4928          if (event.wheelDelta != null) { // WebKit / Opera / Explorer 9
4929
4930            delta = event.wheelDelta / 120;
4931
4932          }
4933          else if (event.detail != null) { // Firefox
4934
4935            delta = -event.detail / 3;
4936
4937          }
4938
4939          var zoom1 = _this.contentProvider.zoomScale,
4940            maxZoom = _this.contentProvider.maxZoom;
4941
4942          if (delta) {
4943
4944            if ((delta > 0 && zoom1 < maxZoom) || (delta < 0 && zoom1 > 1)) {
4945
4946              event.stopPropagation();
4947              event.preventDefault();
4948
4949              var pointOld = _this.eventToPoint(event);
4950              var pointNew = _this.eventToPoint(event);
4951
4952              var origin = {x: _this.container.width() / 2, y: -23 + _this.container.height() / 2};
4953
4954              _this.previewObject.zoom(delta);
4955
4956              var zoom2 = _this.contentProvider.zoomScale;
4957              if (zoom1 !== zoom2) {
4958                var dz = (zoom2 / zoom1);
4959
4960                //fix zoom to previous center
4961                if (zoom2 == 1) {
4962                  _this.left = 0;
4963                  _this.top = 0;
4964                }
4965                else {
4966                  _this.left *= dz;
4967                  _this.top *= dz;
4968                }
4969
4970                //fix zoom to previous pointer
4971                var dx = (pointOld.raw.x - origin.x) * dz,
4972                  dy = (pointOld.raw.y - origin.y) * dz;
4973
4974                pointNew.raw.x = origin.x + dx;// origin.x + dz * (point.x-origin.x);
4975                pointNew.raw.y = origin.y + dy;// origin.y + dz * (point.y-origin.y);
4976
4977                _this.startPoint = pointNew;
4978                //console.log(pointOld.raw.x - origin.x,dx,pointOld.raw.y - origin.y,dy,pointNew.raw,_this.startPoint.raw);
4979                _this.pan(pointOld);
4980
4981                var targetPage = _this.dragPage || pointOld.page;
4982                if (_this.dragPage == null && targetPage != null && pointOld.isInside == true && targetPage.magnetic == true) {
4983                  targetPage.pendingPoint = pointOld;
4984                  targetPage.animateToReset = true;
4985                  _this.corner = targetPage.magneticCorner;
4986                  _this.animatePage(targetPage);
4987                  targetPage.pendingPoint = null;
4988                  targetPage.magnetic = false;
4989                  targetPage.magneticCorner = null;
4990                }
4991              }
4992
4993            }
4994          }
4995
4996        };
4997
4998      var containerDom = _this.container[0];
4999      var stageDom = _this.stage[0];
5000      if (containerDom) {
5001        stageDom.addEventListener("mousemove", mouseMove, false);
5002        stageDom.addEventListener("touchmove", mouseMove, false);
5003
5004        stageDom.addEventListener("mousedown", mouseDown, false);
5005        stageDom.addEventListener("click", mouseClick, false);
5006        stageDom.addEventListener("mouseup", mouseUp, false);
5007        stageDom.addEventListener("touchend", mouseUp, false);
5008        stageDom.addEventListener("touchstart", mouseDown, false);
5009
5010        if (_this.options.scrollWheel == true) {
5011          //lets not trigger scroll when in outline or another
5012          stageDom.addEventListener('mousewheel', onMouseWheel, false);
5013          stageDom.addEventListener('DOMMouseScroll', onMouseWheel, false); // firefox
5014        }
5015      }
5016
5017      this.dispose = function () {
5018        stageDom.removeEventListener("mousemove", mouseMove, false);
5019        stageDom.removeEventListener("touchmove", mouseMove, false);
5020
5021        stageDom.removeEventListener("mousedown", mouseDown, false);
5022        stageDom.removeEventListener("click", mouseClick, false);
5023        stageDom.removeEventListener("mouseup", mouseUp, false);
5024        stageDom.removeEventListener("touchend", mouseUp, false);
5025        stageDom.removeEventListener("touchstart", mouseDown, false);
5026
5027        if (_this.options.scrollWheel == true) {
5028          stageDom.removeEventListener('mousewheel', onMouseWheel, false);
5029          stageDom.removeEventListener('DOMMouseScroll', onMouseWheel, false); // firefox
5030        }
5031        _this.updatePageCallback = null;
5032        _this.flipCallback = null;
5033        _this.animateF = null;
5034        _this.stage.remove();
5035
5036      };
5037    }
5038
5039    BookCSS.prototype = {
5040      add: function (object) {
5041        if (object instanceof PageCSS)
5042          this.container.append($(object.element));
5043        else
5044          this.container.append($(object));
5045      },
5046      pan: function (point) {
5047        var origin = this.startPoint;
5048        var scale = this.contentProvider.zoomScale;
5049
5050        var left = (this.left + (point.raw.x - origin.raw.x)),
5051          top = (this.top + (point.raw.y - origin.raw.y));
5052
5053        //round removes blur due to decimal value in transform.
5054        this.left = Math.round(limitAt(left, -this.shiftWidth, this.shiftWidth));
5055        this.top = Math.round(limitAt(top, -this.shiftHeight, this.shiftHeight));
5056
5057        if (scale == 1) {
5058          this.left = 0;
5059          this.top = 0;
5060        }
5061
5062        this.startPoint = point;
5063
5064        //console.log(point, origin);
5065        this.stage.css({
5066          transform: "translate3d(" + this.left + "px," + this.top + "px,0)"
5067        });
5068
5069        //var a = book.wrapper.height();
5070      },
5071      getPageByNumber: function (pageNumber) {
5072        var relativePageNumber = isBookletMode(this) ? (isRTLMode(this) ? pageNumber + 1 : pageNumber)
5073                                                     : Math.floor((pageNumber - 1) / 2);
5074        var page;
5075        for (var count = 0; count < this.pages.length; count++) {
5076          if (relativePageNumber == parseInt(this.pages[count].name, 10))
5077            page = this.pages[count];
5078        }
5079        return page;
5080      },
5081      getPageSide: function (pageNumber) {
5082
5083        var isRTL = this.direction == DFLIP.DIRECTION.RTL;
5084
5085        var page = this.getPageByNumber(pageNumber);
5086        if (page == null) return;
5087        if (isBookletMode(this)) return isRTL ? page.front : page.back;
5088        if (pageNumber % 2 == 0)
5089          return isRTL ? page.back : page.front;
5090        else
5091          return isRTL ? page.front : page.back;
5092      },
5093      getContentLayer: function (pageNumber) {
5094        var pageSide = this.getPageSide(pageNumber);
5095        return pageSide == null ? null : pageSide.contentLayer;
5096      }
5097    };
5098
5099    BookCSS.prototype.init = function (parameters) {
5100      var _this = this;
5101      _this.stage = $(html.div, {
5102        class: "df-book-stage"
5103      });
5104      _this.wrapper = $(html.div, {
5105        class: "df-book-wrapper"
5106      });
5107      _this.shadow = $(html.div, {
5108        class: "df-book-shadow"
5109      });
5110      //_this.resize();
5111      _this.container.append(_this.stage);
5112      _this.stage.append(_this.wrapper);
5113      _this.wrapper.append(_this.shadow);
5114      /*			_this.nextButton = $(html.div, {
5115       class: "df-book-next-button df-book-side-buttons " + parameters.icons['altnext']
5116       }).appendTo(_this.wrapper).on("click", function () {
5117       _this.next();
5118       });
5119       _this.prevButton = $(html.div, {
5120       class: "df-book-prev-button df-book-side-buttons " + parameters.icons['altprev']
5121       }).appendTo(_this.wrapper).on("click", function () {
5122       _this.prev();
5123       });*/
5124
5125
5126      //_this.container.height(parameters.height);
5127
5128      _this.createStack(parameters);
5129    };
5130
5131    BookCSS.prototype.createStack = function (parameters) {
5132
5133      var colors = "red,green,blue,yellow,orange,black".split(",");
5134
5135      for (var _stackCount = 0; _stackCount < this.stackCount; _stackCount++) {
5136        parameters.angles = [, this.stackCount - _stackCount];//[1] = (this.stackCount - _stackCount);
5137        parameters.stiffness = (this.stackCount - _stackCount) / 100;
5138
5139        var clone = new PageCSS(parameters);
5140        clone.angles[1] = 180;
5141        clone.index = _stackCount;
5142        clone.parent = this;
5143        clone.textureReady = false;
5144        clone.textureRequested = false;
5145        this.wrapper.append(clone.element);
5146        clone.isFlipping = false;
5147        this.pages.push(clone);
5148        clone.color = colors[_stackCount];
5149        //for (var _count = 0; _count < 4; _count++) {
5150        //    clone.element.css({
5151        //        backgroundColor : colors[_stackCount]
5152        //    });
5153        //}
5154      }
5155
5156      this.children = this.pages;
5157    };
5158
5159    BookCSS.prototype.isPageHard = function (pageNumber) {
5160
5161      return utils.isHardPage(this.hardConfig, pageNumber, this.pageCount, isBookletMode(this));
5162
5163    };
5164
5165    BookCSS.prototype.setDuration = function (_duration) {
5166      this.duration = _duration;
5167    };
5168
5169    BookCSS.prototype.moveBy = function (step) {
5170      var nextPage = this._activePage + step;
5171
5172      nextPage = limitAt(nextPage, this.startPage, this.endPage);
5173      if (this.firstFlipped != true) {
5174        this.previewObject.analytics({
5175          eventAction: "First Page Flip",
5176          options: this.previewObject.options
5177        });
5178        this.firstFlipped = true;
5179      }
5180      this.gotoPage(nextPage);
5181    };
5182
5183    BookCSS.prototype.next = function (step) {
5184      if (step == null)
5185        step =
5186          (this.direction == DFLIP.DIRECTION.RTL)
5187          ? -this.pageMode : this.pageMode;
5188
5189      this.moveBy(step);
5190    };
5191
5192    BookCSS.prototype.prev = function (step) {
5193      if (step == null)
5194        step =
5195          (this.direction == DFLIP.DIRECTION.RTL)
5196          ? this.pageMode : -this.pageMode;
5197
5198      this.moveBy(step);
5199    };
5200    BookCSS.prototype.eventToPoint = function (event) {
5201
5202      event = fixMouseEvent(event);
5203
5204      var wrapper = this.wrapper,
5205        pages = this.pages,
5206        pageWidth = this.pageWidth,
5207        fullWidth = this.fullWidth,
5208        height = this.height,
5209        win = $(window),
5210        point = {x: event.clientX, y: event.clientY};
5211
5212      var left = point.x - wrapper[0].getBoundingClientRect().left;// + win['scrollLeft']();
5213
5214      var top = point.y - wrapper[0].getBoundingClientRect().top;// + win['scrollTop']();
5215
5216      point.x = point.x - this.container[0].getBoundingClientRect().left;
5217      point.y = point.y - this.container[0].getBoundingClientRect().top;
5218
5219      var distance = (this.drag == drag.none)
5220                     ? left < pageWidth ? left : fullWidth - left
5221                     : this.drag == drag.left ? left : fullWidth - left;
5222
5223      var page = //((left >= 0 && left <= fullWidth)?
5224        (left < pageWidth ? pages[this.stackCount / 2 - 1] : pages[this.stackCount / 2]);
5225
5226      var pageDrag = left < this.foldSense ? drag.left
5227                                           : (left > fullWidth - this.foldSense) ? drag.right : drag.none;
5228
5229      //determine the corner
5230      var x = left,
5231        y = top,
5232        h = height,
5233        w = fullWidth,
5234        delta = this.foldSense,
5235        corners = DFLIP.CORNERS,
5236        corner;
5237
5238      if (x >= 0 && x < delta) {
5239        if (y >= 0 && y <= delta)
5240          corner = corners.TL;
5241        else if (y >= h - delta && y <= h)
5242          corner = corners.BL;
5243        else if (y > delta && y < h - delta)
5244          corner = corners.L;
5245        else
5246          corner = corners.NONE;
5247      }
5248      else if (x >= w - delta && x <= w) {
5249        if (y >= 0 && y <= delta)
5250          corner = corners.TR;
5251        else if (y >= h - delta && y <= h)
5252          corner = corners.BR;
5253        else if (y > delta && y < h - delta)
5254          corner = corners.R;
5255        else
5256          corner = corners.NONE;
5257      }
5258      else
5259        corner = corners.NONE;
5260
5261      return {
5262        isInsidePage: x >= 0 && x <= w && y >= 0 && y <= h,
5263        isInside: corner !== corners.NONE && corner !== corners.L && corner !== corners.R,
5264        x: left,
5265        y: top,
5266        fullWidth: fullWidth,
5267        rawDistance: fullWidth - left,
5268        distance: distance,
5269        page: page,
5270        drag: pageDrag,
5271        foldSense: this.foldSense,
5272        event: event,
5273        raw: point,
5274        corner: corner
5275      };
5276    };
5277
5278    BookCSS.prototype.gotoPage = function (pageNumber) {
5279      pageNumber = parseInt(pageNumber, 10);
5280      this._activePage = pageNumber;
5281
5282      if (this.autoPlay == true) {
5283        this.previewObject.setAutoPlay(this.autoPlay);
5284      }
5285      this.updatePage(pageNumber);
5286      if (this && this.thumblist && this.thumblist.review)
5287        this.thumblist.review();
5288    };
5289
5290    BookCSS.prototype.refresh = function () {
5291      this.updatePage(this._activePage);
5292      if (this.flipCallback != null) this.flipCallback();
5293    };
5294
5295    BookCSS.prototype.updatePage = function (pageNumber) {
5296
5297      var isRTL = (this.direction == DFLIP.DIRECTION.RTL),
5298        isBooklet = isBookletMode(this),
5299        newBaseNumber = getBasePage(pageNumber);
5300
5301      var pageDivisor = isBooklet ? 1 : 2;
5302
5303      pageNumber = Math.floor((pageNumber / pageDivisor));
5304
5305      if (isRTL) pageNumber = this.pageCount / pageDivisor - pageNumber;
5306
5307      var oldBaseNumber = this.oldBaseNumber || 0;
5308      var pageCount = this.pageCount / pageDivisor;
5309      var stackCount = this.stackCount;
5310
5311      var midPoint = Math.floor(stackCount / 2);
5312
5313      if (oldBaseNumber > pageNumber) {
5314        this.children[stackCount - 1].skipFlip = true;
5315        this.children.unshift(this.children.pop());
5316      }
5317      else if (oldBaseNumber < pageNumber) {
5318        this.children[0].skipFlip = true;
5319        this.children.push(this.children.shift());
5320      }
5321
5322      for (var _pageCount = 0; _pageCount < stackCount; _pageCount++) {
5323        var page = this.children[_pageCount];
5324
5325        if (oldBaseNumber !== pageNumber) {
5326          if (page.currentTween != null) {
5327            page.clearTween(true);
5328            //page.currentTween.stop();
5329            //page.completeTween(true);
5330            //page.resetCSS();
5331            //page.currentTween = null;
5332          }
5333        }
5334
5335        var oldSide = page.side;
5336        var newSide;
5337        var relativePageNumber = pageNumber - midPoint + _pageCount;
5338        if (isRTL) relativePageNumber = isBooklet ? this.pageCount - relativePageNumber
5339                                                  : Math.floor(this.pageCount / 2) - relativePageNumber - 1;
5340
5341        var oldName = page.name;
5342
5343        page.isHard = this.isPageHard(relativePageNumber);
5344        if (page.isHard) {
5345          page.element.addClass("df-hard-page");
5346        }
5347        else {
5348          page.element.removeClass("df-hard-page");
5349          page.front.css({display: "block"});
5350          page.back.css({display: "block"});
5351        }
5352        if (relativePageNumber == 0 || relativePageNumber == pageCount) {
5353          page.element.addClass("df-cover-page");
5354        }
5355        else {
5356          page.element.removeClass("df-cover-page");
5357        }
5358
5359        var oldPageNumber = $(page.element).attr("pageNumber");
5360        if (oldPageNumber != relativePageNumber) {
5361          page.front.contentLayer.empty();
5362          page.back.contentLayer.empty();
5363        }
5364        $(page.element).attr("pageNumber", relativePageNumber);
5365
5366
5367        //Sizing
5368        page.isEdge = false; //true;
5369        if (_pageCount == 0) {
5370
5371        }
5372        else if (_pageCount == stackCount - 1) {
5373
5374        }
5375        else {
5376
5377          page.isEdge = false;
5378        }
5379
5380
5381        if (_pageCount < midPoint) {
5382          newSide = drag.left;
5383        }
5384        else {
5385          newSide = drag.right;
5386        }
5387
5388
5389        if (page.isFlipping == false) {
5390
5391          if (newSide !== oldSide && page.skipFlip == false) {
5392
5393            this.animatePage(page);
5394
5395            if (this.preFlipCallback != null)
5396              this.preFlipCallback();
5397
5398          }
5399          else {
5400            page.skipFlip = false;
5401            page.element.removeClass("df-flipping df-quick-turn df-folding df-left-side df-right-side");
5402            page.element.addClass((_pageCount < midPoint) ? "df-left-side" : "df-right-side");
5403            page.side = newSide;
5404          }
5405        }
5406
5407        page.visible = isBooklet
5408                       ? (isRTL
5409
5410                          ? (_pageCount < midPoint || page.isFlipping)
5411                          : (_pageCount >= midPoint || page.isFlipping))
5412
5413                       : ((relativePageNumber >= 0 && relativePageNumber < pageCount) || (isBooklet && relativePageNumber == pageCount));
5414
5415        if (this.requestPage != null && page.visible == true) {
5416
5417          page.name = relativePageNumber.toString();
5418          if (page.name != oldName) {
5419
5420            page.backTextureLoaded = false;
5421            page.frontTextureLoaded = false;
5422            page.backPageStamp = "-1";
5423            page.frontPageStamp = "-1";
5424            page.thumbLoaded = false;
5425            page.front.contentLayer.html("");
5426            page.back.contentLayer.html("");
5427            //if (oldName !== '-2') {
5428            //canvas clearing
5429            page.frontImage(defaults.textureLoadFallback);
5430            page.backImage(defaults.textureLoadFallback);
5431            //}
5432            this.requestPage();
5433
5434          }
5435        }
5436
5437        page.oldDepth = page.depth;
5438        page.updateCSS({
5439          display: page.visible == true ? "block" : "none",
5440          zIndex: 6 + (_pageCount < midPoint ? (_pageCount - midPoint) : (midPoint - _pageCount)),
5441          transform: ''
5442        });
5443
5444        if (page.pendingPoint == null && page.isFlipping == false) {
5445          page.resetCSS();
5446        }
5447      }
5448
5449      if (TWEEN.getAll().length == 0) {
5450        clearInterval(this.animate);
5451      }
5452      $(".quick-hint").html(pageNumber);
5453
5454      this.oldBaseNumber = pageNumber;
5455
5456      if (this.updatePageCallback)
5457        this.updatePageCallback();
5458
5459    };
5460
5461    BookCSS.prototype.animatePage = function (page) {
5462      page.element.addClass("df-flipping");
5463      page.isFlipping = true;
5464
5465      if (this.animate != null) {
5466        clearInterval(this.animate);
5467      }
5468
5469      this.animate = setInterval(this.animateF, 30);
5470
5471      page.tween(page.pendingPoint);
5472    };
5473
5474    return BookCSS;
5475  })
5476  ({});
5477
5478  var FlipBook = (function (_super) {
5479
5480    __extends(FlipBook, _super);
5481
5482    function FlipBook(container, source, parameters) {
5483      _super.call(this, parameters);
5484      var _this = this;
5485
5486      _this.type = "FlipBook";
5487      _this.container = container;
5488      _this.options = parameters;
5489      _this.options.source = source;
5490      _this.contentSource = source;
5491
5492      if (parameters.height != null && parameters.height.toString().indexOf('%') < 0) {
5493        _this.container.height(Math.min(parameters.height, $(window).height()));
5494      }
5495      else {
5496        _this.container.height(parameters.height);
5497      }
5498
5499      if (_this.options.isLightBox) {
5500        window.dfLightBox.closeButton.addClass(_this.options.icons['close']);
5501      }
5502      if (_this.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL) {
5503        //currently booklet version cannot handle double sized image pages
5504        if (Array === _this.contentSource.constructor || Array.isArray(_this.contentSource) || _this.contentSource instanceof Array) {
5505          _this.options.singlePageMode = DFLIP.SINGLE_PAGE_MODE.ZOOM;
5506        }
5507        _this.container.addClass("df-double-internal");
5508      }
5509      if (!_this.options.isLightBox && _this.container.attr("id") != null) {
5510        _this.options.id = _this.container.attr("id");
5511      }
5512
5513      if (_this.options.parsed !== true && _this.options.links != null) {
5514        DFLIP.parseLinks(_this.options.links);
5515      }
5516      var webgl = _this.webgl = parameters.webgl == true && hasWebgl == true;
5517
5518      container.addClass("df-container df-loading df-init df-floating" + " df-controls-" + _this.options.controlsPosition);
5519
5520      if (_this.options.transparent == true) {
5521        container.addClass("df-transparent");
5522      }
5523      if (_this.options.direction == DFLIP.DIRECTION.RTL) {
5524        container.addClass("df-rtl");
5525      }
5526      _this.container.info = $(html.div, {
5527        class: "loading-info"
5528      }).appendTo(_this.container).html("Loading...");
5529
5530      if (userAgent.indexOf('MSIE') !== -1
5531        || navigator.appVersion.indexOf('Trident/') > 0 || (isSafari && !isIOS)) {
5532        _this.options.webgl = false; //IE 11
5533      }
5534
5535      if (!!userAgent.match(/msie\s[5-9]/i)) {
5536        _this.container.info.html("Your browser (Internet Explorer) is out of date to run DFlip Flipbook Plugin. <br><a href='http://browsehappy.com/'>Upgrade to a new one</a>").addClass("df-old-browser");
5537        container.removeClass("df-loading");
5538        return _this;
5539      }
5540
5541      var backgroundImage = parameters.backgroundImage == null || parameters.backgroundImage == '' ? ''
5542                                                                                                   : "url('" + parameters.backgroundImage + "')";
5543
5544      _this.container.css({
5545        position: "relative",
5546        overflow: "hidden",
5547        backgroundColor: parameters.backgroundColor,
5548        backgroundImage: backgroundImage
5549      });
5550
5551      if (_this.options.isLightBox == true) {
5552        _this.analytics({
5553          eventAction: "Open Book",
5554          options: _this.options
5555        });
5556      }
5557      _this.init(webgl, source);
5558
5559      if (_this.options.onCreate != null)
5560        _this.options.onCreate(_this);
5561
5562      return _this;
5563
5564    }
5565
5566    FlipBook.prototype.init = function (webgl) {
5567      var _this = this;
5568      var book = _this.target;
5569
5570      var options = _this.options;
5571
5572      if (webgl == true) {
5573
5574        var updateMockupJs = function (callback) {
5575
5576            var process3d = function () {
5577              MOCKUP.defaults.anisotropy = 0;
5578              MOCKUP.defaults.groundTexture = "blank";
5579              THREE.skipPowerOfTwo = true;
5580
5581              RegisterMockupObjects();
5582
5583              if (callback != null) callback();
5584            };
5585
5586            if (window.MOCKUP == null) {
5587              _this.updateInfo("Loading WEBGL 3D ...");
5588
5589              if (typeof define === 'function' && define.amd && window.requirejs) {
5590                requirejs.config({
5591                  "paths": {
5592                    "three": defaults.threejsSrc.replace(".js", "")
5593                  },
5594                  shim: {
5595                    'three': {
5596                      exports: 'THREE'
5597                    }
5598                  }
5599                });
5600                require(['three'], function (THREE) {
5601                  window.THREE = THREE;
5602                  getScript(defaults.mockupjsSrc + "?ver=" + DFLIP.version, function () {
5603                    process3d();
5604                  });
5605                  return THREE;
5606                });
5607              }
5608              else if (typeof define === 'function' && define.amd) {
5609                require(["three", defaults.threejsSrc.replace(".js", "")], function (ready, fx) {
5610                  ready(function () {
5611
5612                  });
5613                });
5614              }
5615              else {
5616                getScript(defaults.threejsSrc + "?ver=" + DFLIP.version, function () {
5617                  //_this.updateInfo("Loading 3D Pages ..."); this was retainnng _this and not releasing memory
5618                  getScript(defaults.mockupjsSrc + "?ver=" + DFLIP.version, function () {
5619                    process3d();
5620                  });
5621                });
5622              }
5623            }
5624            else {
5625              process3d();
5626            }
5627          }
5628        ;
5629
5630        updateMockupJs(function () {
5631
5632          //Todo: ability to use anisotropy
5633
5634          _this.container.css({
5635            minHeight: 300,
5636            minWidth: 300
5637          });
5638
5639          _this.stage = new PreviewStage(extendOptions(_this.options, {container: _this.container}));
5640          _this.stage.previewObject = _this;
5641
5642          _this.contentProvider = new ContentProvider(_this.contentSource, function (contentProvider) {
5643            // _this.pageCount = contentProvider.pageCount = utils.limitAt(contentProvider.pageCount, 1, 2 * 5);
5644            var options = {
5645              pageCount: (utils.hasCompatibility() === true
5646                          ? utils.limitAt(contentProvider.pageCount, 1, 2 * 15)
5647                          : contentProvider.pageCount),
5648              stackCount: 6,
5649              segments: 20,
5650              width: contentProvider.bookSize.width,
5651              height: contentProvider.bookSize.height
5652            };
5653
5654            // _this.checkOpenPage();
5655            _this.target = book = _this.stage.target = new MOCKUP.Book(extendOptions(_this.options, options), _this.stage);
5656            _this.extendtarget();
5657            createUI(_this.container, _this);
5658
5659            //bookStage.setTarget(_this.target);
5660            book.ui = _this.ui;
5661            book.container = _this.container;
5662            contentProvider.webgl = webgl;
5663            contentProvider.setTarget(_this.target);
5664
5665            book.getContentLayer = function (pageNumber) {
5666
5667              var isRTL = book.direction == DFLIP.DIRECTION.RTL,
5668                left = _this.stage.cssScene.divLeft.element,
5669                right = _this.stage.cssScene.divRight.element;
5670
5671              var baseActive = getBasePage(book._activePage);
5672
5673              //if(isRTL){
5674              //	if(pageNumber == 0 || pageNumber == 1) return right;
5675              //	if(pageNumber == book.pageCount) return left;
5676              //}
5677
5678              if (isBookletMode(book)) return isRTL ? left : right;
5679
5680              if (pageNumber % 2 == 0)
5681                return isRTL ? right : left;
5682              else
5683                return isRTL ? left : right;
5684              //else
5685              //	return null;
5686            };
5687            book.stage = _this.stage;
5688
5689            book.flipCallback = function () {
5690              if (_this.contentProvider) {
5691                _this.contentProvider.review("flipCallback");
5692
5693                var baseActive = getBasePage(book._activePage);
5694
5695                var width, height;
5696                var pageLeft = book.getPageByNumber(baseActive),
5697                  pageRight = book.getPageByNumber(baseActive + 1);
5698                //if (page3d != null) {
5699                //    var isLeft = (pageNumber % 2 == 0);
5700                var divLeft = book.parent.cssScene.divLeft,
5701                  divRight = book.parent.cssScene.divRight;
5702
5703                var isSingle = book.pageMode == DFLIP.PAGE_MODE.SINGLE;
5704                var isRTL = book.direction == DFLIP.DIRECTION.RTL;
5705
5706                if (pageLeft != null && divLeft != null) {
5707                  width = Math.abs(pageLeft.geometry.boundingBox.max.x - pageLeft.geometry.boundingBox.min.x);
5708                  height = Math.abs(pageLeft.geometry.boundingBox.max.z - pageLeft.geometry.boundingBox.min.z);
5709
5710                  divLeft.rotation.y = -Math.atan2(height, width) * 0.9;
5711                  divLeft.position.z = height * 0.8;
5712                  divLeft.position.x = height / 2.5;
5713                  $(divLeft.element).css({
5714                    width: width,
5715                    left: -width / 2//baseActive == 0 && isRTL == true? width
5716                    //: baseActive == book.pageCount && isRTL == true ? 0 : -width / 2
5717                  });
5718
5719                }
5720
5721                if (pageRight != null && divRight != null) {
5722                  width = Math.abs(pageRight.geometry.boundingBox.max.x - pageRight.geometry.boundingBox.min.x);
5723                  height = Math.abs(pageRight.geometry.boundingBox.max.z - pageRight.geometry.boundingBox.min.z);
5724
5725                  divRight.rotation.y = Math.atan2(height, width) * 0.9;
5726                  divRight.position.z = height * 0.8;
5727                  divRight.position.x = -height / 2.5;
5728                  $(divRight.element).css({
5729                    width: width,
5730                    left: width / 2// == 0 && isRTL == true ? 0
5731                    //: baseActive == book.pageCount && isRTL == true ? -width : width / 2
5732                  });
5733
5734                }
5735
5736                if (_this.options.onFlip != null)
5737                  _this.options.onFlip(_this);
5738              }
5739            };
5740
5741            book.resize = function () {
5742              _this.resize();
5743            }();
5744
5745            book.updatePageCallback = function () {
5746              _this.ui.update();
5747              _this.checkCenter();
5748              _this.stage.renderRequestPending = true;
5749            };
5750
5751            var divLeft = $(_this.stage.cssScene.divLeft.element);
5752            var divRight = $(_this.stage.cssScene.divRight.element);
5753
5754            book.preFlipCallback = function () {
5755              divLeft.empty();
5756              divRight.empty();
5757              if (_this.options.beforeFlip != null)
5758                _this.options.beforeFlip(_this);
5759
5760              _this.playSound();
5761            };
5762
5763            $(window).trigger("resize");
5764
5765            divLeft.css({
5766              width: contentProvider.bookSize.width,
5767              height: contentProvider.bookSize.height,
5768              left: -contentProvider.bookSize.width / 2
5769            });
5770
5771            divRight.css({
5772              width: contentProvider.bookSize.width,
5773              height: contentProvider.bookSize.height,
5774              left: contentProvider.bookSize.width / 2
5775            });
5776
5777            book.ease = TWEEN.Easing.Cubic.InOut;
5778            //book.ease = TWEEN.Easing.Quadratic.InOut;
5779            book.contentProvider = contentProvider;
5780            book.duration = _this.options.duration;
5781            book.gotoPage(book._activePage);
5782            book.flipCallback();
5783
5784            if (_this.options.isLightBox == true) {
5785              _this.analytics({
5786                eventAction: "Book Ready",
5787                options: _this.options
5788              });
5789            }
5790
5791            if (_this.options.onReady != null)
5792              _this.options.onReady(_this);
5793
5794          }, options, _this);
5795        });
5796      }
5797      else {
5798
5799        _this.contentProvider = new ContentProvider(_this.contentSource, function (contentProvider) {
5800          // _this.pageCount = contentProvider.pageCount = utils.limitAt(contentProvider.pageCount, 1, 2 * 5);
5801          var options = {
5802            pageCount: (utils.hasCompatibility() === true
5803                        ? utils.limitAt(contentProvider.pageCount, 1, 2 * 15)
5804                        : contentProvider.pageCount),
5805            contentSourceType: contentProvider.contentSourceType
5806          };
5807
5808          // _this.checkOpenPage();
5809          _this.target = book = new BookCSS(extendOptions(_this.options, options), _this.container);
5810          _this.target.previewObject = _this;
5811          _this.extendtarget();
5812          createUI(_this.container, _this);
5813          contentProvider.webgl = webgl;
5814          contentProvider.setTarget(_this.target);
5815          contentProvider.waitPeriod = 2;
5816          book.ease = TWEEN.Easing.Quadratic.InOut;
5817          book.duration = _this.options.duration;
5818
5819          /*					_this.ui.prev.hide();
5820           _this.ui.next.hide();
5821
5822           _this.ui.prev = book.prevButton;
5823           _this.ui.next = book.nextButton;*/
5824
5825          book.container = _this.container;
5826          book.updatePageCallback = function () {
5827            _this.ui.update();
5828            _this.checkCenter();
5829          };
5830
5831          book.resize = function () {
5832            _this.resize();
5833          }();
5834
5835          $(window).trigger("resize");
5836
5837          book.flipCallback = function () {
5838            if (_this.contentProvider) {
5839              _this.contentProvider.review("flipCallback");
5840
5841              if (_this.options.onFlip != null)
5842                _this.options.onFlip(_this);
5843            }
5844          };
5845
5846          book.preFlipCallback = function () {
5847            if (_this.options.beforeFlip != null)
5848              _this.options.beforeFlip(_this);
5849
5850            _this.playSound();
5851          };
5852          book.gotoPage(book._activePage);
5853          book.flipCallback();
5854
5855          if (_this.options.onReady != null)
5856            _this.options.onReady(_this);
5857          _this.analytics({
5858            eventAction: "Book Ready",
5859            options: _this.options
5860          });
5861        }, options, _this);
5862
5863      }
5864
5865
5866    }
5867    ;
5868
5869    FlipBook.prototype.extendtarget = function () {
5870      var _this = this;
5871      _this.target.previewObject = _this;
5872      _this.target.reset = function () {
5873        for (var pageCount = 0; pageCount < _this.target.children.length; pageCount++) {
5874          var page = _this.target.children[pageCount];
5875          page.skipFlip = true;
5876          page.name = '-2';
5877        }
5878        _this.contentProvider.annotedPage = '-2';
5879        _this.target.refresh();
5880
5881      }
5882    };
5883
5884    FlipBook.prototype.getURLHash = function () {
5885      if (this.options.id != null) {
5886        var hash = "dflip-" + (this.options.slug != null ? this.options.slug : this.options.id) + "/";
5887        if (this.target != null && this.target._activePage != null) {
5888          hash += this.target._activePage + "/";
5889        }
5890        window.location.hash = hash;
5891      }
5892      return window.location.href;
5893    };
5894
5895    /*
5896        Depreciated handled through getOptions
5897        FlipBook.prototype.checkOpenPage = function ()
5898        {
5899          //options value is overridden by attribute
5900          if (this.options.id != null) {
5901            var book = $("#" + this.options.id);
5902            if (book.length > 0 && book.data("page") != null) {
5903              var pageNumber = parseInt(book.data("page"), 10);
5904              if (!isNaN(pageNumber))
5905                this.options.openPage = pageNumber;
5906            }
5907          }
5908        };*/
5909
5910    FlipBook.prototype.end = function () {
5911
5912      this.target.gotoPage(this.target.endPage);
5913
5914    };
5915
5916    FlipBook.prototype.gotoPage = function (pageNumber) {
5917
5918      this.target.gotoPage(pageNumber);
5919      if (this.ui != null) this.ui.update();
5920    };
5921
5922    FlipBook.prototype.prev = function () {
5923
5924      this.target.prev();
5925
5926    };
5927
5928    FlipBook.prototype.next = function () {
5929
5930      this.target.next();
5931
5932    };
5933
5934    FlipBook.prototype.updateInfo = function (info) {
5935      if (this.container && this.container.info && this.container.info.html)
5936        this.container.info.html(info);
5937    }
5938
5939    FlipBook.prototype.analytics = function (eventData) {
5940      if (this.options.enableAnalytics == true) {
5941        try {
5942          var anaytics = window.ga || window.__gaTracker;
5943          var options = eventData.options,
5944            eventLabel = undefined;
5945          if (options) {
5946            eventLabel = options.bookTitle || options.slug || options.id;
5947          }
5948          anaytics("send", {
5949            hitType: 'event',
5950            eventCategory: 'Flipbook',
5951            eventAction: eventData.eventAction,
5952            eventLabel: eventLabel
5953          });
5954        } catch (e) {
5955          //silent suppress
5956        }
5957      }
5958    }
5959    return FlipBook;
5960
5961  })(PreviewObject);
5962
5963  $.fn.extend({
5964
5965    shelf: function () {
5966
5967    },
5968    flipBook: function (source, options) {
5969      return new FlipBook($(this), source, extendDFlipOptions(options));
5970    }
5971  });
5972
5973})
5974(DFLIP, jQuery);
5975
5976
5977//Polyfills
5978
5979/**
5980 * Blob.js Polyfill
5981 * A Blob implementation.
5982 * 2014-07-24
5983 *
5984 * By Eli Grey, http://eligrey.com
5985 * By Devin Samarin, https://github.com/dsamarin
5986 * License: X11/MIT
5987 */
5988(function (view) {
5989  "use strict";
5990
5991  view.URL = view.URL || view.webkitURL;
5992
5993  if (view.Blob && view.URL) {
5994    try {
5995      new Blob;
5996      return;
5997    } catch (e) {
5998    }
5999  }
6000
6001  // Internally we use a BlobBuilder implementation to base Blob off of
vendor: 6,683 bytes, lines 6002-6193
6002  // in order to support older browsers that only have BlobBuilder
6003  var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function (view) {
6004    var
6005      get_class = function (object) {
6006        return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
6007      }, FakeBlobBuilder = function BlobBuilder() {
6008        this.data = [];
6009      }, FakeBlob = function Blob(data, type, encoding) {
6010        this.data = data;
6011        this.size = data.length;
6012        this.type = type;
6013        this.encoding = encoding;
6014      }, FBB_proto = FakeBlobBuilder.prototype, FB_proto = FakeBlob.prototype, FileReaderSync = view.FileReaderSync,
6015      FileException = function (type) {
6016        this.code = this[this.name = type];
6017      }, file_ex_codes = (
6018        "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
6019        + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
6020      ).split(" "), file_ex_code = file_ex_codes.length, real_URL = view.URL || view.webkitURL || view,
6021      real_create_object_URL = real_URL.createObjectURL, real_revoke_object_URL = real_URL.revokeObjectURL,
6022      URL = real_URL, btoa = view.btoa, atob = view.atob, ArrayBuffer = view.ArrayBuffer,
6023      Uint8Array = view.Uint8Array, origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/
6024    ;
6025    FakeBlob.fake = FB_proto.fake = true;
6026    while (file_ex_code--) {
6027      FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
6028    }
6029    // Polyfill URL
6030    if (!real_URL.createObjectURL) {
6031      URL = view.URL = function (uri) {
6032        var
6033          uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a"), uri_origin
6034        ;
6035        uri_info.href = uri;
6036        if (!("origin" in uri_info)) {
6037          if (uri_info.protocol.toLowerCase() === "data:") {
6038            uri_info.origin = null;
6039          }
6040          else {
6041            uri_origin = uri.match(origin);
6042            uri_info.origin = uri_origin && uri_origin[1];
6043          }
6044        }
6045        return uri_info;
6046      };
6047    }
6048    URL.createObjectURL = function (blob) {
6049      var
6050        type = blob.type, data_URI_header
6051      ;
6052      if (type === null) {
6053        type = "application/octet-stream";
6054      }
6055      if (blob instanceof FakeBlob) {
6056        data_URI_header = "data:" + type;
6057        if (blob.encoding === "base64") {
6058          return data_URI_header + ";base64," + blob.data;
6059        }
6060        else if (blob.encoding === "URI") {
6061          return data_URI_header + "," + decodeURIComponent(blob.data);
6062        }
6063        if (btoa) {
6064          return data_URI_header + ";base64," + btoa(blob.data);
6065        }
6066        else {
6067          return data_URI_header + "," + encodeURIComponent(blob.data);
6068        }
6069      }
6070      else if (real_create_object_URL) {
6071        return real_create_object_URL.call(real_URL, blob);
6072      }
6073    };
6074    URL.revokeObjectURL = function (object_URL) {
6075      if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
6076        real_revoke_object_URL.call(real_URL, object_URL);
6077      }
6078    };
6079    FBB_proto.append = function (data/*, endings*/) {
6080      var bb = this.data;
6081      // decode data to a binary string
6082      if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
6083        var
6084          str = "", buf = new Uint8Array(data), i = 0, buf_len = buf.length
6085        ;
6086        for (; i < buf_len; i++) {
6087          str += String.fromCharCode(buf[i]);
6088        }
6089        bb.push(str);
6090      }
6091      else if (get_class(data) === "Blob" || get_class(data) === "File") {
6092        if (FileReaderSync) {
6093          var fr = new FileReaderSync;
6094          bb.push(fr.readAsBinaryString(data));
6095        }
6096        else {
6097          // async FileReader won't work as BlobBuilder is sync
6098          throw new FileException("NOT_READABLE_ERR");
6099        }
6100      }
6101      else if (data instanceof FakeBlob) {
6102        if (data.encoding === "base64" && atob) {
6103          bb.push(atob(data.data));
6104        }
6105        else if (data.encoding === "URI") {
6106          bb.push(decodeURIComponent(data.data));
6107        }
6108        else if (data.encoding === "raw") {
6109          bb.push(data.data);
6110        }
6111      }
6112      else {
6113        if (typeof data !== "string") {
6114          data += ""; // convert unsupported types to strings
6115        }
6116        // decode UTF-16 to binary string
6117        bb.push(unescape(encodeURIComponent(data)));
6118      }
6119    };
6120    FBB_proto.getBlob = function (type) {
6121      if (!arguments.length) {
6122        type = null;
6123      }
6124      return new FakeBlob(this.data.join(""), type, "raw");
6125    };
6126    FBB_proto.toString = function () {
6127      return "[object BlobBuilder]";
6128    };
6129    FB_proto.slice = function (start, end, type) {
6130      var args = arguments.length;
6131      if (args < 3) {
6132        type = null;
6133      }
6134      return new FakeBlob(
6135        this.data.slice(start, args > 1 ? end : this.data.length), type, this.encoding
6136      );
6137    };
6138    FB_proto.toString = function () {
6139      return "[object Blob]";
6140    };
6141    FB_proto.close = function () {
6142      this.size = 0;
6143      delete this.data;
6144    };
6145    return FakeBlobBuilder;
6146  }(view));
6147
6148  view.Blob = function (blobParts, options) {
6149    var type = options ? (options.type || "") : "";
6150    var builder = new BlobBuilder();
6151    if (blobParts) {
6152      for (var i = 0, len = blobParts.length; i < len; i++) {
6153        if (Uint8Array && blobParts[i] instanceof Uint8Array) {
6154          builder.append(blobParts[i].buffer);
6155        }
6156        else {
6157          builder.append(blobParts[i]);
6158        }
6159      }
6160    }
6161    var blob = builder.getBlob(type);
6162    if (!blob.slice && blob.webkitSlice) {
6163      blob.slice = blob.webkitSlice;
6164    }
6165    return blob;
6166  };
6167
6168  var getPrototypeOf = Object.getPrototypeOf || function (object) {
6169    return object.__proto__;
6170  };
6171  view.Blob.prototype = getPrototypeOf(new view.Blob());
6172}(window));
6173
6174/**
6175 * canvas-toBlob.js Polyfill
6176 * A canvas.toBlob() implementation.
6177 * 2013-12-27
6178 *
6179 * By Eli Grey, http://eligrey.com and Devin Samarin, https://github.com/eboyjr
6180 * License: X11/MIT
6181 *   See https://github.com/eligrey/canvas-toBlob.js/blob/master/LICENSE.md
6182 */
6183(function (view) {
6184  "use strict";
6185  var
6186    Uint8Array = view.Uint8Array, HTMLCanvasElement = view.HTMLCanvasElement,
6187    canvas_proto = HTMLCanvasElement && HTMLCanvasElement.prototype, is_base64_regex = /\s*;\s*base64\s*(?:;|$)/i,
6188    to_data_url = "toDataURL", base64_ranks, decode_base64 = function (base64) {
6189      var
6190        len = base64.length, buffer = new Uint8Array(len / 4 * 3 | 0), i = 0, outptr = 0, last = [0, 0], state = 0,
6191        save = 0, rank, code;
6192      while (len--) {
6193        code = base64.charCodeAt(i++);
6194        rank = base64_ranks[code - 43];
6195        if (rank !== 255 && rank != null) {
6196          last[1] = last[0];
6197          last[0] = code;
6198          save = (save << 6) | rank;
6199          state++;
6200          if (state === 4) {
6201            buffer[outptr++] = save >>> 16;
6202            if (last[1] !== 61 /* padding character */) {
6203              buffer[outptr++] = save >>> 8;
6204            }
6205            if (last[0] !== 61 /* padding character */) {
6206              buffer[outptr++] = save;
6207            }
6208            state = 0;
6209          }
6210        }
6211      }
6212      // 2/3 chance there's going to be some null bytes at the end, but that
6213      // doesn't really matter with most image formats.
6214      // If it somehow matters for you, truncate the buffer up outptr.
6215      return buffer;
6216    }
6217  ;
6218  if (Uint8Array) {
6219    base64_ranks = new Uint8Array([
6220      62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
6221    ]);
6222  }
6223  if (HTMLCanvasElement && !canvas_proto.toBlob) {
6224    canvas_proto.toBlob = function (callback, type /*, ...args*/) {
6225      if (!type) {
6226        type = "image/png";
6227      }
6228      if (this.mozGetAsFile) {
6229        callback(this.mozGetAsFile("canvas", type));
6230        return;
6231      }
6232      if (this.msToBlob && /^\s*image\/png\s*(?:$|;)/i.test(type)) {
6233        callback(this.msToBlob());
6234        return;
6235      }
6236
6237      var
6238        args = Array.prototype.slice.call(arguments, 1),
6239        dataURI = this[to_data_url].apply(this, args),
6240        header_end = dataURI.indexOf(","),
6241        data = dataURI.substring(header_end + 1),
6242        is_base64 = is_base64_regex.test(dataURI.substring(0, header_end)),
6243        blob
6244      ;
6245      if (Blob.fake) {
6246        // no reason to decode a data: URI that's just going to become a data URI again
6247        blob = new Blob;
6248        if (is_base64) {
6249          blob.encoding = "base64";
6250        }
6251        else {
6252          blob.encoding = "URI";
6253        }
6254        blob.data = data;
6255        blob.size = data.length;
6256      }
6257      else if (Uint8Array) {
6258        if (is_base64) {
6259          blob = new Blob([decode_base64(data)], {type: type});
6260        }
6261        else {
6262          blob = new Blob([decodeURIComponent(data)], {type: type});
6263        }
6264      }
6265      callback(blob);
6266    };
6267
6268    if (canvas_proto.toDataURLHD) {
6269      canvas_proto.toBlobHD = function () {
6270        to_data_url = "toDataURLHD";
6271        var blob = this.toBlob();
6272        to_data_url = "toDataURL";
6273        return blob;
6274      }
6275    }
6276    else {
6277      canvas_proto.toBlobHD = canvas_proto.toBlob;
6278    }
6279  }
6280}(window));
6281
6282/**
6283 * performance.now polyfill
6284 **/
6285(function PerformanceNowPolyfill() {
6286
6287  if ('performance' in window === false) {
6288    window.performance = {};
6289  }
6290
6291  // IE 8
6292  Date.now = (Date.now || function () {
6293    return new Date().getTime();
6294  });
6295
6296  if ('now' in window.performance === false) {
6297    var offset = window.performance.timing && window.performance.timing.navigationStart
6298                 ? window.performance.timing.navigationStart
6299                 : Date.now();
6300
6301    window.performance.now = function () {
6302      return Date.now() - offset;
6303    };
6304  }
6305
6306})();
6307
6308/**
6309 * Tween.js - Licensed under the MIT license
6310 * https://github.com/tweenjs/tween.js
6311 */
6312(function TweenJs() {
6313  var TWEEN = TWEEN || (function () {
6314
6315    var _tweens = [];
6316
6317    return {
6318
6319      getAll: function () {
6320
6321        return _tweens;
6322
6323      },
6324
6325      removeAll: function () {
6326
6327        _tweens = [];
6328
6329      },
6330
6331      add: function (tween) {
6332
6333        _tweens.push(tween);
6334
6335      },
6336
6337      remove: function (tween) {
6338
6339        var i = _tweens.indexOf(tween);
6340
6341        if (i !== -1) {
6342          _tweens.splice(i, 1);
6343        }
6344
6345      },
6346
6347      update: function (time) {
6348
6349        if (_tweens.length === 0) {
6350          return false;
6351        }
6352
6353        var i = 0;
6354
6355        time = time != null ? time : window.performance.now();
6356
6357        while (i < _tweens.length) {
6358
6359          if (_tweens[i].update(time)) {
6360            i++;
6361          }
6362          else {
6363            _tweens.splice(i, 1);
6364          }
6365
6366        }
6367
6368        return true;
6369
6370      }
6371    };
6372
6373  })();
6374
6375  TWEEN.Tween = function (object) {
6376
6377    var _object = object;
6378    var _valuesStart = {};
6379    var _valuesEnd = {};
6380    var _valuesStartRepeat = {};
6381    var _duration = 1000;
6382    var _repeat = 0;
6383    var _yoyo = false;
6384    var _isPlaying = false;
6385    var _reversed = false;
6386    var _delayTime = 0;
6387    var _startTime = null;
6388    var _easingFunction = TWEEN.Easing.Linear.None;
6389    var _interpolationFunction = TWEEN.Interpolation.Linear;
6390    var _chainedTweens = [];
6391    var _onStartCallback = null;
6392    var _onStartCallbackFired = false;
6393    var _onUpdateCallback = null;
6394    var _onCompleteCallback = null;
6395    var _onStopCallback = null;
6396
6397    // Set all starting values present on the target object
6398    for (var field in object) {
6399      _valuesStart[field] = parseFloat(object[field], 10);
6400    }
6401
6402    this.to = function (properties, duration) {
6403
6404      if (duration != null) {
6405        _duration = duration;
6406      }
6407
6408      _valuesEnd = properties;
6409
6410      return this;
6411
6412    };
6413
6414    this.start = function (time) {
6415
6416      TWEEN.add(this);
6417
6418      _isPlaying = true;
6419
6420      _onStartCallbackFired = false;
6421
6422      _startTime = time != null ? time : window.performance.now();
6423      _startTime += _delayTime;
6424
6425      for (var property in _valuesEnd) {
6426
6427        // Check if an Array was provided as property value
6428        if (_valuesEnd[property] instanceof Array) {
6429
6430          if (_valuesEnd[property].length === 0) {
6431            continue;
6432          }
6433
6434          // Create a local copy of the Array with the start value at the front
6435          _valuesEnd[property] = [_object[property]].concat(_valuesEnd[property]);
6436
6437        }
6438
6439        // If `to()` specifies a property that doesn't exist in the source object,
6440        // we should not set that property in the object
6441        if (_valuesStart[property] === null) {
6442          continue;
6443        }
6444
6445        _valuesStart[property] = _object[property];
6446
6447        if ((_valuesStart[property] instanceof Array) === false) {
6448          _valuesStart[property] *= 1.0; // Ensures we're using numbers, not strings
6449        }
6450
6451        _valuesStartRepeat[property] = _valuesStart[property] || 0;
6452
6453      }
6454
6455      return this;
6456
6457    };
6458
6459    this.stop = function () {
6460
6461      if (!_isPlaying) {
6462        return this;
6463      }
6464
6465      TWEEN.remove(this);
6466      _isPlaying = false;
6467
6468      if (_onStopCallback !== null) {
6469        _onStopCallback.call(_object);
6470      }
6471
6472      this.stopChainedTweens();
6473      return this;
6474
6475    };
6476
6477    this.stopChainedTweens = function () {
6478
6479      for (var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++) {
6480        _chainedTweens[i].stop();
6481      }
6482
6483    };
6484
6485    this.complete = function () {
6486      if (!_isPlaying) {
6487        return this;
6488      }
6489
6490      TWEEN.remove(this);
6491      _isPlaying = false;
6492
6493      if (_onCompleteCallback !== null) {
6494        _onCompleteCallback.call(_object);
6495      }
6496
6497      this.completeChainedTweens();
6498      return this;
6499    };
6500
6501    this.completeChainedTweens = function () {
6502
6503      for (var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++) {
6504        _chainedTweens[i].complete();
6505      }
6506
6507    };
6508
6509    this.delay = function (amount) {
6510
6511      _delayTime = amount;
6512      return this;
6513
6514    };
6515
6516    this.repeat = function (times) {
6517
6518      _repeat = times;
6519      return this;
6520
6521    };
6522
6523    this.yoyo = function (yoyo) {
6524
6525      _yoyo = yoyo;
6526      return this;
6527
6528    };
6529
6530
6531    this.easing = function (easing) {
6532
6533      _easingFunction = easing == null ? _easingFunction : easing;
6534      return this;
6535
6536    };
6537
6538    this.interpolation = function (interpolation) {
6539
6540      _interpolationFunction = interpolation;
6541      return this;
6542
6543    };
6544
6545    this.chain = function () {
6546
6547      _chainedTweens = arguments;
6548      return this;
6549
6550    };
6551
6552    this.onStart = function (callback) {
6553
6554      _onStartCallback = callback;
6555      return this;
6556
6557    };
6558
6559    this.onUpdate = function (callback) {
6560
6561      _onUpdateCallback = callback;
6562      return this;
6563
6564    };
6565
6566    this.onComplete = function (callback) {
6567
6568      _onCompleteCallback = callback;
6569      return this;
6570
6571    };
6572
6573    this.onStop = function (callback) {
6574
6575      _onStopCallback = callback;
6576      return this;
6577
6578    };
6579
6580    this.update = function (time) {
6581
6582      var property;
6583      var elapsed;
6584      var value;
6585
6586      if (time < _startTime) {
6587        return true;
6588      }
6589
6590      if (_onStartCallbackFired === false) {
6591
6592        if (_onStartCallback !== null) {
6593          _onStartCallback.call(_object);
6594        }
6595
6596        _onStartCallbackFired = true;
6597
6598      }
6599
6600      elapsed = (time - _startTime) / _duration;
6601      elapsed = elapsed > 1 ? 1 : elapsed;
6602
6603      value = _easingFunction(elapsed);
6604
6605      for (property in _valuesEnd) {
6606
6607        // Don't update properties that do not exist in the source object
6608        if (_valuesStart[property] === null) {
6609          continue;
6610        }
6611
6612        var start = _valuesStart[property] || 0;
6613        var end = _valuesEnd[property];
6614
6615        if (end instanceof Array) {
6616
6617          _object[property] = _interpolationFunction(end, value);
6618
6619        }
6620        else {
6621
6622          // Parses relative end values with start as base (e.g.: +10, -3)
6623          if (typeof (end) === 'string') {
6624
6625            if (end.startsWith('+') || end.startsWith('-')) {
6626              end = start + parseFloat(end, 10);
6627            }
6628            else {
6629              end = parseFloat(end, 10);
6630            }
6631          }
6632
6633          // Protect against non numeric properties.
6634          if (typeof (end) === 'number') {
6635            _object[property] = start + (end - start) * value;
6636          }
6637
6638        }
6639
6640      }
6641
6642      if (_onUpdateCallback !== null) {
6643        _onUpdateCallback.call(_object, value);
6644      }
6645
6646      if (elapsed === 1) {
6647
6648        if (_repeat > 0) {
6649
6650          if (isFinite(_repeat)) {
6651            _repeat--;
6652          }
6653
6654          // Reassign starting values, restart by making startTime = now
6655          for (property in _valuesStartRepeat) {
6656
6657            if (typeof (_valuesEnd[property]) === 'string') {
6658              _valuesStartRepeat[property] = _valuesStartRepeat[property] + parseFloat(_valuesEnd[property], 10);
6659            }
6660
6661            if (_yoyo) {
6662              var tmp = _valuesStartRepeat[property];
6663
6664              _valuesStartRepeat[property] = _valuesEnd[property];
6665              _valuesEnd[property] = tmp;
6666            }
6667
6668            _valuesStart[property] = _valuesStartRepeat[property];
6669
6670          }
6671
6672          if (_yoyo) {
6673            _reversed = !_reversed;
6674          }
6675
6676          _startTime = time + _delayTime;
6677
6678          return true;
6679
6680        }
6681        else {
6682
6683          if (_onCompleteCallback !== null) {
6684            _onCompleteCallback.call(_object);
6685          }
6686
6687          for (var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++) {
6688            // Make the chained tweens start exactly at the time they should,
6689            // even if the `update()` method was called way past the duration of the tween
6690            _chainedTweens[i].start(_startTime + _duration);
6691          }
6692
6693          return false;
6694
6695        }
6696
6697      }
6698
6699      return true;
6700
6701    };
6702
6703  };
6704
6705  TWEEN.Easing = {
6706
6707    Linear: {
6708
6709      None: function (k) {
6710
6711        return k;
6712
6713      }
6714
6715    },
6716
6717    Quadratic: {
6718
6719      In: function (k) {
6720
6721        return k * k;
6722
6723      },
6724
6725      Out: function (k) {
6726
6727        return k * (2 - k);
6728
6729      },
6730
6731      InOut: function (k) {
6732
6733        if ((k *= 2) < 1) {
6734          return 0.5 * k * k;
6735        }
6736
6737        return -0.5 * (--k * (k - 2) - 1);
6738
6739      }
6740
6741    },
6742    Quartic: {
6743
6744      In: function (k) {
6745
6746        return k * k * k * k;
6747
6748      },
6749
6750      Out: function (k) {
6751
6752        return 1 - (--k * k * k * k);
6753
6754      },
6755
6756      InOut: function (k) {
6757
6758        if ((k *= 2) < 1) {
6759          return 0.5 * k * k * k * k;
6760        }
6761
6762        return -0.5 * ((k -= 2) * k * k * k - 2);
6763
6764      }
6765
6766    },
6767    Sinusoidal: {
6768
6769      In: function (k) {
6770
6771        return 1 - Math.cos(k * Math.PI / 2);
6772
6773      },
6774
6775      Out: function (k) {
6776
6777        return Math.sin(k * Math.PI / 2);
6778
6779      },
6780
6781      InOut: function (k) {
6782
6783        return 0.5 * (1 - Math.cos(Math.PI * k));
6784
6785      }
6786
6787    },
6788    Cubic: {
6789
6790      In: function (k) {
6791
6792        return k * k * k;
6793
6794      },
6795
6796      Out: function (k) {
6797
6798        return --k * k * k + 1;
6799
6800      },
6801
6802      InOut: function (k) {
6803
6804        if ((k *= 2) < 1) {
6805          return 0.5 * k * k * k;
6806        }
6807
6808        return 0.5 * ((k -= 2) * k * k + 2);
6809
6810      }
6811
6812    }
6813
6814  };
6815
6816  TWEEN.Interpolation = {
6817
6818    Linear: function (v, k) {
6819
6820      var m = v.length - 1;
6821      var f = m * k;
6822      var i = Math.floor(f);
6823      var fn = TWEEN.Interpolation.Utils.Linear;
6824
6825      if (k < 0) {
6826        return fn(v[0], v[1], f);
6827      }
6828
6829      if (k > 1) {
6830        return fn(v[m], v[m - 1], m - f);
6831      }
6832
6833      return fn(v[i], v[i + 1 > m ? m : i + 1], f - i);
6834
6835    },
6836
6837    Bezier: function (v, k) {
6838
6839      var b = 0;
6840      var n = v.length - 1;
6841      var pw = Math.pow;
6842      var bn = TWEEN.Interpolation.Utils.Bernstein;
6843
6844      for (var i = 0; i <= n; i++) {
6845        b += pw(1 - k, n - i) * pw(k, i) * v[i] * bn(n, i);
6846      }
6847
6848      return b;
6849
6850    },
6851
6852    Utils: {
6853
6854      Linear: function (p0, p1, t) {
6855
6856        return (p1 - p0) * t + p0;
6857
6858      },
6859
6860      Bernstein: function (n, i) {
6861
6862        var fc = TWEEN.Interpolation.Utils.Factorial;
6863
6864        return fc(n) / fc(i) / fc(n - i);
6865
6866      },
6867
6868      Factorial: (function () {
6869
6870        var a = [1];
6871
6872        return function (n) {
6873
6874          var s = 1;
6875
6876          if (a[n]) {
6877            return a[n];
6878          }
6879
6880          for (var i = n; i > 1; i--) {
6881            s *= i;
6882          }
6883
6884          a[n] = s;
6885          return s;
6886
6887        };
6888
6889      })(),
6890
6891      CatmullRom: function (p0, p1, p2, p3, t) {
6892
6893        var v0 = (p2 - p0) * 0.5;
6894        var v1 = (p3 - p1) * 0.5;
6895        var t2 = t * t;
6896        var t3 = t * t2;
6897
6898        return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
6899
6900      }
6901
6902    }
6903  };
6904
6905  window.TWEEN = TWEEN;
6906})();
6907
6908DFLIP.createBlob = function createBlob(data, contentType) {
6909  if (typeof Blob !== 'undefined') {
6910    return new Blob([data], {type: contentType});
6911  }
6912  // Blob builder is deprecated in FF14 and removed in FF18.
6913  var bb = new MozBlobBuilder();
6914  bb.append(data);
6915  return bb.getBlob(contentType);
6916};
6917
6918DFLIP.createObjectURL = (function createObjectURLClosure() {
6919  // Blob/createObjectURL is not available, falling back to data schema.
6920  var digits =
6921    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
6922
6923  return function createObjectURL(data, contentType) {
6924    if (typeof URL !== 'undefined' && URL.createObjectURL) {
6925      var blob = DFLIP.createBlob(data, contentType);
6926      return URL.createObjectURL(blob);
6927    }
6928
6929    var buffer = 'data:' + contentType + ';base64,';
6930    for (var i = 0, ii = data.length; i < ii; i += 3) {
6931      var b1 = data[i] & 0xFF;
6932      var b2 = data[i + 1] & 0xFF;
6933      var b3 = data[i + 2] & 0xFF;
6934      var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);
6935      var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
6936      var d4 = i + 2 < ii ? (b3 & 0x3F) : 64;
6937      buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
6938    }
6939    return buffer;
6940  };
6941})();
6942
6943var ThumbList = (function ThumbListClosure() {
6944  function ThumbList(config) {
6945    var width = (config && config.w + 'px') || '100%';
6946    var height = (config && config.h + 'px') || '100%';
6947    var itemHeight = this.itemHeight = config.itemHeight;
6948
6949    this.items = config.items;
6950    this.generatorFn = config.generatorFn;
6951    this.totalRows = config.totalRows || (config.items && config.items.length);
6952
6953    this.addFn = config.addFn;
6954    this.scrollFn = config.scrollFn;
6955
6956    var scroller = ThumbList.createScroller(itemHeight * this.totalRows);
6957    this.container = ThumbList.createContainer(width, height);
6958    this.container.appendChild(scroller);
6959
6960    this.screenItemsLen = Math.ceil(config.h / itemHeight);
6961    this.offsetItems = this.screenItemsLen;
6962    // Cache 4 times the number of items that fit in the container viewport
6963    this.cachedItemsLen = this.screenItemsLen + this.offsetItems * 2;
6964    this._renderChunk(this.container, 0);
6965
6966    var self = this;
6967    self.lastRepaintY = 0;
6968    var maxBuffer = this.screenItemsLen * itemHeight;
6969    var lastScrolled = 0;
6970
6971    var requestInterval;
6972
6973    function onScroll(e) {
6974      var scrollTop = e.target.scrollTop; // Triggers reflow
6975      if (!self.lastRepaintY || Math.abs(scrollTop - self.lastRepaintY) >= (self.offsetItems * self.itemHeight)) {
6976        var first = parseInt(scrollTop / itemHeight, 10) - self.offsetItems;
6977        self._renderChunk(self.container, first < 0 ? 0 : first);
6978        self.lastRepaintY = scrollTop;
6979      }
6980
6981      self.lastScrolled = lastScrolled = Date.now();
6982
6983      if (self.scrollFn != null) {
6984        self.scrollFn();
6985      }
6986
6987      e.preventDefault && e.preventDefault();
6988    }
6989
6990    self.dispose = function () {
6991      if (self.container) {
6992        if (self.container.parentNode) {
6993          self.container.parentNode.removeChild(self.container);
6994        }
6995      }
6996
6997      self.container.removeEventListener('scroll', onScroll);
6998    };
6999
7000    self.container.addEventListener('scroll', onScroll);
7001  }
7002
7003  ThumbList.prototype.reset = function (height) {
7004
7005    //container.find(".df-vrow").remove();
7006    this.screenItemsLen = Math.ceil(height / this.itemHeight);
7007    this.cachedItemsLen = this.screenItemsLen + this.offsetItems * 2;
7008    var first = parseInt(this.lastRepaintY / this.itemHeight, 10) - this.offsetItems;
7009    //this.lastRepaintY = 0;
7010    this.needReset = true;
7011    this._renderChunk(this.container, Math.max(first, 0));
7012  };
7013
7014  ThumbList.prototype.createRow = function (i) {
7015    var item;
7016    if (this.generatorFn) {
7017      item = this.generatorFn(i);
7018      item.classList.add('df-vrow');
7019      item.style.position = 'absolute';
7020      item.style.top = (i * this.itemHeight) + 'px';
7021      item.setAttribute("index", i);
7022    }
7023    return item;
7024  };
7025
7026  /**
7027   * Renders a particular, consecutive chunk of the total rows in the list. To
7028   * keep acceleration while scrolling, we mark the nodes that are candidate for
7029   * deletion instead of deleting them right away, which would suddenly stop the
7030   * acceleration. We delete them once scrolling has finished.
7031   *
7032   * @param {Node} node Parent node where we want to append the children chunk.
7033   * @param {Number} from Starting position, i.e. first children index.
7034   * @return {void}
7035   */
7036  ThumbList.prototype._renderChunk = function (node, from) {
7037    var isEmpty = this.range == null;
7038    this.range = this.range || {min: 0, max: this.cachedItemsLen};
7039    var range = this.range;
7040
7041    var min = range.min, max = range.max;
7042
7043    var isAdd = isEmpty ? true : from >= min;
7044
7045    if (!isEmpty && from == min && this.needReset == false) return;
7046
7047    var countVar;
7048
7049    var start = isEmpty ? min : isAdd ? max : from;// - this.cachedItemsLen/3;
7050
7051    start = start > this.totalRows ? this.totalRows
7052                                   : start < 0 ? 0 : start;
7053
7054    var end = from + this.cachedItemsLen;//this.cachedItemsLen/3);
7055
7056    end = end > this.totalRows ? this.totalRows : end;
7057
7058    for (countVar = start; countVar < end; countVar++) {
7059      if (isAdd)
7060        node.appendChild(this.createRow(countVar));
7061      else
7062        node.insertBefore(this.createRow(countVar), node.childNodes[1 + countVar - start]);
7063      if (this.addFn != null) {
7064        this.addFn(countVar);
7065      }
7066    }
7067    var difference = Math.abs(from - min);
7068    this.needReset = false;
7069    if (!isEmpty && node.childNodes.length > (this.cachedItemsLen + 1)) {
7070      // Hide and mark obsolete nodes for deletion.
7071      var delStart = isAdd ? 1 : 1 + this.cachedItemsLen,
7072        delEnd = delStart + (end - start);
7073
7074      for (var j = delEnd; j > delStart; j--) {
7075        if (node.childNodes[delStart])
7076          this.container.removeChild(node.childNodes[delStart]);
7077      }
7078    }
7079    this.range.min = from;
7080    this.range.max = end;
7081  };
7082
7083  ThumbList.createContainer = function (w, h) {
7084    var c = document.createElement('div');
7085    c.style.width = w;
7086    c.style.height = h;
7087    c.style.overflow = 'auto';
7088    c.style.position = 'relative';
7089    c.style.padding = 0;
7090    //c.style.border = '1px solid black';
7091    return c;
7092  };
7093
7094  ThumbList.createScroller = function (h) {
7095    var scroller = document.createElement('div');
7096    scroller.style.opacity = 0;
7097    scroller.style.position = 'absolute';
7098    scroller.style.top = 0;
7099    scroller.style.left = 0;
7100    scroller.style.width = '1px';
7101    scroller.style.height = h + 'px';
7102    return scroller;
7103  };
7104  return ThumbList;
7105})();
7106
7107
7108/**
7109 * @typedef {Object} BookMarkViewerOptions
7110 * @property {HTMLDivElement} container - The viewer element.
7111 * @property {IPDFLinkService} linkService - The navigation/linking service.
7112 */
7113
7114/**
7115 * @typedef {Object} BookMarkViewerRenderParameters
7116 * @property {Array|null} outline - An array of outline objects.
7117 */
7118
7119/**
7120 * @class
7121 */
7122var BookMarkViewer = (function BookMarkViewerClosure() {
7123  /**
7124   * @constructs BookMarkViewer
7125   * @param {BookMarkViewerOptions} options
7126   */
7127  function BookMarkViewer(options) {
7128    this.outline = null;
7129    this.lastToggleIsShow = true;
7130    this.container = options.container;
7131    this.linkService = options.linkService;
7132    this.outlineItemClass = options.outlineItemClass || "outlineItem";
7133    this.outlineToggleClass = options.outlineToggleClass || "outlineItemToggler";
7134    this.outlineToggleHiddenClass = options.outlineToggleHiddenClass || "outlineItemsHidden";
7135  }
7136
7137  BookMarkViewer.prototype = {
7138
7139    dispose: function () {
7140      if (this.container) {
7141        if (this.container.parentNode) {
7142          this.container.parentNode.removeChild(this.container);
7143        }
7144      }
7145      this.linkService = null;
7146
7147    },
7148    reset: function BookMarkViewer_reset() {
7149      this.outline = null;
7150      this.lastToggleIsShow = true;
7151
7152      var container = this.container;
7153      while (container.firstChild) {
7154        container.removeChild(container.firstChild);
7155      }
7156    },
7157
7158    /**
7159     * @private
7160     */
7161    _dispatchEvent: function BookMarkViewer_dispatchEvent(outlineCount) {
7162      var event = document.createEvent('CustomEvent');
7163      event.initCustomEvent('outlineloaded', true, true, {
7164        outlineCount: outlineCount
7165      });
7166      this.container.dispatchEvent(event);
7167    },
7168
7169    /**
7170     * @private
7171     */
7172    _bindLink: function BookMarkViewer_bindLink(element, item) {
7173      var linkService = this.linkService;
7174      if (item.custom == true) {
7175        element.href = linkService.getCustomDestinationHash(item.dest);
7176        element.onclick = function goToDestination(e) {
7177          linkService.customNavigateTo(item.dest);
7178          return false;
7179        };
7180      }
7181      else {
7182        if (item.url) {
7183          PDFJS.addLinkAttributes(element, {url: item.url});
7184          return;
7185        }
7186
7187        element.href = linkService.getDestinationHash(item.dest);
7188        element.onclick = function goToDestination(e) {
7189          linkService.navigateTo(item.dest);
7190          return false;
7191        };
7192      }
7193    },
7194
7195    /**
7196     * Prepend a button before an outline item which allows the user to toggle
7197     * the visibility of all outline items at that level.
7198     *
7199     * @private
7200     */
7201    _addToggleButton: function BookMarkViewer_addToggleButton(div) {
7202      var toggler = document.createElement('div');
7203      toggler.className = this.outlineToggleClass + " " + this.outlineToggleHiddenClass;
7204      toggler.onclick = function (event) {
7205        event.stopPropagation();
7206        toggler.classList.toggle(this.outlineToggleHiddenClass);
7207
7208        if (event.shiftKey) {
7209          var shouldShowAll = !toggler.classList.contains(this.outlineToggleHiddenClass);
7210          this._toggleOutlineItem(div, shouldShowAll);
7211        }
7212      }.bind(this);
7213      div.insertBefore(toggler, div.firstChild);
7214    },
7215
7216    /**
7217     * Toggle the visibility of the subtree of an outline item.
7218     *
7219     * @param {Element} root - the root of the outline (sub)tree.
7220     * @param {boolean} show - whether to show the outline (sub)tree. If false,
7221     *   the outline subtree rooted at |root| will be collapsed.
7222     *
7223     * @private
7224     */
7225    _toggleOutlineItem: function BookMarkViewer_toggleOutlineItem(root, show) {
7226      this.lastToggleIsShow = show;
7227      var togglers = root.querySelectorAll('.' + this.outlineToggleClass);
7228      for (var i = 0, ii = togglers.length; i < ii; ++i) {
7229        togglers[i].classList[show ? 'remove' : 'add'](this.outlineToggleHiddenClass);
7230      }
7231    },
7232
7233    /**
7234     * Collapse or expand all subtrees of the outline.
7235     */
7236    toggleOutlineTree: function BookMarkViewer_toggleOutlineTree() {
7237      if (!this.outline) {
7238        return;
7239      }
7240      this._toggleOutlineItem(this.container, !this.lastToggleIsShow);
7241    },
7242
7243    /**
7244     * @param {BookMarkViewerRenderParameters} params
7245     */
7246    render: function BookMarkViewer_render(params) {
7247      var outline = (params && params.outline) || null;
7248      var outlineCount = 0;
7249
7250      if (this.outline) {
7251        this.reset();
7252      }
7253      this.outline = outline;
7254
7255      if (!outline) {
7256        //this._dispatchEvent(outlineCount);
7257        return;
7258      }
7259
7260      var fragment = document.createDocumentFragment();
7261      var queue = [{parent: fragment, items: this.outline}];
7262      var hasAnyNesting = false;
7263      while (queue.length > 0) {
7264        var levelData = queue.shift();
7265        var isCustom = levelData.custom;
7266        for (var i = 0, len = levelData.items.length; i < len; i++) {
7267          var item = levelData.items[i];
7268
7269          var div = document.createElement('div');
7270          div.className = this.outlineItemClass;
7271
7272          var element = document.createElement('a');
7273          if (item.custom == null && isCustom != null)
7274            item.custom = isCustom;
7275
7276          this._bindLink(element, item);
7277          //element.
7278          element.textContent = item.title.replace(/\x00/g, '');
7279          //PDFJS.removeNullCharacters(item.title) || "Untitled Bookmark";
7280
7281          div.appendChild(element);
7282
7283          if (item.items && item.items.length > 0) {
7284            hasAnyNesting = true;
7285            this._addToggleButton(div);
7286
7287            var itemsDiv = document.createElement('div');
7288            itemsDiv.className = this.outlineItemClass + "s";
7289            div.appendChild(itemsDiv);
7290            queue.push({parent: itemsDiv, custom: item.custom, items: item.items});
7291          }
7292
7293          levelData.parent.appendChild(div);
7294          outlineCount++;
7295        }
7296      }
7297      if (hasAnyNesting) {
7298        if (this.container.classList != null) {
7299          this.container.classList.add(this.outlineItemClass + "s");
7300        }
7301        else if (this.container.className != null) {
7302          this.container.className += " picWindow";
7303        }
7304      }
7305
7306      this.container.appendChild(fragment);
7307
7308      this._dispatchEvent(outlineCount);
7309    }
7310
7311  };
7312
7313  return BookMarkViewer;
7314})();
7315//PDFJS.PDFOutlineViewer = PDFOutlineViewer;
7316
7317var DFLightBox = (function DFLightBoxClosure($) {
7318  /**
7319   * @constructs DFLightBox
7320   * @param closeCallback callBack function required to dispose object properly when lighbox is closed
7321   */
7322  function DFLightBox(closeCallback, options) {
7323
7324    this.duration = 300;
7325
7326    //cache this
7327    var _this = this;
7328    //lightbox wrapper div
7329    _this.lightboxWrapper = $("<div>").addClass("df-lightbox-wrapper");
7330
7331    //lightbox container
7332    _this.container = $("<div>").addClass("df-container").appendTo(_this.lightboxWrapper);
7333    //lightbox controls
7334    _this.controls = $("<div>").addClass("df-lightbox-controls").appendTo(_this.lightboxWrapper);
7335
7336    //lightbox close button
7337    _this.closeButton = $("<div>").addClass("df-lightbox-close df-ui-btn")
7338      .on("click", function () {
7339        _this.close(closeCallback);
7340      })
7341      .appendTo(_this.controls);
7342
7343    _this.lightboxWrapper.append(_this.container);
7344
7345    return _this;
7346  }
7347
7348  DFLightBox.prototype.show = function (callback) {
7349
7350    if (this.lightboxWrapper.parent().length == 0)
7351      $("body").append(this.lightboxWrapper);
7352
7353    this.lightboxWrapper.fadeIn(this.duration, callback);
7354
7355    return this;
7356  };
7357
7358  DFLightBox.prototype.close = function (callback) {
7359
7360    this.lightboxWrapper.fadeOut(this.duration);
7361    setTimeout(callback, this.duration);
7362
7363    return this;
7364  };
7365
7366  return DFLightBox;
7367})(jQuery);
7368
7369DFLIP.Share = (function ShareClosure($) {
7370
7371  function Share(container, options) {
7372    var _this = this;
7373    var htmlDiv = '<div>';
7374    var shareButtonClass = "df-share-button";
7375    var windowParameters = "width=500,height=400";
7376    _this.isOpen = false;
7377    _this.shareUrl = "";
7378    _this.wrapper = $('<div class="df-share-wrapper" style="display: none;">')
7379      .on("click", function (e) {
7380        _this.close();
7381      });
7382    _this.box = $('<div class="df-share-box">')
7383      .on("click", function (e) {
7384        e.preventDefault();
7385        e.stopPropagation();
7386      }).appendTo(_this.wrapper).html('<span class="df-share-title">' + options.text.share + '</span>');
7387    _this.urlInput = $('<textarea class="df-share-url">').on("click", function () {
7388      $(this).select();
7389    });
7390
7391    _this.facebook = $(htmlDiv, {
7392      class: shareButtonClass + " df-share-facebook " + options.icons['facebook']
7393    }).on("click", function (e) {
7394      window.open('https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(_this.shareUrl), "Sharer", windowParameters);
7395    });
7396    _this.google = $(htmlDiv, {
7397      class: shareButtonClass + " df-share-google " + options.icons['google']
7398    }).on("click", function (e) {
7399      window.open('https://plus.google.com/share?url=' + encodeURIComponent(_this.shareUrl), "Sharer", windowParameters);
7400    });
7401    _this.twitter = $(htmlDiv, {
7402      class: shareButtonClass + " df-share-twitter " + options.icons['twitter']
7403    }).on("click", function (e) {
7404      window.open('http://twitter.com/share?url=' + encodeURIComponent(_this.shareUrl), "Sharer", windowParameters);
7405    });
7406    _this.mail = $('<a>', {
7407      class: shareButtonClass + " df-share-mail " + options.icons['mail'],
7408      href: 'mailto:?subject=I wanted you to see this FlipBook&body=Check out this site ' + encodeURIComponent(_this.shareUrl),
7409      target: '_blank'
7410    }).on("click", function (e) {
7411      $(this).attr('href', 'mailto:?subject=I wanted you to see this FlipBook&body=Check out this site ' + encodeURIComponent(_this.shareUrl));
7412      e.stopPropagation();//so the default event is not cancelled by parent element
7413    });
7414
7415    _this.box.append(_this.urlInput).append(_this.facebook).append(_this.google).append(_this.twitter).append(_this.mail);
7416    $(container).append(_this.wrapper);
7417
7418  }
7419
7420  Share.prototype.show = function () {
7421    this.wrapper.fadeIn(300);
7422    this.urlInput.val(this.shareUrl);
7423    this.urlInput.trigger("click");
7424    this.isOpen = true;
7425  }
7426
7427  Share.prototype.dispose = function () {
7428    var _this = this;
7429    _this.box.off();
7430    _this.google.off();
7431    _this.twitter.off();
7432    _this.facebook.off();
7433    _this.mail.off();
7434    _this.urlInput.off();
7435    _this.wrapper.off().remove();
7436  }
7437
7438  Share.prototype.close = function () {
7439    this.wrapper.fadeOut(300);
7440    this.isOpen = false;
7441  }
7442
7443  Share.prototype.update = function (url) {
7444    this.shareUrl = url;
7445  }
7446
7447  return Share;
7448})(jQuery);
7449DFLIP.Popup = (function PopupClosure($) {
7450
7451  function Popup(container, options) {
7452    var _this = this;
7453    var htmlDiv = '<div>';
7454    var windowParameters = "width=500,height=400";
7455    _this.isOpen = false;
7456    _this.wrapper = $('<div class="df-popup-wrapper" style="display: none;">')
7457      .on("click", function (e) {
7458        _this.close();
7459      });
7460    _this.box = $('<div class="df-popup-box">')
7461      .on("click", function (e) {
7462        e.preventDefault();
7463        e.stopPropagation();
7464      }).appendTo(_this.wrapper);
7465
7466    $(container).append(_this.wrapper);
7467
7468  }
7469
7470  Popup.prototype.show = function () {
7471    this.wrapper.fadeIn(300);
7472    this.isOpen = true;
7473  }
7474
7475  Popup.prototype.dispose = function () {
7476    var _this = this;
7477    _this.box.off();
7478    _this.wrapper.off().remove();
7479  }
7480
7481  Popup.prototype.close = function () {
7482    this.wrapper.fadeOut(300);
7483    this.isOpen = false;
7484  }
7485
7486  return Popup;
7487})(jQuery);
7488
7489/**
7490 * Performs navigation functions inside PDF, such as opening specified page,
7491 * or destination.
7492 * @class
7493 * @implements {IPDFLinkService}
7494 */
7495var PDFLinkService = (function () {
7496  /**
7497   * @constructs PDFLinkService
7498   */
7499  function PDFLinkService() {
7500    this.baseUrl = null;
7501    this.pdfDocument = null;
7502    this.pdfViewer = null;
7503    this.pdfHistory = null;
7504
7505    this._pagesRefCache = null;
7506  }
7507
7508  PDFLinkService.prototype = {
7509    dispose: function () {
7510      this.baseUrl = null;
7511      this.pdfDocument = null;
7512      this.pdfViewer = null;
7513      this.pdfHistory = null;
7514
7515      this._pagesRefCache = null;
7516    },
7517    setDocument: function PDFLinkService_setDocument(pdfDocument, baseUrl) {
7518      this.baseUrl = baseUrl;
7519      this.pdfDocument = pdfDocument;
7520      this._pagesRefCache = Object.create(null);
7521    },
7522
7523    setViewer: function PDFLinkService_setViewer(pdfViewer) {
7524      this.pdfViewer = pdfViewer;
7525    },
7526
7527    setHistory: function PDFLinkService_setHistory(pdfHistory) {
7528      this.pdfHistory = pdfHistory;
7529    },
7530
7531    /**
7532     * @returns {number}
7533     */
7534    get pagesCount() {
7535      return this.pdfDocument.numPages;
7536    },
7537
7538    /**
7539     * @returns {number}
7540     */
7541    get page() {
7542      return this.pdfViewer.currentPageNumber;
7543    },
7544
7545    /**
7546     * @param {number} value
7547     */
7548    set page(value) {
7549      this.pdfViewer.currentPageNumber = value;
7550    },
7551
7552    /**
7553     * @param dest - The PDF destination object.
7554     */
7555    navigateTo: function PDFLinkService_navigateTo(dest) {
7556      var destString = '';
7557      var self = this;
7558
7559      var goToDestination = function (destRef) {
7560        // dest array looks like that: <page-ref> </XYZ|FitXXX> <args..>
7561        var pageNumber = destRef instanceof Object ? self._pagesRefCache[destRef.num + ' ' + destRef.gen + ' R']
7562                                                   : (destRef + 1);
7563        if (pageNumber) {
7564          //case double internal
7565          if (self.pdfViewer.contentProvider.options.pageSize == DFLIP.PAGE_SIZE.DOUBLEINTERNAL && pageNumber > 2) {
7566            pageNumber = pageNumber * 2 - 1;
7567          }
7568
7569          if (pageNumber >
7569 self.pdfViewer.pageCount) {
7570            pageNumber = self.pdfViewer.pageCount;
7571          }
7572          self.pdfViewer.gotoPage(pageNumber);
7573          // self.pdfViewer.scrollPageIntoView(pageNumber, dest);
7574
7575          if (self.pdfHistory) {
7576            // Update the browsing history.
7577            self.pdfHistory.push({
7578              dest: dest,
7579              hash: destString,
7580              page: pageNumber
7581            });
7582          }
7583        }
7584        else {
7585          self.pdfDocument.getPageIndex(destRef).then(function (pageIndex) {
7586            var pageNum = pageIndex + 1;
7587            var cacheKey = destRef.num + ' ' + destRef.gen + ' R';
7588            self._pagesRefCache[cacheKey] = pageNum;
7589            goToDestination(destRef);
7590          });
7591        }
7592      };
7593
7594      var destinationPromise;
7595      if (typeof dest === 'string') {
7596        destString = dest;
7597        destinationPromise = this.pdfDocument.getDestination(dest);
7598      }
7599      else {
7600        destinationPromise = Promise.resolve(dest);
7601      }
7602      destinationPromise.then(function (destination) {
7603        dest = destination;
7604        if (!(destination instanceof Array)) {
7605          return; // invalid destination
7606        }
7607        goToDestination(destination[0]);
7608      });
7609    },
7610
7611
7612    /**
7613     * @param dest - The PDF destination object.
7614     */
7615    customNavigateTo: function PDFLinkService_navigateTo(dest) {
7616      if (dest == '' || dest == null || dest == 'null') return;
7617      var pageNumber = null;
7618      if (!isNaN(Math.round(dest))) {
7619        pageNumber = dest;
7620      }
7621      else if (typeof dest === 'string') {
7622        pageNumber = parseInt(dest.replace("#", ""), 10);
7623        if (isNaN(pageNumber)) {
7624          window.open(dest, (DFLIP.defaults.linkTarget == DFLIP.LINK_TARGET.SELF ? "_self" : "_blank"));
7625          return;
7626        }
7627      }
7628
7629      if (pageNumber != null)
7630        this.pdfViewer.gotoPage(pageNumber);
7631
7632    },
7633
7634    /**
7635     * @param dest - The PDF destination object.
7636     * @returns {string} The hyperlink to the PDF object.
7637     */
7638    getDestinationHash: function PDFLinkService_getDestinationHash(dest) {
7639      if (typeof dest === 'string') {
7640        return this.getAnchorUrl('#' + escape(dest));
7641      }
7642      if (dest instanceof Array) {
7643        var destRef = dest[0]; // see navigateTo method for dest format
7644        var pageNumber = destRef instanceof Object ? this._pagesRefCache[destRef.num + ' ' + destRef.gen + ' R']
7645                                                   : (destRef + 1);
7646        if (pageNumber) {
7647          var pdfOpenParams = this.getAnchorUrl('#page=' + pageNumber);
7648          var destKind = dest[1];
7649          if (typeof destKind === 'object' && 'name' in destKind &&
7650            destKind.name === 'XYZ') {
7651            var scale = (dest[4] || this.pdfViewer.currentScaleValue);
7652            var scaleNumber = parseFloat(scale);
7653            if (scaleNumber) {
7654              scale = scaleNumber * 100;
7655            }
7656            pdfOpenParams += '&zoom=' + scale;
7657            if (dest[2] || dest[3]) {
7658              pdfOpenParams += ',' + (dest[2] || 0) + ',' + (dest[3] || 0);
7659            }
7660          }
7661          return pdfOpenParams;
7662        }
7663      }
7664      return this.getAnchorUrl('');
7665    },
7666
7667    /**
7668     * @param dest - The PDF destination object.
7669     * @returns {string} The hyperlink to the PDF object.
7670     */
7671    getCustomDestinationHash: function PDFLinkService_getCustomDestinationHash(dest) {
7672      //if (typeof dest === 'string') {
7673      return '#' + escape(dest);
7674      //}
7675      //return this.getAnchorUrl('');
7676    },
7677
7678
7679    /**
7680     * Prefix the full url on anchor links to make sure that links are resolved
7681     * relative to the current URL instead of the one defined in <base href>.
7682     * @param {String} anchor The anchor hash, including the #.
7683     * @returns {string} The hyperlink to the PDF object.
7684     */
7685    getAnchorUrl: function PDFLinkService_getAnchorUrl(anchor) {
7686      return (this.baseUrl || '') + anchor;
7687    },
7688
7689    /**
7690     * @param {string} hash
7691     */
7692    setHash: function PDFLinkService_setHash(hash) {
7693      if (hash.indexOf('=') >= 0) {
7694        var params = parseQueryString(hash);
7695        // borrowing syntax from "Parameters for Opening PDF Files"
7696        if ('nameddest' in params) {
7697          if (this.pdfHistory) {
7698            this.pdfHistory.updateNextHashParam(params.nameddest);
7699          }
7700          this.navigateTo(params.nameddest);
7701          return;
7702        }
7703        var pageNumber, dest;
7704        if ('page' in params) {
7705          pageNumber = (params.page | 0) || 1;
7706        }
7707        if ('zoom' in params) {
7708          // Build the destination array.
7709          var zoomArgs = params.zoom.split(','); // scale,left,top
7710          var zoomArg = zoomArgs[0];
7711          var zoomArgNumber = parseFloat(zoomArg);
7712
7713          if (zoomArg.indexOf('Fit') === -1) {
7714            // If the zoomArg is a number, it has to get divided by 100. If it's
7715            // a string, it should stay as it is.
7716            dest = [null, {name: 'XYZ'},
7717              zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null,
7718              zoomArgs.length > 2 ? (zoomArgs[2] | 0) : null,
7719              (zoomArgNumber ? zoomArgNumber / 100 : zoomArg)];
7720          }
7721          else {
7722            if (zoomArg === 'Fit' || zoomArg === 'FitB') {
7723              dest = [null, {name: zoomArg}];
7724            }
7725            else if ((zoomArg === 'FitH' || zoomArg === 'FitBH') ||
7726              (zoomArg === 'FitV' || zoomArg === 'FitBV')) {
7727              dest = [null, {name: zoomArg},
7728                zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null];
7729            }
7730            else if (zoomArg === 'FitR') {
7731              if (zoomArgs.length !== 5) {
7732                console.error('PDFLinkService_setHash: ' +
7733                  'Not enough parameters for \'FitR\'.');
7734              }
7735              else {
7736                dest = [null, {name: zoomArg},
7737                  (zoomArgs[1] | 0), (zoomArgs[2] | 0),
7738                  (zoomArgs[3] | 0), (zoomArgs[4] | 0)];
7739              }
7740            }
7741            else {
7742              console.error('PDFLinkService_setHash: \'' + zoomArg +
7743                '\' is not a valid zoom value.');
7744            }
7745          }
7746        }
7747        if (dest) {
7748          this.pdfViewer.scrollPageIntoView(pageNumber || this.page, dest);
7749        }
7750        else if (pageNumber) {
7751          this.page = pageNumber; // simple page
7752        }
7753        if ('pagemode' in params) {
7754          var event = document.createEvent('CustomEvent');
7755          event.initCustomEvent('pagemode', true, true, {
7756            mode: params.pagemode
7757          });
7758          this.pdfViewer.container.dispatchEvent(event);
7759        }
7760      }
7761      else if (/^\d+$/.test(hash)) { // page number
7762        this.page = hash;
7763      }
7764      else { // named destination
7765        if (this.pdfHistory) {
7766          this.pdfHistory.updateNextHashParam(unescape(hash));
7767        }
7768        this.navigateTo(unescape(hash));
7769      }
7770    },
7771
7772    /**
7773     * @param {string} action
7774     */
7775    executeNamedAction: function PDFLinkService_executeNamedAction(action) {
7776      // See PDF reference, table 8.45 - Named action
7777      switch (action) {
7778        case 'GoBack':
7779          if (this.pdfHistory) {
7780            this.pdfHistory.back();
7781          }
7782          break;
7783
7784        case 'GoForward':
7785          if (this.pdfHistory) {
7786            this.pdfHistory.forward();
7787          }
7788          break;
7789
7790        case 'NextPage':
7791          this.page++;
7792          break;
7793
7794        case 'PrevPage':
7795          this.page--;
7796          break;
7797
7798        case 'LastPage':
7799          this.page = this.pagesCount;
7800          break;
7801
7802        case 'FirstPage':
7803          this.page = 1;
7804          break;
7805
7806        default:
7807          break; // No action according to spec
7808      }
7809
7810      var event = document.createEvent('CustomEvent');
7811      event.initCustomEvent('namedaction', true, true, {
7812        action: action
7813      });
7814      this.pdfViewer.container.dispatchEvent(event);
7815    },
7816
7817    /**
7818     * @param {number} pageNum - page number.
7819     * @param {Object} pageRef - reference to the page.
7820     */
7821    cachePageRef: function PDFLinkService_cachePageRef(pageNum, pageRef) {
7822      var refStr = pageRef.num + ' ' + pageRef.gen + ' R';
7823      this._pagesRefCache[refStr] = pageNum;
7824    }
7825  };
7826
7827  return PDFLinkService;
7828})();
7829//PDFJS.PDFLinkService = PDFLinkService;
7830var FindStates = {
7831  FIND_FOUND: 0,
7832  FIND_NOTFOUND: 1,
7833  FIND_WRAPPED: 2,
7834  FIND_PENDING: 3
7835};
7836var FIND_SCROLL_OFFSET_TOP = -50;
7837var FIND_SCROLL_OFFSET_LEFT = -400;
7838var CHARACTERS_TO_NORMALIZE = {
7839  '\u2018': '\'',
7840  '\u2019': '\'',
7841  '\u201A': '\'',
7842  '\u201B': '\'',
7843  '\u201C': '"',
7844  '\u201D': '"',
7845  '\u201E': '"',
7846  '\u201F': '"',
7847  '\u00BC': '1/4',
7848  '\u00BD': '1/2',
7849  '\u00BE': '3/4'
7850};
7851DFLIP.PDFFindController = (function PDFFindControllerClosure() {
7852  function PDFFindController(options) {
7853    this.pdfViewer = options.pdfViewer || null;
7854    this.onUpdateResultsCount = null;
7855    this.onUpdateState = null;
7856    this.reset();
7857    var replace = Object.keys(CHARACTERS_TO_NORMALIZE).join('');
7858    this.normalizationRegex = new RegExp('[' + replace + ']', 'g');
7859  }
7860
7861  PDFFindController.prototype = {
7862    reset: function PDFFindController_reset() {
7863      this.startedTextExtraction = false;
7864      this.extractTextPromises = [];
7865      this.pendingFindMatches = Object.create(null);
7866      this.active = false;
7867      this.pageContents = [];
7868      this.pageMatches = [];
7869      this.pageMatchesLength = null;
7870      this.matchCount = 0;
7871      this.selected = {
7872        pageIdx: -1,
7873        matchIdx: -1
7874      };
7875      this.offset = {
7876        pageIdx: null,
7877        matchIdx: null
7878      };
7879      this.pagesToSearch = null;
7880      this.resumePageIdx = null;
7881      this.state = null;
7882      this.dirtyMatch = false;
7883      this.findTimeout = null;
7884      this.firstPagePromise = new Promise(function (resolve) {
7885        this.resolveFirstPage = resolve;
7886      }.bind(this));
7887    },
7888    normalize: function PDFFindController_normalize(text) {
7889      return text.replace(this.normalizationRegex, function (ch) {
7890        return CHARACTERS_TO_NORMALIZE[ch];
7891      });
7892    },
7893    _prepareMatches: function PDFFindController_prepareMatches(matchesWithLength, matches, matchesLength) {
7894      function isSubTerm(matchesWithLength, currentIndex) {
7895        var currentElem, prevElem, nextElem;
7896        currentElem = matchesWithLength[currentIndex];
7897        nextElem = matchesWithLength[currentIndex + 1];
7898        if (currentIndex < matchesWithLength.length - 1 && currentElem.match === nextElem.match) {
7899          currentElem.skipped = true;
7900          return true;
7901        }
7902        for (var i = currentIndex - 1; i >= 0; i--) {
7903          prevElem = matchesWithLength[i];
7904          if (prevElem.skipped) {
7905            continue;
7906          }
7907          if (prevElem.match + prevElem.matchLength < currentElem.match) {
7908            break;
7909          }
7910          if (prevElem.match + prevElem.matchLength >= currentElem.match + currentElem.matchLength) {
7911            currentElem.skipped = true;
7912            return true;
7913          }
7914        }
7915        return false;
7916      }
7917
7918      var i, len;
7919      matchesWithLength.sort(function (a, b) {
7920        return a.match === b.match ? a.matchLength - b.matchLength : a.match - b.match;
7921      });
7922      for (i = 0, len = matchesWithLength.length; i < len; i++) {
7923        if (isSubTerm(matchesWithLength, i)) {
7924          continue;
7925        }
7926        matches.push(matchesWithLength[i].match);
7927        matchesLength.push(matchesWithLength[i].matchLength);
7928      }
7929    },
7930    calcFindPhraseMatch: function PDFFindController_calcFindPhraseMatch(query, pageIndex, pageContent) {
7931      var matches = [];
7932      var queryLen = query.length;
7933      var matchIdx = -queryLen;
7934      while (true) {
7935        matchIdx = pageContent.indexOf(query, matchIdx + queryLen);
7936        if (matchIdx === -1) {
7937          break;
7938        }
7939        matches.push(matchIdx);
7940      }
7941      this.pageMatches[pageIndex] = matches;
7942    },
7943    calcFindWordMatch: function PDFFindController_calcFindWordMatch(query, pageIndex, pageContent) {
7944      var matchesWithLength = [];
7945      var queryArray = query.match(/\S+/g);
7946      var subquery, subqueryLen, matchIdx;
7947      for (var i = 0, len = queryArray.length; i < len; i++) {
7948        subquery = queryArray[i];
7949        subqueryLen = subquery.length;
7950        matchIdx = -subqueryLen;
7951        while (true) {
7952          matchIdx = pageContent.indexOf(subquery, matchIdx + subqueryLen);
7953          if (matchIdx === -1) {
7954            break;
7955          }
7956          matchesWithLength.push({
7957            match: matchIdx,
7958            matchLength: subqueryLen,
7959            skipped: false
7960          });
7961        }
7962      }
7963      if (!this.pageMatchesLength) {
7964        this.pageMatchesLength = [];
7965      }
7966      this.pageMatchesLength[pageIndex] = [];
7967      this.pageMatches[pageIndex] = [];
7968      this._prepareMatches(matchesWithLength, this.pageMatches[pageIndex], this.pageMatchesLength[pageIndex]);
7969    },
7970    calcFindMatch: function PDFFindController_calcFindMatch(pageIndex) {
7971      var pageContent = this.normalize(this.pageContents[pageIndex]);
7972      var query = this.normalize(this.state.query);
7973      var caseSensitive = this.state.caseSensitive;
7974      var phraseSearch = this.state.phraseSearch;
7975      var queryLen = query.length;
7976      if (queryLen === 0) {
7977        return;
7978      }
7979      if (!caseSensitive) {
7980        pageContent = pageContent.toLowerCase();
7981        query = query.toLowerCase();
7982      }
7983      if (phraseSearch) {
7984        this.calcFindPhraseMatch(query, pageIndex, pageContent);
7985      }
7986      else {
7987        this.calcFindWordMatch(query, pageIndex, pageContent);
7988      }
7989      this.updatePage(pageIndex);
7990      if (this.resumePageIdx === pageIndex) {
7991        this.resumePageIdx = null;
7992        this.nextPageMatch();
7993      }
7994      if (this.pageMatches[pageIndex].length > 0) {
7995        this.matchCount += this.pageMatches[pageIndex].length;
7996        this.updateUIResultsCount();
7997      }
7998    },
7999    extractText: function PDFFindController_extractText() {
8000      if (this.startedTextExtraction) {
8001        return;
8002      }
8003      this.startedTextExtraction = true;
8004      this.pageContents = [];
8005      var extractTextPromisesResolves = [];
8006      var numPages = this.pdfViewer.contentProvider.pdfDocument.numPages;
8007      for (var i = 0; i < numPages; i++) {
8008        this.extractTextPromises.push(new Promise(function (resolve) {
8009          extractTextPromisesResolves.push(resolve);
8010        }));
8011      }
8012      var self = this;
8013
8014      function extractPageText(pageIndex) {
8015        self.pdfViewer.getPageTextContent(pageIndex).then(function textContentResolved(textContent) {
8016          var textItems = textContent.items;
8017          var str = [];
8018          for (var i = 0, len = textItems.length; i < len; i++) {
8019            str.push(textItems[i].str);
8020          }
8021          self.pageContents.push(str.join(''));
8022          extractTextPromisesResolves[pageIndex](pageIndex);
8023          console.log("extracting Page" + pageIndex);
8024          if (pageIndex + 1 < self.pdfViewer.contentProvider.pdfDocument.numPages) {
8025            extractPageText(pageIndex + 1);
8026          }
8027        });
8028      }
8029
8030      extractPageText(0);
8031    },
8032    executeCommand: function PDFFindController_executeCommand(cmd, state) {
8033      if (this.state === null || cmd !== 'findagain') {
8034        this.dirtyMatch = true;
8035      }
8036      this.state = state;
8037      this.updateUIState(FindStates.FIND_PENDING);
8038      this.firstPagePromise.then(function () {
8039        this.extractText();
8040        clearTimeout(this.findTimeout);
8041        if (cmd === 'find') {
8042          this.findTimeout = setTimeout(this.nextMatch.bind(this), 250);
8043        }
8044        else {
8045          this.nextMatch();
8046        }
8047      }.bind(this));
8048    },
8049    updatePage: function PDFFindController_updatePage(index) {
8050      if (this.selected.pageIdx === index) {
8051        this.pdfViewer.currentPageNumber = index + 1;
8052      }
8053      var page = this.pdfViewer.getPageView(index);
8054      if (page.textLayer) {
8055        page.textLayer.updateMatches();
8056      }
8057    },
8058    nextMatch: function PDFFindController_nextMatch() {
8059      var previous = this.state.findPrevious;
8060      var currentPageIndex = this.pdfViewer.currentPageNumber - 1;
8061      var numPages = this.pdfViewer.contentProvider.pageCount;
8062      this.active = true;
8063      if (this.dirtyMatch) {
8064        this.dirtyMatch = false;
8065        this.selected.pageIdx = this.selected.matchIdx = -1;
8066        this.offset.pageIdx = currentPageIndex;
8067        this.offset.matchIdx = null;
8068        this.hadMatch = false;
8069        this.resumePageIdx = null;
8070        this.pageMatches = [];
8071        this.matchCount = 0;
8072        this.pageMatchesLength = null;
8073        var self = this;
8074        for (var i = 0; i < numPages; i++) {
8075          this.updatePage(i);
8076          if (!(i in this.pendingFindMatches)) {
8077            this.pendingFindMatches[i] = true;
8078            this.extractTextPromises[i].then(function (pageIdx) {
8079              delete self.pendingFindMatches[pageIdx];
8080              self.calcFindMatch(pageIdx);
8081            });
8082          }
8083        }
8084      }
8085      if (this.state.query === '') {
8086        this.updateUIState(FindStates.FIND_FOUND);
8087        return;
8088      }
8089      if (this.resumePageIdx) {
8090        return;
8091      }
8092      var offset = this.offset;
8093      this.pagesToSearch = numPages;
8094      if (offset.matchIdx !== null) {
8095        var numPageMatches = this.pageMatches[offset.pageIdx].length;
8096        if (!previous && offset.matchIdx + 1 < numPageMatches || previous && offset.matchIdx > 0) {
8097          this.hadMatch = true;
8098          offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1;
8099          this.updateMatch(true);
8100          return;
8101        }
8102        this.advanceOffsetPage(previous);
8103      }
8104      this.nextPageMatch();
8105    },
8106    matchesReady: function PDFFindController_matchesReady(matches) {
8107      var offset = this.offset;
8108      var numMatches = matches.length;
8109      var previous = this.state.findPrevious;
8110      if (numMatches) {
8111        this.hadMatch = true;
8112        offset.matchIdx = previous ? numMatches - 1 : 0;
8113        this.updateMatch(true);
8114        return true;
8115      }
8116      this.advanceOffsetPage(previous);
8117      if (offset.wrapped) {
8118        offset.matchIdx = null;
8119        if (this.pagesToSearch < 0) {
8120          this.updateMatch(false);
8121          return true;
8122        }
8123      }
8124      return false;
8125    },
8126    updateMatchPosition: function PDFFindController_updateMatchPosition(pageIndex, index, elements, beginIdx) {
8127      if (this.selected.matchIdx === index && this.selected.pageIdx === pageIndex) {
8128        var spot = {
8129          top: FIND_SCROLL_OFFSET_TOP,
8130          left: FIND_SCROLL_OFFSET_LEFT
8131        };
8132        scrollIntoView(elements[beginIdx], spot, true);
8133      }
8134    },
8135    nextPageMatch: function PDFFindController_nextPageMatch() {
8136      if (this.resumePageIdx !== null) {
8137        console.error('There can only be one pending page.');
8138      }
8139      do {
8140        var pageIdx = this.offset.pageIdx;
8141        var matches = this.pageMatches[pageIdx];
8142        if (!matches) {
8143          this.resumePageIdx = pageIdx;
8144          break;
8145        }
8146      } while (!this.matchesReady(matches));
8147    },
8148    advanceOffsetPage: function PDFFindController_advanceOffsetPage(previous) {
8149      var offset = this.offset;
8150      var numPages = this.extractTextPromises.length;
8151      offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1;
8152      offset.matchIdx = null;
8153      this.pagesToSearch--;
8154      if (offset.pageIdx >= numPages || offset.pageIdx < 0) {
8155        offset.pageIdx = previous ? numPages - 1 : 0;
8156        offset.wrapped = true;
8157      }
8158    },
8159    updateMatch: function PDFFindController_updateMatch(found) {
8160      var state = FindStates.FIND_NOTFOUND;
8161      var wrapped = this.offset.wrapped;
8162      this.offset.wrapped = false;
8163      if (found) {
8164        var previousPage = this.selected.pageIdx;
8165        this.selected.pageIdx = this.offset.pageIdx;
8166        this.selected.matchIdx = this.offset.matchIdx;
8167        state = wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND;
8168        if (previousPage !== -1 && previousPage !== this.selected.pageIdx) {
8169          this.updatePage(previousPage);
8170        }
8171      }
8172      this.updateUIState(state, this.state.findPrevious);
8173      if (this.selected.pageIdx !== -1) {
8174        this.updatePage(this.selected.pageIdx);
8175      }
8176    },
8177    updateUIResultsCount: function PDFFindController_updateUIResultsCount() {
8178      if (this.onUpdateResultsCount) {
8179        this.onUpdateResultsCount(this.matchCount);
8180      }
8181    },
8182    updateUIState: function PDFFindController_updateUIState(state, previous) {
8183      if (this.onUpdateState) {
8184        this.onUpdateState(state, previous, this.matchCount);
8185      }
8186    }
8187  };
8188  return PDFFindController;
8189})();
8190/**
8191 * @typedef {Object} TextLayerBuilderOptions
8192 * @property {HTMLDivElement} textLayerDiv - The text layer container.
8193 * @property {EventBus} eventBus - The application event bus.
8194 * @property {number} pageIndex - The page index.
8195 * @property {PageViewport} viewport - The viewport of the text layer.
8196 * @property {PDFFindController} findController
8197 * @property {boolean} enhanceTextSelection - Option to turn on improved
8198 *   text selection.
8199 */
8200
8201/**
8202 * TextLayerBuilder provides text-selection functionality for the PDF.
8203 * It does this by creating overlay divs over the PDF text. These divs
8204 * contain text that matches the PDF text they are overlaying. This object
8205 * also provides a way to highlight text that is being searched for.
8206 * @class
8207 */
8208DFLIP.TextLayerBuilder = (function TextLayerBuilderClosure() {
8209  function TextLayerBuilder(options) {
8210    this.textLayerDiv = options.textLayerDiv;
8211    this.renderingDone = false;
8212    this.divContentDone = false;
8213    this.pageIdx = options.pageIndex;
8214    this.pageNumber = this.pageIdx + 1;
8215    this.matches = [];
8216    this.viewport = options.viewport;
8217    this.textDivs = [];
8218    this.findController = options.findController || null;
8219    this.textLayerRenderTask = null;
8220    this.enhanceTextSelection = options.enhanceTextSelection;
8221    this._bindMouse();
8222  }
8223
8224  TextLayerBuilder.prototype = {
8225    _finishRendering: function TextLayerBuilder_finishRendering() {
8226      this.renderingDone = true;
8227
8228      if (!this.enhanceTextSelection) {
8229        var endOfContent = document.createElement('div');
8230        endOfContent.className = 'endOfContent';
8231        this.textLayerDiv.appendChild(endOfContent);
8232      }
8233
8234      /*			this.eventBus.dispatch('textlayerrendered', {
8235       source: this,
8236       pageNumber: this.pageNumber
8237       });*/
8238    },
8239
8240    /**
8241     * Renders the text layer.
8242     * @param {number} timeout (optional) if specified, the rendering waits
8243     *   for specified amount of ms.
8244     */
8245    render: function TextLayerBuilder_render(timeout) {
8246      if (!this.divContentDone || this.renderingDone) {
8247        return;
8248      }
8249
8250      if (this.textLayerRenderTask) {
8251        this.textLayerRenderTask.cancel();
8252        this.textLayerRenderTask = null;
8253      }
8254
8255      this.textDivs = [];
8256      var textLayerFrag = document.createDocumentFragment();
8257      this.textLayerRenderTask = PDFJS.renderTextLayer({
8258        textContent: this.textContent,
8259        container: textLayerFrag,
8260        viewport: this.viewport,
8261        textDivs: this.textDivs,
8262        timeout: timeout,
8263        enhanceTextSelection: this.enhanceTextSelection,
8264      });
8265      this.textLayerRenderTask.promise.then(function () {
8266        this.textLayerDiv.appendChild(textLayerFrag);
8267        this._finishRendering();
8268        this.updateMatches();
8269      }.bind(this), function (reason) {
8270        // canceled or failed to render text layer -- skipping errors
8271      });
8272    },
8273
8274    setTextContent: function TextLayerBuilder_setTextContent(textContent) {
8275      if (this.textLayerRenderTask) {
8276        this.textLayerRenderTask.cancel();
8277        this.textLayerRenderTask = null;
8278      }
8279      this.textContent = textContent;
8280      this.divContentDone = true;
8281    },
8282
8283    convertMatches: function TextLayerBuilder_convertMatches(matches,
8284                                                             matchesLength) {
8285      var i = 0;
8286      var iIndex = 0;
8287      var bidiTexts = this.textContent.items;
8288      var end = bidiTexts.length - 1;
8289      var queryLen = (this.findController === null ? 0 : this.findController.state.query.length);
8290      var ret = [];
8291      if (!matches) {
8292        return ret;
8293      }
8294      for (var m = 0, len = matches.length; m < len; m++) {
8295        // Calculate the start position.
8296        var matchIdx = matches[m];
8297
8298        // Loop over the divIdxs.
8299        while (i !== end && matchIdx >= (iIndex + bidiTexts[i].str.length)) {
8300          iIndex += bidiTexts[i].str.length;
8301          i++;
8302        }
8303
8304        if (i === bidiTexts.length) {
8305          console.error('Could not find a matching mapping');
8306        }
8307
8308        var match = {
8309          begin: {
8310            divIdx: i,
8311            offset: matchIdx - iIndex
8312          }
8313        };
8314
8315        // Calculate the end position.
8316        if (matchesLength) { // multiterm search
8317          matchIdx += matchesLength[m];
8318        }
8319        else { // phrase search
8320          matchIdx += queryLen;
8321        }
8322
8323        // Somewhat the same array as above, but use > instead of >= to get
8324        // the end position right.
8325        while (i !== end && matchIdx > (iIndex + bidiTexts[i].str.length)) {
8326          iIndex += bidiTexts[i].str.length;
8327          i++;
8328        }
8329
8330        match.end = {
8331          divIdx: i,
8332          offset: matchIdx - iIndex
8333        };
8334        ret.push(match);
8335      }
8336
8337      return ret;
8338    },
8339
8340    renderMatches: function TextLayerBuilder_renderMatches(matches) {
8341      // Early exit if there is nothing to render.
8342      if (matches.length === 0) {
8343        return;
8344      }
8345
8346      var bidiTexts = this.textContent.items;
8347      var textDivs = this.textDivs;
8348      var prevEnd = null;
8349      var pageIdx = this.pageIdx;
8350      var isSelectedPage = (this.findController === null ? false : (pageIdx === this.findController.selected.pageIdx));
8351      var selectedMatchIdx = (this.findController === null ? -1 : this.findController.selected.matchIdx);
8352      var highlightAll = (this.findController === null ? false : this.findController.state.highlightAll);
8353      var infinity = {
8354        divIdx: -1,
8355        offset: undefined
8356      };
8357
8358      function beginText(begin, className) {
8359        var divIdx = begin.divIdx;
8360        textDivs[divIdx].textContent = '';
8361        appendTextToDiv(divIdx, 0, begin.offset, className);
8362      }
8363
8364      function appendTextToDiv(divIdx, fromOffset, toOffset, className) {
8365        var div = textDivs[divIdx];
8366        var content = bidiTexts[divIdx].str.substring(fromOffset, toOffset);
8367        var node = document.createTextNode(content);
8368        if (className) {
8369          var span = document.createElement('span');
8370          span.className = className;
8371          span.appendChild(node);
8372          div.appendChild(span);
8373          return;
8374        }
8375        div.appendChild(node);
8376      }
8377
8378      var i0 = selectedMatchIdx, i1 = i0 + 1;
8379      if (highlightAll) {
8380        i0 = 0;
8381        i1 = matches.length;
8382      }
8383      else if (!isSelectedPage) {
8384        // Not highlighting all and this isn't the selected page, so do nothing.
8385        return;
8386      }
8387
8388      for (var i = i0; i < i1; i++) {
8389        var match = matches[i];
8390        var begin = match.begin;
8391        var end = match.end;
8392        var isSelected = (isSelectedPage && i === selectedMatchIdx);
8393        var highlightSuffix = (isSelected ? ' selected' : '');
8394
8395        if (this.findController) {
8396          this.findController.updateMatchPosition(pageIdx, i, textDivs,
8397            begin.divIdx);
8398        }
8399
8400        // Match inside new div.
8401        if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
8402          // If there was a previous div, then add the text at the end.
8403          if (prevEnd !== null) {
8404            appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
8405          }
8406          // Clear the divs and set the content until the starting point.
8407          beginText(begin);
8408        }
8409        else {
8410          appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset);
8411        }
8412
8413        if (begin.divIdx === end.divIdx) {
8414          appendTextToDiv(begin.divIdx, begin.offset, end.offset,
8415            'highlight' + highlightSuffix);
8416        }
8417        else {
8418          appendTextToDiv(begin.divIdx, begin.offset, infinity.offset,
8419            'highlight begin' + highlightSuffix);
8420          for (var n0 = begin.divIdx + 1, n1 = end.divIdx; n0 < n1; n0++) {
8421            textDivs[n0].className = 'highlight middle' + highlightSuffix;
8422          }
8423          beginText(end, 'highlight end' + highlightSuffix);
8424        }
8425        prevEnd = end;
8426      }
8427
8428      if (prevEnd) {
8429        appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
8430      }
8431    },
8432
8433    updateMatches: function TextLayerBuilder_updateMatches() {
8434      // Only show matches when all rendering is done.
8435      if (!this.renderingDone) {
8436        return;
8437      }
8438
8439      // Clear all matches.
8440      var matches = this.matches;
8441      var textDivs = this.textDivs;
8442      var bidiTexts = this.textContent.items;
8443      var clearedUntilDivIdx = -1;
8444
8445      // Clear all current matches.
8446      for (var i = 0, len = matches.length; i < len; i++) {
8447        var match = matches[i];
8448        var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
8449        for (var n = begin, end = match.end.divIdx; n <= end; n++) {
8450          var div = textDivs[n];
8451          div.textContent = bidiTexts[n].str;
8452          div.className = '';
8453        }
8454        clearedUntilDivIdx = match.end.divIdx + 1;
8455      }
8456
8457      if (this.findController === null || !this.findController.active) {
8458        return;
8459      }
8460
8461      // Convert the matches on the page controller into the match format
8462      // used for the textLayer.
8463      var pageMatches, pageMatchesLength;
8464      if (this.findController !== null) {
8465        pageMatches = this.findController.pageMatches[this.pageIdx] || null;
8466        pageMatchesLength = (this.findController.pageMatchesLength)
8467                            ? this.findController.pageMatchesLength[this.pageIdx] || null : null;
8468      }
8469
8470      this.matches = this.convertMatches(pageMatches, pageMatchesLength);
8471      this.renderMatches(this.matches);
8472    },
8473
8474    /**
8475     * Fixes text selection: adds additional div where mouse was clicked.
8476     * This reduces flickering of the content if mouse slowly dragged down/up.
8477     * @private
8478     */
8479    _bindMouse: function TextLayerBuilder_bindMouse() {
8480      var div = this.textLayerDiv;
8481      var self = this;
8482      div.addEventListener('mousedown', function (e) {
8483        if (self.enhanceTextSelection && self.textLayerRenderTask) {
8484          self.textLayerRenderTask.expandTextDivs(true);
8485          return;
8486        }
8487        var end = div.querySelector('.endOfContent');
8488        if (!end) {
8489          return;
8490        }
8491        // On non-Firefox browsers, the selection will feel better if the height
8492        // of the endOfContent div will be adjusted to start at mouse click
8493        // location -- this will avoid flickering when selections moves up.
8494        // However it does not work when selection started on empty space.
8495        var adjustTop = e.target !== div;
8496        adjustTop = adjustTop && window.getComputedStyle(end).getPropertyValue('-moz-user-select') !== 'none';
8497        if (adjustTop) {
8498          var divBounds = div.getBoundingClientRect();
8499          var r = Math.max(0, (e.pageY - divBounds.top) / divBounds.height);
8500          end.style.top = (r * 100).toFixed(2) + '%';
8501        }
8502        end.classList.add('active');
8503      });
8504      div.addEventListener('mouseup', function (e) {
8505        if (self.enhanceTextSelection && self.textLayerRenderTask) {
8506          self.textLayerRenderTask.expandTextDivs(false);
8507          return;
8508        }
8509        var end = div.querySelector('.endOfContent');
8510        if (!end) {
8511          return;
8512        }
8513        end.style.top = '';
8514        end.classList.remove('active');
8515      });
8516    },
8517  };
8518  return TextLayerBuilder;
8519})();
8520
8521DFLIP.ConvertPageLinks = function () {
8522
8523  var w = arguments[0] / 100, h = arguments[1] / 100;
8524
8525  var toPercent = function (_x, _y, _w, _h, _dest) {
8526    return {
8527      x: _x / w,
8528      y: _y / h,
8529      w: _w / w,
8530      h: _h / h,
8531      dest: _dest
8532    };
8533  };
8534
8535  var percents = [];
8536  var input;
8537
8538  for (var index = 2; index < arguments.length; index++) {
8539    input = arguments[index];
8540    percents[index - 2] = toPercent.apply(this, input);
8541  }
8542
8543  return percents;
8544};
8545
8546DFLIP.parseLinks = function (links) {
8547  var _links;
8548  if (links != null && links.length > 0) {
8549    for (var index = 0; index < links.length; index++) {
8550      _links = links[index];
8551
8552      if (_links != null && _links[0] != null && _links[0].dest == null) {
8553
8554        _links = DFLIP.ConvertPageLinks.apply(this, _links);
8555        links[index] = _links;
8556      }
8557    }
8558  }
8559  return links;
8560};
8561
8562/**
8563 * DFLIP.parseBooks
8564 */
8565(function ($) {
8566
8567  //php and javascript interpret booleans differently so we use string checks
8568  function isTrue(val) {
8569    return val == "true" || val == true;
8570  }
8571
8572  function checkValues(options) {
8573
8574    //boolean values
8575    if (options.webgl != null) options.webgl = isTrue(options.webgl);
8576    if (options.enableDownload != null) options.enableDownload = isTrue(options.enableDownload);
8577    if (options.search != null) options.search = isTrue(options.search);
8578    if (options.enableAnalytics != null) options.enableAnalytics = isTrue(options.enableAnalytics);
8579    if (options.scrollWheel != null) options.scrollWheel = isTrue(options.scrollWheel);
8580    if (options.autoEnableOutline != null) options.autoEnableOutline = isTrue(options.autoEnableOutline);
8581    if (options.autoEnableThumbnail != null) options.autoEnableThumbnail = isTrue(options.autoEnableThumbnail);
8582    if (options.transparent != null) options.transparent = isTrue(options.transparent);
8583    if (options.overwritePDFOutline != null) options.overwritePDFOutline = isTrue(options.overwritePDFOutline);
8584    if (options.soundEnable != null) options.soundEnable = isTrue(options.soundEnable);
8585    if (options.forceFit != null) options.forceFit = isTrue(options.forceFit);
8586    if (options.enableAnnotation != null) options.enableAnnotation = isTrue(options.enableAnnotation);
8587    if (options.webglShadow != null) options.webglShadow = isTrue(options.webglShadow);
8588    if (options.autoPlay != null) options.autoPlay = isTrue(options.autoPlay);
8589    if (options.autoPlayStart != null) options.autoPlayStart = isTrue(options.autoPlayStart);
8590
8591    //integer value
8592    if (options.paddingTop != null) options.paddingTop = parseInt(options.paddingTop, 10);
8593    if (options.paddingRight != null) options.paddingRight = parseInt(options.paddingRight, 10);
8594    if (options.paddingBottom != null) options.paddingBottom = parseInt(options.paddingBottom, 10);
8595    if (options.paddingLeft != null) options.paddingLeft = parseInt(options.paddingLeft, 10);
8596    if (options.zoomRatio != null) options.zoomRatio = parseFloat(options.zoomRatio, 10);
8597    if (options.stiffness != null) options.stiffness = parseFloat(options.stiffness, 10);
8598    if (options.autoPlayDuration != null) options.autoPlayDuration = parseInt(options.autoPlayDuration, 10);
8599    if (options.linkTarget != null) options.linkTarget = parseInt(options.linkTarget, 10);
8600
8601    if (options.pageMode == 0 || options.pageMode == "0")
8602      options.pageMode = null;
8603    if (options.singlePageMode == 0 || options.singlePageMode == "0")
8604      options.singlePageMode = null;
8605  }
8606
8607  function parseOptions(options) {
8608
8609    //bail out if already parsed or failed
8610    if (options.parsed == true) return;
8611
8612    options.parsed = true;
8613    //options.links are in json format
8614    //{"1":[]}
8615    //convert them to array format
8616    var links = [];
8617    checkValues(options);
8618
8619    if (typeof dFlipWPGlobal !== 'undefined' && options.wpOptions == 'true') {
8620
8621      try {
8622        for (var key in options.links) {
8623          var _pagelinks = options.links[key];
8624          var pagelink = [100, 100];
8625          for (var l = 0; l < _pagelinks.length; l++) {
8626            var _link = _pagelinks[l];
8627            var _values = _link.substr(1).slice(0, -1).split(",");
8628            var _linkarr = [];
8629            for (var v = 0; v < 5; v++) {
8630              _linkarr[v] = _values[v];
8631            }
8632            pagelink.push(_linkarr);
8633          }
8634          links[parseInt(key, 10) + 1] = pagelink;
8635        }
8636      } catch (error) {
8637        console.error(error.stack);
8638      }
8639      options.links = DFLIP.parseLinks(links);
8640
8641    }
8642    else {
8643      options.links = DFLIP.parseLinks(options.links);
8644    }
8645
8646  }
8647
8648  DFLIP.getOptions = function (book) {
8649
8650    book = $(book);
8651
8652    var book_id = book.attr("id");
8653
8654    var options = "option_" + book_id,
8655      source = book.attr("source") || book.attr("df-source");
8656
8657    //verify and optimize the values
8658    options = options == null || options == "" || window[options] == null ? {} : window[options];
8659
8660    options.source = source == null || source == "" ? options.source : source;
8661
8662    /*As of 1.2.6 attribute values are also considered as options in some cases*/
8663    var attrOptions = {
8664      webgl: book.attr("webgl"),
8665      height: book.attr("height"),
8666      soundEnable: book.attr("sound"),
8667      bookTitle: book.attr("title"),
8668      transparent: book.attr("transparent"),
8669      enableDownload: book.attr("download"),
8670      search: book.attr("search"),
8671      duration: book.attr("duration"),
8672      hard: book.attr("hard"),
8673      openPage: book.data("page"),
8674      pageMode: book.attr("pagemode"),
8675      direction: book.attr("direction"),
8676      backgroundColor: book.attr("backgroundcolor"),
8677      scrollWheel: book.attr("scrollwheel"),
8678      backgroundImage: book.attr("backgroundimage"),
8679      paddingTop: book.attr("paddingtop"),
8680      paddingRight: book.attr("paddingright"),
8681      paddingBottom: book.attr("paddingbottom"),
8682      paddingLeft: book.attr("paddingleft"),
8683      wpOptions: book.attr("wpoptions")
8684    };
8685
8686    options = $.extend(true, {}, options, attrOptions);
8687
8688    parseOptions(options);
8689
8690    return options;
8691  }
8692
8693  DFLIP.parseBooks = function () {
8694
8695    $('._df_button, ._df_thumb, ._df_custom, ._df_book').each(function () {
8696
8697      var book = $(this);
8698
8699      //fetch any existing values
8700      var parsed = book.attr("parsed") || book.attr("df-parsed");
8701
8702      //skip if already parsed or failed
8703      if (parsed !== "true") {
8704        book.attr("df-parsed", "true")
8705
8706        if (book.hasClass("_df_book")) {
8707
8708          var book_id = book.attr("id"),
8709            slug = book.attr("slug");
8710          var options = DFLIP.getOptions(book);
8711          options.id = book_id;
8712          if (slug != null)
8713            options.slug = slug;
8714          if (book_id) {
8715            window[book_id.toString()] = $(book).flipBook(options.source, options);
8716          }
8717          else {
8718            $(book).flipBook(options.source, options);
8719          }
8720
8721        }
8722        else {
8723
8724          if (book.hasClass("_df_thumb")) {
8725            var wrapper = $("<div class='_df_book-cover'>");
8726
8727            var text = book.html().trim();
8728            book.html("");
8729            var title = $("<span class='_df_book-title'>").html(text).appendTo(wrapper);
8730
8731            var thumb = book.attr("thumb") || book.attr("df-thumb"),
8732              thumbType = book.attr("thumbtype") || DFLIP.defaults.thumbElement || "div",
8733              tags = book.attr("tags") || book.attr("df-tags");
8734
8735            if (tags) {
8736              tags = tags.split(",");
8737
8738              if (tags.length > 0) {
8739                for (var tagcount = 0; tagcount < tags.length; tagcount++) {
8740                  book.append("<span class='_df_book-tag'>" + tags[tagcount] + "</span>");
8741                }
8742              }
8743            }
8744
8745            if (thumb != null && thumb.toString().trim() != '') {
8746              if (thumbType == 'img') {
8747                wrapper.append('<img src="' + thumb + '" alt="' + text 
8747+ '"/>');
8748                book.attr("thumb-type", "img");
8749              }
8750              else {
8751                wrapper.css({
8752                  backgroundImage: "url('" + thumb + "')"
8753                });
8754              }
8755            }
8756            else {
8757              wrapper.addClass("_df_thumb-not-found");
8758            }
8759
8760            book.append(wrapper);
8761          }
8762
8763        }
8764
8765      }
8766    });
8767
8768  };
8769
8770  $(document).ready(function () {
8771
8772    //Autodetection if the folder structure is copied properly
8773    if (typeof dFlipLocation == 'undefined' && DFLIP.autoDetectLocation != false) {
8774      $("script").each(function () {
8775        var src = $(this)[0].src;
8776        if ((src.indexOf("/dflip.js") > -1 || src.indexOf("/dflip.min.js") > -1)
8777          && (src.indexOf("https://") > -1 || src.indexOf("http://") > -1) && src.indexOf("js/dflip.") > -1) {
8778          var splits = src.split("/");
8779          window.dFlipLocation = splits.slice(0, -2).join("/");
8780        }
8781      });
8782    }
8783
8784    if (typeof dFlipLocation !== 'undefined') {
8785
8786      //add ending forward slash trail for safety
8787      if (dFlipLocation.length > 2 && dFlipLocation.slice(-1) !== "/") {
8788        window.dFlipLocation += "/";
8789      }
8790
8791      //PRESENTATION.defaults.backgroundImage = "blank"; "images/textures/white.jpg";
8792      //PRESENTATION.defaults.textureLoadFallback = dFlipLocation + "images/textures/white.jpg";
8793      DFLIP.defaults.mockupjsSrc = dFlipLocation + "js/libs/mockup.min.js";
8794      DFLIP.defaults.pdfjsSrc = dFlipLocation + "js/libs/pdf.min.js";
8795      DFLIP.defaults.pdfjsCompatibilitySrc = dFlipLocation + "js/libs/compatibility.js";
8796      DFLIP.defaults.threejsSrc = dFlipLocation + "js/libs/three.min.js";
8797      DFLIP.defaults.pdfjsWorkerSrc = dFlipLocation + "js/libs/pdf.worker.min.js";
8798      DFLIP.defaults.soundFile = dFlipLocation + "sound/turn2.mp3";
8799      DFLIP.defaults.imagesLocation = dFlipLocation + "images";
8800      DFLIP.defaults.imageResourcesPath = dFlipLocation + "images/pdfjs/";
8801      DFLIP.defaults.cMapUrl = dFlipLocation + "js/libs/cmaps/";
8802
8803      if (typeof dFlipWPGlobal !== 'undefined') {
8804
8805        checkValues(dFlipWPGlobal);
8806
8807        $.extend(DFLIP.defaults, dFlipWPGlobal);
8808      }
8809    }
8810
8811    DFLIP.preParseHash = window.location.hash;
8812    DFLIP.parseBooks();
8813
8814    $('body').on('click', '._df_button, ._df_thumb, ._df_custom', function (event) {
8815      //incase the element is link type
8816      event.preventDefault();
8817      //cache the book element
8818      var book = $(this);
8819
8820      if (!window.dfLightBox) {
8821        window.dfLightBox = new DFLightBox(function () {
8822
8823          if (window.location.hash.indexOf("#dflip-") == 0)
8824            window.location.hash = "#_";
8825          window.dfActiveLightBoxBook.analytics({
8826            eventAction: "Book Closed",
8827            options: window.dfActiveLightBoxBook.options
8828          });
8829          window.dfActiveLightBoxBook.dispose();
8830          window.dfActiveLightBoxBook = null;
8831        });
8832      }
8833
8834      window.dfLightBox.duration = 500;
8835
8836      if (window.dfActiveLightBoxBook && window.dfActiveLightBoxBook.dispose) {
8837        window.dfActiveLightBoxBook.dispose();
8838
8839      }
8840      else {
8841        window.dfLightBox.show(
8842          function () {
8843            //                            $("body").addClass("df-no-scroll");
8844            var options = DFLIP.getOptions(book);
8845            options.transparent = false;
8846            options.height = "100%";
8847            options.id = book.attr("id");
8848            var slug = book.attr("slug");
8849            if (slug != null)
8850              options.slug = slug;
8851            options.isLightBox = true;
8852            window.dfActiveLightBoxBook = $(window.dfLightBox.container).flipBook(options.source, options);
8853          }
8854        );
8855      }
8856
8857
8858    });
8859
8860    if (DFLIP.utils.isSafari || DFLIP.utils.isIOS) {
8861      $('body').addClass("df-webkit");
8862    }
8863    //parse hash and check if any exists
8864    if (DFLIP.preParseHash && DFLIP.preParseHash.indexOf('dflip-') >= 0) {
8865      var id = DFLIP.preParseHash.split('dflip-')[1].split('/')[0];
8866      var page = DFLIP.preParseHash.split('dflip-')[1].split('/')[1];
8867      if (page != null) {
8868        page = page.split('/')[0];
8869      }
8870      var book;
8871      //first check for slug pattern
8872      book = $("[slug=" + id + "]");
8873      //then id pattern
8874      if (book.length == 0) book = $('#' + id);
8875
8876      if (book.length > 0) {
8877
8878        //var oldHash = window.location.hash;
8879        //window.location.hash = id;
8880        //window.location.hash = DFLIP.preParseHash;
8881
8882        if (page != null) {
8883          book.data("page", page)
8884        }
8885
8886        if (book.is('._df_button, ._df_thumb, ._df_custom')) {
8887          book.trigger("click");
8888        }
8889      }
8890    }
8891
8892    $('body').on('click', '.df-ui-sidemenu-close', function () {
8893      var $this = $(this);
8894      $this.closest(".df-container").find(".df-ui-outline.df-active , .df-ui-thumbn
8894ail.df-active").trigger("click");
8895    });
8896
8897
8898  });
8899
8900})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.