From 32993dc58ce82cd14557ab00686af7a684898416 Mon Sep 17 00:00:00 2001 From: Fred Chasen Date: Mon, 24 Oct 2016 15:15:16 +0200 Subject: [PATCH] Tabify src --- dist/epub.js | 7027 ++++++++++++++++++------------------ dist/epub.js.map | 2 +- gulpfile.js | 162 +- src/book.js | 416 +-- src/contents.js | 776 ++-- src/core.js | 740 ++-- src/epub.js | 2 +- src/epubcfi.js | 1302 +++---- src/hook.js | 52 +- src/layout.js | 150 +- src/locations.js | 222 +- src/managers/continuous.js | 404 +-- src/managers/single.js | 124 +- src/mapping.js | 390 +- src/navigation.js | 126 +- src/parser.js | 350 +- src/queue.js | 232 +- src/rendition.js | 120 +- src/replacements.js | 136 +- src/request.js | 202 +- src/section.js | 192 +- src/spine.js | 146 +- src/stage.js | 4 +- src/unarchive.js | 182 +- src/views.js | 136 +- src/views/iframe.js | 624 ++-- src/views/inline.js | 446 +-- test/epub.js | 50 +- test/epubcfi.js | 402 +-- test/tests/epub.js | 384 +- test/tests/rendering.js | 16 +- 31 files changed, 7759 insertions(+), 7758 deletions(-) diff --git a/dist/epub.js b/dist/epub.js index 7d6cb97..65d3572 100644 --- a/dist/epub.js +++ b/dist/epub.js @@ -5441,264 +5441,264 @@ var EpubCFI = require('./epubcfi'); function Book(_url, options){ - this.settings = core.extend(this.settings || {}, { + this.settings = core.extend(this.settings || {}, { requestMethod: this.requestMethod }); - core.extend(this.settings, options); + core.extend(this.settings, options); - // Promises - this.opening = new RSVP.defer(); - this.opened = this.opening.promise; - this.isOpen = false; + // Promises + this.opening = new RSVP.defer(); + this.opened = this.opening.promise; + this.isOpen = false; - this.url = undefined; + this.url = undefined; - this.loading = { - manifest: new RSVP.defer(), - spine: new RSVP.defer(), - metadata: new RSVP.defer(), - cover: new RSVP.defer(), - navigation: new RSVP.defer(), - pageList: new RSVP.defer() - }; + this.loading = { + manifest: new RSVP.defer(), + spine: new RSVP.defer(), + metadata: new RSVP.defer(), + cover: new RSVP.defer(), + navigation: new RSVP.defer(), + pageList: new RSVP.defer() + }; - this.loaded = { - manifest: this.loading.manifest.promise, - spine: this.loading.spine.promise, - metadata: this.loading.metadata.promise, - cover: this.loading.cover.promise, - navigation: this.loading.navigation.promise, - pageList: this.loading.pageList.promise - }; + this.loaded = { + manifest: this.loading.manifest.promise, + spine: this.loading.spine.promise, + metadata: this.loading.metadata.promise, + cover: this.loading.cover.promise, + navigation: this.loading.navigation.promise, + pageList: this.loading.pageList.promise + }; - this.ready = RSVP.hash(this.loaded); + this.ready = RSVP.hash(this.loaded); - // Queue for methods used before opening - this.isRendered = false; - // this._q = core.queue(this); + // Queue for methods used before opening + this.isRendered = false; + // this._q = core.queue(this); - this.request = this.settings.requestMethod.bind(this); + this.request = this.settings.requestMethod.bind(this); - this.spine = new Spine(this.request); - this.locations = new Locations(this.spine, this.request); + this.spine = new Spine(this.request); + this.locations = new Locations(this.spine, this.request); - if(_url) { - this.open(_url).catch(function (error) { - var err = new Error("Cannot load book at "+ _url ); - console.error(err); + if(_url) { + this.open(_url).catch(function (error) { + var err = new Error("Cannot load book at "+ _url ); + console.error(err); - this.trigger("loadFailed", error); - }.bind(this)); - } + this.trigger("loadFailed", error); + }.bind(this)); + } }; Book.prototype.open = function(_url, options){ - var uri; - var parse = new Parser(); - var epubPackage; - var epubContainer; - var book = this; - var containerPath = "META-INF/container.xml"; - var location; - var absoluteUri; - var isArrayBuffer = false; - var isBase64 = options && options.base64; + var uri; + var parse = new Parser(); + var epubPackage; + var epubContainer; + var book = this; + var containerPath = "META-INF/container.xml"; + var location; + var absoluteUri; + var isArrayBuffer = false; + var isBase64 = options && options.base64; - if(!_url) { - this.opening.resolve(this); - return this.opened; - } - - // Reuse parsed url or create a new uri object - // if(typeof(_url) === "object") { - // uri = _url; - // } else { - // uri = core.uri(_url); - // } - if (_url instanceof ArrayBuffer || isBase64) { - isArrayBuffer = true; - this.url = '/'; - } else { - uri = URI(_url); + if(!_url) { + this.opening.resolve(this); + return this.opened; } - if (window && window.location && uri) { - absoluteUri = uri.absoluteTo(window.location.href); - this.url = absoluteUri.toString(); - } if (window && window.location) { - this.url = window.location.href; - } else { - this.url = _url; - } + // Reuse parsed url or create a new uri object + // if(typeof(_url) === "object") { + // uri = _url; + // } else { + // uri = core.uri(_url); + // } + if (_url instanceof ArrayBuffer || isBase64) { + isArrayBuffer = true; + this.url = '/'; + } else { + uri = URI(_url); + } - // Find path to the Container - if(uri && uri.suffix() === "opf") { - // Direct link to package, no container - this.packageUrl = _url; - this.containerUrl = ''; + if (window && window.location && uri) { + absoluteUri = uri.absoluteTo(window.location.href); + this.url = absoluteUri.toString(); + } else if (window && window.location) { + this.url = window.location.href; + } else { + this.url = _url; + } - if(uri.origin()) { - this.baseUrl = uri.origin() + "/" + uri.directory() + "/"; - } else if(absoluteUri){ - this.baseUrl = absoluteUri.origin(); - this.baseUrl += absoluteUri.directory() + "/"; - } else { - this.baseUrl = uri.directory() + "/"; - } + // Find path to the Container + if(uri && uri.suffix() === "opf") { + // Direct link to package, no container + this.packageUrl = _url; + this.containerUrl = ''; - epubPackage = this.request(this.packageUrl) - .catch(function(error) { - book.opening.reject(error); - }); + if(uri.origin()) { + this.baseUrl = uri.origin() + "/" + uri.directory() + "/"; + } else if(absoluteUri){ + this.baseUrl = absoluteUri.origin(); + this.baseUrl += absoluteUri.directory() + "/"; + } else { + this.baseUrl = uri.directory() + "/"; + } - } else if(isArrayBuffer || isBase64 || this.isArchivedUrl(uri)) { - // Book is archived - this.url = '/'; - this.containerUrl = URI(containerPath).absoluteTo(this.url).toString(); + epubPackage = this.request(this.packageUrl) + .catch(function(error) { + book.opening.reject(error); + }); - epubContainer = this.unarchive(_url, isBase64). - then(function() { - return this.request(this.containerUrl); - }.bind(this)) - .catch(function(error) { - book.opening.reject(error); - }); - } - // Find the path to the Package from the container - else if (!uri.suffix()) { + } else if(isArrayBuffer || isBase64 || this.isArchivedUrl(uri)) { + // Book is archived + this.url = '/'; + this.containerUrl = URI(containerPath).absoluteTo(this.url).toString(); - this.containerUrl = this.url + containerPath; + epubContainer = this.unarchive(_url, isBase64). + then(function() { + return this.request(this.containerUrl); + }.bind(this)) + .catch(function(error) { + book.opening.reject(error); + }); + } + // Find the path to the Package from the container + else if (!uri.suffix()) { - epubContainer = this.request(this.containerUrl) - .catch(function(error) { - // handle errors in loading container - book.opening.reject(error); - }); - } + this.containerUrl = this.url + containerPath; - if (epubContainer) { - epubPackage = epubContainer. - then(function(containerXml){ - return parse.container(containerXml); // Container has path to content - }). - then(function(paths){ - var packageUri = URI(paths.packagePath); - var absPackageUri = packageUri.absoluteTo(book.url); - var absWindowUri; + epubContainer = this.request(this.containerUrl) + .catch(function(error) { + // handle errors in loading container + book.opening.reject(error); + }); + } - book.packageUrl = absPackageUri.toString(); - book.encoding = paths.encoding; + if (epubContainer) { + epubPackage = epubContainer. + then(function(containerXml){ + return parse.container(containerXml); // Container has path to content + }). + then(function(paths){ + var packageUri = URI(paths.packagePath); + var absPackageUri = packageUri.absoluteTo(book.url); + var absWindowUri; - // Set Url relative to the content - if(absPackageUri.origin()) { - book.baseUrl = absPackageUri.origin() + absPackageUri.directory() + "/"; - } else { - if(packageUri.directory()) { - book.baseUrl = "/" + packageUri.directory() + "/"; - } else { - book.baseUrl = "/" - } - } + book.packageUrl = absPackageUri.toString(); + book.encoding = paths.encoding; - return book.request(book.packageUrl); - }).catch(function(error) { - // handle errors in either of the two requests - book.opening.reject(error); - }); - } + // Set Url relative to the content + if(absPackageUri.origin()) { + book.baseUrl = absPackageUri.origin() + absPackageUri.directory() + "/"; + } else { + if(packageUri.directory()) { + book.baseUrl = "/" + packageUri.directory() + "/"; + } else { + book.baseUrl = "/" + } + } - epubPackage.then(function(packageXml) { + return book.request(book.packageUrl); + }).catch(function(error) { + // handle errors in either of the two requests + book.opening.reject(error); + }); + } - if (!packageXml) { - return; - } + epubPackage.then(function(packageXml) { - // Get package information from epub opf - book.unpack(packageXml); + if (!packageXml) { + return; + } - // Resolve promises - book.loading.manifest.resolve(book.package.manifest); - book.loading.metadata.resolve(book.package.metadata); - book.loading.spine.resolve(book.spine); - book.loading.cover.resolve(book.cover); + // Get package information from epub opf + book.unpack(packageXml); - book.isOpen = true; + // Resolve promises + book.loading.manifest.resolve(book.package.manifest); + book.loading.metadata.resolve(book.package.metadata); + book.loading.spine.resolve(book.spine); + book.loading.cover.resolve(book.cover); - // Clear queue of any waiting book request + book.isOpen = true; - // Resolve book opened promise - book.opening.resolve(book); + // Clear queue of any waiting book request - }).catch(function(error) { - // handle errors in parsing the book - // console.error(error.message, error.stack); - book.opening.reject(error); - }); + // Resolve book opened promise + book.opening.resolve(book); - return this.opened; + }).catch(function(error) { + // handle errors in parsing the book + // console.error(error.message, error.stack); + book.opening.reject(error); + }); + + return this.opened; }; Book.prototype.unpack = function(packageXml){ - var book = this, - parse = new Parser(); + var book = this, + parse = new Parser(); - book.package = parse.packageContents(packageXml); // Extract info from contents - if(!book.package) { - return; - } + book.package = parse.packageContents(packageXml); // Extract info from contents + if(!book.package) { + return; + } - book.package.baseUrl = book.baseUrl; // Provides a url base for resolving paths + book.package.baseUrl = book.baseUrl; // Provides a url base for resolving paths - this.spine.load(book.package); + this.spine.load(book.package); - book.navigation = new Navigation(book.package, this.request); - book.navigation.load().then(function(toc){ - book.toc = toc; - book.loading.navigation.resolve(book.toc); - }); + book.navigation = new Navigation(book.package, this.request); + book.navigation.load().then(function(toc){ + book.toc = toc; + book.loading.navigation.resolve(book.toc); + }); - // //-- Set Global Layout setting based on metadata - // MOVE TO RENDER - // book.globalLayoutProperties = book.parseLayoutProperties(book.package.metadata); + // //-- Set Global Layout setting based on metadata + // MOVE TO RENDER + // book.globalLayoutProperties = book.parseLayoutProperties(book.package.metadata); - book.cover = URI(book.package.coverPath).absoluteTo(book.baseUrl).toString(); + book.cover = URI(book.package.coverPath).absoluteTo(book.baseUrl).toString(); }; // Alias for book.spine.get Book.prototype.section = function(target) { - return this.spine.get(target); + return this.spine.get(target); }; // Sugar to render a book Book.prototype.renderTo = function(element, options) { - // var renderMethod = (options && options.method) ? - // options.method : - // "single"; + // var renderMethod = (options && options.method) ? + // options.method : + // "single"; - this.rendition = new Rendition(this, options); - this.rendition.attachTo(element); + this.rendition = new Rendition(this, options); + this.rendition.attachTo(element); - return this.rendition; + return this.rendition; }; Book.prototype.requestMethod = function(_url) { - // Switch request methods - if(this.unarchived) { - return this.unarchived.request(_url); - } else { - return request(_url, null, this.requestCredentials, this.requestHeaders); - } + // Switch request methods + if(this.unarchived) { + return this.unarchived.request(_url); + } else { + return request(_url, null, this.requestCredentials, this.requestHeaders); + } }; Book.prototype.setRequestCredentials = function(_credentials) { - this.requestCredentials = _credentials; + this.requestCredentials = _credentials; }; Book.prototype.setRequestHeaders = function(_headers) { - this.requestHeaders = _headers; + this.requestHeaders = _headers; }; Book.prototype.unarchive = function(bookUrl, isBase64){ @@ -5708,21 +5708,21 @@ Book.prototype.unarchive = function(bookUrl, isBase64){ //-- Checks if url has a .epub or .zip extension, or is ArrayBuffer (of zip/epub) Book.prototype.isArchivedUrl = function(bookUrl){ - var uri; - var extension; + var uri; + var extension; - if (bookUrl instanceof ArrayBuffer) { + if (bookUrl instanceof ArrayBuffer) { return true; } - // Reuse parsed url or create a new uri object - // if(typeof(bookUrl) === "object") { - // uri = bookUrl; - // } else { - // uri = core.uri(bookUrl); - // } - uri = URI(bookUrl); - extension = uri.suffix(); + // Reuse parsed url or create a new uri object + // if(typeof(bookUrl) === "object") { + // uri = bookUrl; + // } else { + // uri = core.uri(bookUrl); + // } + uri = URI(bookUrl); + extension = uri.suffix(); if(extension && (extension == "epub" || extension == "zip")){ return true; @@ -5748,13 +5748,13 @@ Book.prototype.coverUrl = function(){ }; Book.prototype.range = function(cfiRange) { - var cfi = new EpubCFI(cfiRange); - var item = this.spine.get(cfi.spinePos); + var cfi = new EpubCFI(cfiRange); + var item = this.spine.get(cfi.spinePos); - return item.load().then(function (contents) { - var range = cfi.toRange(item.document); - return range; - }) + return item.load().then(function (contents) { + var range = cfi.toRange(item.document); + return range; + }) }; module.exports = Book; @@ -5764,7 +5764,7 @@ RSVP.EventTarget.mixin(Book.prototype); //-- Handle RSVP Errors RSVP.on('error', function(event) { - console.error(event); + console.error(event); }); RSVP.configure('instrument', false); //-- true | will logging out all RSVP rejections @@ -5772,7 +5772,7 @@ RSVP.configure('instrument', false); //-- true | will logging out all RSVP rejec // RSVP.on('chained', listener); // RSVP.on('fulfilled', listener); RSVP.on('rejected', function(event){ - console.error(event.detail.message, event.detail.stack); + console.error(event.detail.message, event.detail.stack); }); },{"./core":10,"./epubcfi":11,"./locations":14,"./navigation":18,"./parser":19,"./rendition":21,"./request":23,"./spine":25,"./unarchive":27,"rsvp":5,"urijs":7}],9:[function(require,module,exports){ @@ -5783,221 +5783,221 @@ var Mapping = require('./mapping'); function Contents(doc, content, cfiBase) { - // Blank Cfi for Parsing - this.epubcfi = new EpubCFI(); + // Blank Cfi for Parsing + this.epubcfi = new EpubCFI(); - this.document = doc; - this.documentElement = this.document.documentElement; - this.content = content || this.document.body; - this.window = this.document.defaultView; - // Dom events to listen for - this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"]; + this.document = doc; + this.documentElement = this.document.documentElement; + this.content = content || this.document.body; + this.window = this.document.defaultView; + // Dom events to listen for + this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"]; - this._size = { - width: 0, - height: 0 - } + this._size = { + width: 0, + height: 0 + } - this.cfiBase = cfiBase || ""; + this.cfiBase = cfiBase || ""; - this.listeners(); + this.listeners(); }; Contents.prototype.width = function(w) { - // var frame = this.documentElement; - var frame = this.content; + // var frame = this.documentElement; + var frame = this.content; - if (w && core.isNumber(w)) { - w = w + "px"; - } + if (w && core.isNumber(w)) { + w = w + "px"; + } - if (w) { - frame.style.width = w; - // this.content.style.width = w; - } + if (w) { + frame.style.width = w; + // this.content.style.width = w; + } - return this.window.getComputedStyle(frame)['width']; + return this.window.getComputedStyle(frame)['width']; }; Contents.prototype.height = function(h) { - // var frame = this.documentElement; - var frame = this.content; + // var frame = this.documentElement; + var frame = this.content; - if (h && core.isNumber(h)) { - h = h + "px"; - } + if (h && core.isNumber(h)) { + h = h + "px"; + } - if (h) { - frame.style.height = h; - // this.content.style.height = h; - } + if (h) { + frame.style.height = h; + // this.content.style.height = h; + } - return this.window.getComputedStyle(frame)['height']; + return this.window.getComputedStyle(frame)['height']; }; Contents.prototype.contentWidth = function(w) { - var content = this.content || this.document.body; + var content = this.content || this.document.body; - if (w && core.isNumber(w)) { - w = w + "px"; - } + if (w && core.isNumber(w)) { + w = w + "px"; + } - if (w) { - content.style.width = w; - } + if (w) { + content.style.width = w; + } - return this.window.getComputedStyle(content)['width']; + return this.window.getComputedStyle(content)['width']; }; Contents.prototype.contentHeight = function(h) { - var content = this.content || this.document.body; + var content = this.content || this.document.body; - if (h && core.isNumber(h)) { - h = h + "px"; - } + if (h && core.isNumber(h)) { + h = h + "px"; + } - if (h) { - content.style.height = h; - } + if (h) { + content.style.height = h; + } - return this.window.getComputedStyle(content)['height']; + return this.window.getComputedStyle(content)['height']; }; Contents.prototype.textWidth = function() { - var width; - var range = this.document.createRange(); - var content = this.content || this.document.body; + var width; + var range = this.document.createRange(); + var content = this.content || this.document.body; - // Select the contents of frame - range.selectNodeContents(content); + // Select the contents of frame + range.selectNodeContents(content); - // get the width of the text content - width = range.getBoundingClientRect().width; + // get the width of the text content + width = range.getBoundingClientRect().width; - return width; + return width; }; Contents.prototype.textHeight = function() { - var height; - var range = this.document.createRange(); - var content = this.content || this.document.body; + var height; + var range = this.document.createRange(); + var content = this.content || this.document.body; - range.selectNodeContents(content); + range.selectNodeContents(content); - height = range.getBoundingClientRect().height; + height = range.getBoundingClientRect().height; - return height; + return height; }; Contents.prototype.scrollWidth = function() { - var width = this.documentElement.scrollWidth; + var width = this.documentElement.scrollWidth; - return width; + return width; }; Contents.prototype.scrollHeight = function() { - var height = this.documentElement.scrollHeight; + var height = this.documentElement.scrollHeight; - return height; + return height; }; Contents.prototype.overflow = function(overflow) { - if (overflow) { - this.documentElement.style.overflow = overflow; - } + if (overflow) { + this.documentElement.style.overflow = overflow; + } - return this.window.getComputedStyle(this.documentElement)['overflow']; + return this.window.getComputedStyle(this.documentElement)['overflow']; }; Contents.prototype.overflowX = function(overflow) { - if (overflow) { - this.documentElement.style.overflowX = overflow; - } + if (overflow) { + this.documentElement.style.overflowX = overflow; + } - return this.window.getComputedStyle(this.documentElement)['overflowX']; + return this.window.getComputedStyle(this.documentElement)['overflowX']; }; Contents.prototype.overflowY = function(overflow) { - if (overflow) { - this.documentElement.style.overflowY = overflow; - } + if (overflow) { + this.documentElement.style.overflowY = overflow; + } - return this.window.getComputedStyle(this.documentElement)['overflowY']; + return this.window.getComputedStyle(this.documentElement)['overflowY']; }; Contents.prototype.css = function(property, value) { - var content = this.content || this.document.body; + var content = this.content || this.document.body; - if (value) { - content.style[property] = value; - } + if (value) { + content.style[property] = value; + } - return this.window.getComputedStyle(content)[property]; + return this.window.getComputedStyle(content)[property]; }; Contents.prototype.viewport = function(options) { - var width, height, scale, scalable; - var $viewport = this.document.querySelector("meta[name='viewport']"); - var newContent = ''; + var width, height, scale, scalable; + var $viewport = this.document.querySelector("meta[name='viewport']"); + var newContent = ''; - /** - * check for the viewport size - * - */ - if($viewport && $viewport.hasAttribute("content")) { - content = $viewport.getAttribute("content"); - contents = content.split(/\s*,\s*/); - if(contents[0]){ - width = contents[0].replace("width=", '').trim(); - } - if(contents[1]){ - height = contents[1].replace("height=", '').trim(); - } - if(contents[2]){ - scale = contents[2].replace("initial-scale=", '').trim(); - } - if(contents[3]){ - scalable = contents[3].replace("user-scalable=", '').trim(); - } - } + /** + * check for the viewport size + * + */ + if($viewport && $viewport.hasAttribute("content")) { + content = $viewport.getAttribute("content"); + contents = content.split(/\s*,\s*/); + if(contents[0]){ + width = contents[0].replace("width=", '').trim(); + } + if(contents[1]){ + height = contents[1].replace("height=", '').trim(); + } + if(contents[2]){ + scale = contents[2].replace("initial-scale=", '').trim(); + } + if(contents[3]){ + scalable = contents[3].replace("user-scalable=", '').trim(); + } + } - if (options) { + if (options) { - newContent += "width=" + (options.width || width); - newContent += ", height=" + (options.height || height); - if (options.scale || scale) { - newContent += ", initial-scale=" + (options.scale || scale); - } - if (options.scalable || scalable) { - newContent += ", user-scalable=" + (options.scalable || scalable); - } + newContent += "width=" + (options.width || width); + newContent += ", height=" + (options.height || height); + if (options.scale || scale) { + newContent += ", initial-scale=" + (options.scale || scale); + } + if (options.scalable || scalable) { + newContent += ", user-scalable=" + (options.scalable || scalable); + } - if (!$viewport) { - $viewport = this.document.createElement("meta"); - $viewport.setAttribute("name", "viewport"); - this.document.querySelector('head').appendChild($viewport); - } + if (!$viewport) { + $viewport = this.document.createElement("meta"); + $viewport.setAttribute("name", "viewport"); + this.document.querySelector('head').appendChild($viewport); + } - $viewport.setAttribute("content", newContent); - } + $viewport.setAttribute("content", newContent); + } - return { - width: parseInt(width), - height: parseInt(height) - }; + return { + width: parseInt(width), + height: parseInt(height) + }; }; @@ -6023,416 +6023,417 @@ Contents.prototype.viewport = function(options) { // }; Contents.prototype.expand = function() { - this.trigger("expand"); + this.trigger("expand"); }; Contents.prototype.listeners = function() { - this.imageLoadListeners(); + this.imageLoadListeners(); - this.mediaQueryListeners(); + this.mediaQueryListeners(); - // this.fontLoadListeners(); + // this.fontLoadListeners(); - this.addEventListeners(); + this.addEventListeners(); - this.addSelectionListeners(); + this.addSelectionListeners(); - this.resizeListeners(); + this.resizeListeners(); }; Contents.prototype.removeListeners = function() { - this.removeEventListeners(); + this.removeEventListeners(); - this.removeSelectionListeners(); + this.removeSelectionListeners(); }; Contents.prototype.resizeListeners = function() { - var width, height; - // Test size again - clearTimeout(this.expanding); + var width, height; + // Test size again + clearTimeout(this.expanding); - width = this.scrollWidth(); - height = this.scrollHeight(); + width = this.scrollWidth(); + height = this.scrollHeight(); - if (width != this._size.width || height != this._size.height) { + if (width != this._size.width || height != this._size.height) { - this._size = { - width: width, - height: height - } + this._size = { + width: width, + height: height + } - this.trigger("resize", this._size); - } + this.trigger("resize", this._size); + } - this.expanding = setTimeout(this.resizeListeners.bind(this), 350); + this.expanding = setTimeout(this.resizeListeners.bind(this), 350); }; //https://github.com/tylergaw/media-query-events/blob/master/js/mq-events.js Contents.prototype.mediaQueryListeners = function() { - var sheets = this.document.styleSheets; - var mediaChangeHandler = function(m){ - if(m.matches && !this._expanding) { - setTimeout(this.expand.bind(this), 1); - // this.expand(); - } - }.bind(this); + var sheets = this.document.styleSheets; + var mediaChangeHandler = function(m){ + if(m.matches && !this._expanding) { + setTimeout(this.expand.bind(this), 1); + // this.expand(); + } + }.bind(this); - for (var i = 0; i < sheets.length; i += 1) { - var rules = sheets[i].cssRules; - if(!rules) return; // Stylesheets changed - for (var j = 0; j < rules.length; j += 1) { - //if (rules[j].constructor === CSSMediaRule) { - if(rules[j].media){ - var mql = this.window.matchMedia(rules[j].media.mediaText); - mql.addListener(mediaChangeHandler); - //mql.onchange = mediaChangeHandler; - } - } - } + for (var i = 0; i < sheets.length; i += 1) { + var rules = sheets[i].cssRules; + if(!rules) return; // Stylesheets changed + for (var j = 0; j < rules.length; j += 1) { + //if (rules[j].constructor === CSSMediaRule) { + if(rules[j].media){ + var mql = this.window.matchMedia(rules[j].media.mediaText); + mql.addListener(mediaChangeHandler); + //mql.onchange = mediaChangeHandler; + } + } + } }; Contents.prototype.observe = function(target) { - var renderer = this; + var renderer = this; - // create an observer instance - var observer = new MutationObserver(function(mutations) { - if(renderer._expanding) { - renderer.expand(); - } - // mutations.forEach(function(mutation) { - // console.log(mutation); - // }); - }); + // create an observer instance + var observer = new MutationObserver(function(mutations) { + if(renderer._expanding) { + renderer.expand(); + } + // mutations.forEach(function(mutation) { + // console.log(mutation); + // }); + }); - // configuration of the observer: - var config = { attributes: true, childList: true, characterData: true, subtree: true }; + // configuration of the observer: + var config = { attributes: true, childList: true, characterData: true, subtree: true }; - // pass in the target node, as well as the observer options - observer.observe(target, config); + // pass in the target node, as well as the observer options + observer.observe(target, config); - return observer; + return observer; }; Contents.prototype.imageLoadListeners = function(target) { - var images = this.document.querySelectorAll("img"); - var img; - for (var i = 0; i < images.length; i++) { - img = images[i]; + var images = this.document.querySelectorAll("img"); + var img; + for (var i = 0; i < images.length; i++) { + img = images[i]; - if (typeof img.naturalWidth !== "undefined" && - img.naturalWidth === 0) { - img.onload = this.expand.bind(this); - } - } + if (typeof img.naturalWidth !== "undefined" && + img.naturalWidth === 0) { + img.onload = this.expand.bind(this); + } + } }; Contents.prototype.fontLoadListeners = function(target) { - if (!this.document || !this.document.fonts) { - return; - } + if (!this.document || !this.document.fonts) { + return; + } - this.document.fonts.ready.then(function () { - this.expand(); - }.bind(this)); + this.document.fonts.ready.then(function () { + this.expand(); + }.bind(this)); }; Contents.prototype.root = function() { - if(!this.document) return null; - return this.document.documentElement; + if(!this.document) return null; + return this.document.documentElement; }; Contents.prototype.locationOf = function(target, ignoreClass) { - var position; - var targetPos = {"left": 0, "top": 0}; + var position; + var targetPos = {"left": 0, "top": 0}; - if(!this.document) return; + if(!this.document) return; - if(this.epubcfi.isCfiString(target)) { - range = new EpubCFI(target).toRange(this.document, ignoreClass); + if(this.epubcfi.isCfiString(target)) { + range = new EpubCFI(target).toRange(this.document, ignoreClass); - if(range) { - if (range.startContainer.nodeType === Node.ELEMENT_NODE) { - position = range.startContainer.getBoundingClientRect(); - targetPos.left = position.left; - targetPos.top = position.top; - } else { - position = range.getBoundingClientRect(); - targetPos.left = position.left; - targetPos.top = position.top; - } - } + if(range) { + if (range.startContainer.nodeType === Node.ELEMENT_NODE) { + position = range.startContainer.getBoundingClientRect(); + targetPos.left = position.left; + targetPos.top = position.top; + } else { + position = range.getBoundingClientRect(); + targetPos.left = position.left; + targetPos.top = position.top; + } + } - } else if(typeof target === "string" && - target.indexOf("#") > -1) { + } else if(typeof target === "string" && + target.indexOf("#") > -1) { - id = target.substring(target.indexOf("#")+1); - el = this.document.getElementById(id); + id = target.substring(target.indexOf("#")+1); + el = this.document.getElementById(id); - if(el) { - position = el.getBoundingClientRect(); - targetPos.left = position.left; - targetPos.top = position.top; - } - } + if(el) { + position = el.getBoundingClientRect(); + targetPos.left = position.left; + targetPos.top = position.top; + } + } - return targetPos; + return targetPos; }; Contents.prototype.addStylesheet = function(src) { - return new RSVP.Promise(function(resolve, reject){ - var $stylesheet; - var ready = false; + return new RSVP.Promise(function(resolve, reject){ + var $stylesheet; + var ready = false; - if(!this.document) { - resolve(false); - return; - } + if(!this.document) { + resolve(false); + return; + } - $stylesheet = this.document.createElement('link'); - $stylesheet.type = 'text/css'; - $stylesheet.rel = "stylesheet"; - $stylesheet.href = src; - $stylesheet.onload = $stylesheet.onreadystatechange = function() { - if ( !ready && (!this.readyState || this.readyState == 'complete') ) { - ready = true; - // Let apply - setTimeout(function(){ - resolve(true); - }, 1); - } - }; + $stylesheet = this.document.createElement('link'); + $stylesheet.type = 'text/css'; + $stylesheet.rel = "stylesheet"; + $stylesheet.href = src; + $stylesheet.onload = $stylesheet.onreadystatechange = function() { + if ( !ready && (!this.readyState || this.readyState == 'complete') ) { + ready = true; + // Let apply + setTimeout(function(){ + resolve(true); + }, 1); + } + }; - this.document.head.appendChild($stylesheet); + this.document.head.appendChild($stylesheet); - }.bind(this)); + }.bind(this)); }; // https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule Contents.prototype.addStylesheetRules = function(rules) { - var styleEl; - var styleSheet; + var styleEl; + var styleSheet; - if(!this.document) return; + if(!this.document) return; - styleEl = this.document.createElement('style'); + styleEl = this.document.createElement('style'); - // Append style element to head - this.document.head.appendChild(styleEl); + // Append style element to head + this.document.head.appendChild(styleEl); - // Grab style sheet - styleSheet = styleEl.sheet; + // Grab style sheet + styleSheet = styleEl.sheet; - for (var i = 0, rl = rules.length; i < rl; i++) { - var j = 1, rule = rules[i], selector = rules[i][0], propStr = ''; - // If the second argument of a rule is an array of arrays, correct our variables. - if (Object.prototype.toString.call(rule[1][0]) === '[object Array]') { - rule = rule[1]; - j = 0; - } + for (var i = 0, rl = rules.length; i < rl; i++) { + var j = 1, rule = rules[i], selector = rules[i][0], propStr = ''; + // If the second argument of a rule is an array of arrays, correct our variables. + if (Object.prototype.toString.call(rule[1][0]) === '[object Array]') { + rule = rule[1]; + j = 0; + } - for (var pl = rule.length; j < pl; j++) { - var prop = rule[j]; - propStr += prop[0] + ':' + prop[1] + (prop[2] ? ' !important' : '') + ';\n'; - } + for (var pl = rule.length; j < pl; j++) { + var prop = rule[j]; + propStr += prop[0] + ':' + prop[1] + (prop[2] ? ' !important' : '') + ';\n'; + } - // Insert CSS Rule - styleSheet.insertRule(selector + '{' + propStr + '}', styleSheet.cssRules.length); - } + // Insert CSS Rule + styleSheet.insertRule(selector + '{' + propStr + '}', styleSheet.cssRules.length); + } }; Contents.prototype.addScript = function(src) { - return new RSVP.Promise(function(resolve, reject){ - var $script; - var ready = false; + return new RSVP.Promise(function(resolve, reject){ + var $script; + var ready = false; - if(!this.document) { - resolve(false); - return; - } + if(!this.document) { + resolve(false); + return; + } - $script = this.document.createElement('script'); - $script.type = 'text/javascript'; - $script.async = true; - $script.src = src; - $script.onload = $script.onreadystatechange = function() { - if ( !ready && (!this.readyState || this.readyState == 'complete') ) { - ready = true; - setTimeout(function(){ - resolve(true); - }, 1); - } - }; + $script = this.document.createElement('script'); + $script.type = 'text/javascript'; + $script.async = true; + $script.src = src; + $script.onload = $script.onreadystatechange = function() { + if ( !ready && (!this.readyState || this.readyState == 'complete') ) { + ready = true; + setTimeout(function(){ + resolve(true); + }, 1); + } + }; - this.document.head.appendChild($script); + this.document.head.appendChild($script); - }.bind(this)); + }.bind(this)); }; Contents.prototype.addEventListeners = function(){ - if(!this.document) { - return; - } - this.listenedEvents.forEach(function(eventName){ - this.document.addEventListener(eventName, this.triggerEvent.bind(this), false); - }, this); + if(!this.document) { + return; + } + this.listenedEvents.forEach(function(eventName){ + this.document.addEventListener(eventName, this.triggerEvent.bind(this), false); + }, this); }; Contents.prototype.removeEventListeners = function(){ - if(!this.document) { - return; - } - this.listenedEvents.forEach(function(eventName){ - this.document.removeEventListener(eventName, this.triggerEvent, false); - }, this); + if(!this.document) { + return; + } + this.listenedEvents.forEach(function(eventName){ + this.document.removeEventListener(eventName, this.triggerEvent, false); + }, this); }; // Pass browser events Contents.prototype.triggerEvent = function(e){ - this.trigger(e.type, e); + this.trigger(e.type, e); }; Contents.prototype.addSelectionListeners = function(){ - if(!this.document) { - return; - } - this.document.addEventListener("selectionchange", this.onSelectionChange.bind(this), false); + if(!this.document) { + return; + } + this.document.addEventListener("selectionchange", this.onSelectionChange.bind(this), false); }; Contents.prototype.removeSelectionListeners = function(){ - if(!this.document) { - return; - } - this.document.removeEventListener("selectionchange", this.onSelectionChange, false); + if(!this.document) { + return; + } + this.document.removeEventListener("selectionchange", this.onSelectionChange, false); }; Contents.prototype.onSelectionChange = function(e){ - if (this.selectionEndTimeout) { - clearTimeout(this.selectionEndTimeout); - } - this.selectionEndTimeout = setTimeout(function() { - var selection = this.window.getSelection(); - this.triggerSelectedEvent(selection); - }.bind(this), 500); + if (this.selectionEndTimeout) { + clearTimeout(this.selectionEndTimeout); + } + this.selectionEndTimeout = setTimeout(function() { + var selection = this.window.getSelection(); + this.triggerSelectedEvent(selection); + }.bind(this), 500); }; Contents.prototype.triggerSelectedEvent = function(selection){ var range, cfirange; - if (selection && selection.rangeCount > 0) { - range = selection.getRangeAt(0); - if(!range.collapsed) { - // cfirange = this.section.cfiFromRange(range); - cfirange = new EpubCFI(range, this.cfiBase).toString(); - this.trigger("selected", cfirange); - this.trigger("selectedRange", range); - } - } + if (selection && selection.rangeCount > 0) { + range = selection.getRangeAt(0); + if(!range.collapsed) { + // cfirange = this.section.cfiFromRange(range); + cfirange = new EpubCFI(range, this.cfiBase).toString(); + this.trigger("selected", cfirange); + this.trigger("selectedRange", range); + } + } }; Contents.prototype.range = function(_cfi, ignoreClass){ - var cfi = new EpubCFI(_cfi); - return cfi.toRange(this.document, ignoreClass); + var cfi = new EpubCFI(_cfi); + return cfi.toRange(this.document, ignoreClass); }; Contents.prototype.map = function(layout){ - var map = new Mapping(layout); - return map.section(); + var map = new Mapping(layout); + return map.section(); }; Contents.prototype.size = function(width, height){ - if (width >= 0) { - this.width(width); - } + if (width >= 0) { + this.width(width); + } - if (height >= 0) { - this.height(height); - } + if (height >= 0) { + this.height(height); + } - this.css("margin", "0"); - this.css("boxSizing", "border-box"); + this.css("margin", "0"); + this.css("boxSizing", "border-box"); }; Contents.prototype.columns = function(width, height, columnWidth, gap){ - var COLUMN_AXIS = core.prefixed('columnAxis'); - var COLUMN_GAP = core.prefixed('columnGap'); - var COLUMN_WIDTH = core.prefixed('columnWidth'); - var COLUMN_FILL = core.prefixed('columnFill'); - var textWidth; + var COLUMN_AXIS = core.prefixed('columnAxis'); + var COLUMN_GAP = core.prefixed('columnGap'); + var COLUMN_WIDTH = core.prefixed('columnWidth'); + var COLUMN_FILL = core.prefixed('columnFill'); + var textWidth; - this.width(width); - this.height(height); + this.width(width); + this.height(height); - // Deal with Mobile trying to scale to viewport - this.viewport({ width: width, height: height, scale: 1.0 }); + // Deal with Mobile trying to scale to viewport + this.viewport({ width: width, height: height, scale: 1.0 }); - // this.overflowY("hidden"); - this.css("overflowY", "hidden"); - this.css("margin", "0"); - this.css("boxSizing", "border-box"); + // this.overflowY("hidden"); + this.css("overflowY", "hidden"); + this.css("margin", "0"); + this.css("boxSizing", "border-box"); + this.css("maxWidth", "inherit"); - this.css(COLUMN_AXIS, "horizontal"); - this.css(COLUMN_FILL, "auto"); + this.css(COLUMN_AXIS, "horizontal"); + this.css(COLUMN_FILL, "auto"); - this.css(COLUMN_GAP, gap+"px"); - this.css(COLUMN_WIDTH, columnWidth+"px"); + this.css(COLUMN_GAP, gap+"px"); + this.css(COLUMN_WIDTH, columnWidth+"px"); }; Contents.prototype.scale = function(scale, offsetX, offsetY){ - var scale = "scale(" + scale + ")"; - var translate = ''; - // this.css("position", "absolute")); - this.css("transformOrigin", "top left"); + var scale = "scale(" + scale + ")"; + var translate = ''; + // this.css("position", "absolute")); + this.css("transformOrigin", "top left"); - if (offsetX >= 0 || offsetY >= 0) { - translate = " translate(" + (offsetX || 0 )+ "px, " + (offsetY || 0 )+ "px )"; - } + if (offsetX >= 0 || offsetY >= 0) { + translate = " translate(" + (offsetX || 0 )+ "px, " + (offsetY || 0 )+ "px )"; + } - this.css("transform", scale + translate); + this.css("transform", scale + translate); }; Contents.prototype.fit = function(width, height){ - var viewport = this.viewport(); - var widthScale = width / viewport.width; - var heightScale = height / viewport.height; - var scale = widthScale < heightScale ? widthScale : heightScale; + var viewport = this.viewport(); + var widthScale = width / viewport.width; + var heightScale = height / viewport.height; + var scale = widthScale < heightScale ? widthScale : heightScale; - var offsetY = (height - (viewport.height * scale)) / 2; + var offsetY = (height - (viewport.height * scale)) / 2; - this.width(width); - this.height(height); - this.overflow("hidden"); + this.width(width); + this.height(height); + this.overflow("hidden"); - // Deal with Mobile trying to scale to viewport - this.viewport({ scale: 1.0 }); + // Deal with Mobile trying to scale to viewport + this.viewport({ scale: 1.0 }); - // Scale to the correct size - this.scale(scale, 0, offsetY); + // Scale to the correct size + this.scale(scale, 0, offsetY); - this.css("backgroundColor", "transparent"); + this.css("backgroundColor", "transparent"); }; Contents.prototype.mapPage = function(cfiBase, start, end) { - var mapping = new Mapping(); + var mapping = new Mapping(); - return mapping.page(this, cfiBase, start, end); + return mapping.page(this, cfiBase, start, end); }; Contents.prototype.destroy = function() { - // Stop observing - if(this.observer) { - this.observer.disconnect(); - } + // Stop observing + if(this.observer) { + this.observer.disconnect(); + } - this.removeListeners(); + this.removeListeners(); }; @@ -6448,538 +6449,538 @@ var requestAnimationFrame = (typeof window != 'undefined') ? (window.requestAnim /* //-- Parse the different parts of a url, returning a object function uri(url){ - var uri = { - protocol : '', - host : '', - path : '', - origin : '', - directory : '', - base : '', - filename : '', - extension : '', - fragment : '', - href : url - }, - doubleSlash = url.indexOf('://'), - search = url.indexOf('?'), - fragment = url.indexOf("#"), - withoutProtocol, - dot, - firstSlash; + var uri = { + protocol : '', + host : '', + path : '', + origin : '', + directory : '', + base : '', + filename : '', + extension : '', + fragment : '', + href : url + }, + doubleSlash = url.indexOf('://'), + search = url.indexOf('?'), + fragment = url.indexOf("#"), + withoutProtocol, + dot, + firstSlash; - if(fragment != -1) { - uri.fragment = url.slice(fragment + 1); - url = url.slice(0, fragment); - } + if(fragment != -1) { + uri.fragment = url.slice(fragment + 1); + url = url.slice(0, fragment); + } - if(search != -1) { - uri.search = url.slice(search + 1); - url = url.slice(0, search); - href = url; - } + if(search != -1) { + uri.search = url.slice(search + 1); + url = url.slice(0, search); + href = url; + } - if(doubleSlash != -1) { - uri.protocol = url.slice(0, doubleSlash); - withoutProtocol = url.slice(doubleSlash+3); - firstSlash = withoutProtocol.indexOf('/'); + if(doubleSlash != -1) { + uri.protocol = url.slice(0, doubleSlash); + withoutProtocol = url.slice(doubleSlash+3); + firstSlash = withoutProtocol.indexOf('/'); - if(firstSlash === -1) { - uri.host = uri.path; - uri.path = ""; - } else { - uri.host = withoutProtocol.slice(0, firstSlash); - uri.path = withoutProtocol.slice(firstSlash); - } + if(firstSlash === -1) { + uri.host = uri.path; + uri.path = ""; + } else { + uri.host = withoutProtocol.slice(0, firstSlash); + uri.path = withoutProtocol.slice(firstSlash); + } - uri.origin = uri.protocol + "://" + uri.host; + uri.origin = uri.protocol + "://" + uri.host; - uri.directory = folder(uri.path); + uri.directory = folder(uri.path); - uri.base = uri.origin + uri.directory; - // return origin; - } else { - uri.path = url; - uri.directory = folder(url); - uri.base = uri.directory; - } + uri.base = uri.origin + uri.directory; + // return origin; + } else { + uri.path = url; + uri.directory = folder(url); + uri.base = uri.directory; + } - //-- Filename - uri.filename = url.replace(uri.base, ''); - dot = uri.filename.lastIndexOf('.'); - if(dot != -1) { - uri.extension = uri.filename.slice(dot+1); - } - return uri; + //-- Filename + uri.filename = url.replace(uri.base, ''); + dot = uri.filename.lastIndexOf('.'); + if(dot != -1) { + uri.extension = uri.filename.slice(dot+1); + } + return uri; }; //-- Parse out the folder, will return everything before the last slash function folder(url){ - var lastSlash = url.lastIndexOf('/'); + var lastSlash = url.lastIndexOf('/'); - if(lastSlash == -1) var folder = ''; + if(lastSlash == -1) var folder = ''; - folder = url.slice(0, lastSlash + 1); + folder = url.slice(0, lastSlash + 1); - return folder; + return folder; }; */ function isElement(obj) { - return !!(obj && obj.nodeType == 1); + return !!(obj && obj.nodeType == 1); }; // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript function uuid() { - var d = new Date().getTime(); - var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = (d + Math.random()*16)%16 | 0; - d = Math.floor(d/16); - return (c=='x' ? r : (r&0x7|0x8)).toString(16); - }); - return uuid; + var d = new Date().getTime(); + var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = (d + Math.random()*16)%16 | 0; + d = Math.floor(d/16); + return (c=='x' ? r : (r&0x7|0x8)).toString(16); + }); + return uuid; }; // From Lodash function values(object) { - var index = -1, - props = Object.keys(object), - length = props.length, - result = Array(length); + var index = -1, + props = Object.keys(object), + length = props.length, + result = Array(length); - while (++index < length) { - result[index] = object[props[index]]; - } - return result; + while (++index < length) { + result[index] = object[props[index]]; + } + return result; }; function resolveUrl(base, path) { - var url = [], - segments = [], - baseUri = uri(base), - pathUri = uri(path), - baseDirectory = baseUri.directory, - pathDirectory = pathUri.directory, - directories = [], - // folders = base.split("/"), - paths; + var url = [], + segments = [], + baseUri = uri(base), + pathUri = uri(path), + baseDirectory = baseUri.directory, + pathDirectory = pathUri.directory, + directories = [], + // folders = base.split("/"), + paths; - // if(uri.host) { - // return path; - // } + // if(uri.host) { + // return path; + // } - if(baseDirectory[0] === "/") { - baseDirectory = baseDirectory.substring(1); - } + if(baseDirectory[0] === "/") { + baseDirectory = baseDirectory.substring(1); + } - if(pathDirectory[pathDirectory.length-1] === "/") { - baseDirectory = baseDirectory.substring(0, baseDirectory.length-1); - } + if(pathDirectory[pathDirectory.length-1] === "/") { + baseDirectory = baseDirectory.substring(0, baseDirectory.length-1); + } - if(pathDirectory[0] === "/") { - pathDirectory = pathDirectory.substring(1); - } + if(pathDirectory[0] === "/") { + pathDirectory = pathDirectory.substring(1); + } - if(pathDirectory[pathDirectory.length-1] === "/") { - pathDirectory = pathDirectory.substring(0, pathDirectory.length-1); - } + if(pathDirectory[pathDirectory.length-1] === "/") { + pathDirectory = pathDirectory.substring(0, pathDirectory.length-1); + } - if(baseDirectory) { - directories = baseDirectory.split("/"); - } + if(baseDirectory) { + directories = baseDirectory.split("/"); + } - paths = pathDirectory.split("/"); + paths = pathDirectory.split("/"); - paths.reverse().forEach(function(part, index){ - if(part === ".."){ - directories.pop(); - } else if(part === directories[directories.length-1]) { - directories.pop(); - segments.unshift(part); - } else { - segments.unshift(part); - } - }); + paths.reverse().forEach(function(part, index){ + if(part === ".."){ + directories.pop(); + } else if(part === directories[directories.length-1]) { + directories.pop(); + segments.unshift(part); + } else { + segments.unshift(part); + } + }); - url = [baseUri.origin]; + url = [baseUri.origin]; - if(directories.length) { - url = url.concat(directories); - } + if(directories.length) { + url = url.concat(directories); + } - if(segments) { - url = url.concat(segments); - } + if(segments) { + url = url.concat(segments); + } - url = url.concat(pathUri.filename); + url = url.concat(pathUri.filename); - return url.join("/"); + return url.join("/"); }; function documentHeight() { - return Math.max( - document.documentElement.clientHeight, - document.body.scrollHeight, - document.documentElement.scrollHeight, - document.body.offsetHeight, - document.documentElement.offsetHeight - ); + return Math.max( + document.documentElement.clientHeight, + document.body.scrollHeight, + document.documentElement.scrollHeight, + document.body.offsetHeight, + document.documentElement.offsetHeight + ); }; function isNumber(n) { - return !isNaN(parseFloat(n)) && isFinite(n); + return !isNaN(parseFloat(n)) && isFinite(n); }; function prefixed(unprefixed) { - var vendors = ["Webkit", "Moz", "O", "ms" ], - prefixes = ['-Webkit-', '-moz-', '-o-', '-ms-'], - upper = unprefixed[0].toUpperCase() + unprefixed.slice(1), - length = vendors.length; + var vendors = ["Webkit", "Moz", "O", "ms" ], + prefixes = ['-Webkit-', '-moz-', '-o-', '-ms-'], + upper = unprefixed[0].toUpperCase() + unprefixed.slice(1), + length = vendors.length; - if (typeof(document) === 'undefined' || typeof(document.body.style[unprefixed]) != 'undefined') { - return unprefixed; - } + if (typeof(document) === 'undefined' || typeof(document.body.style[unprefixed]) != 'undefined') { + return unprefixed; + } - for ( var i=0; i < length; i++ ) { - if (typeof(document.body.style[vendors[i] + upper]) != 'undefined') { - return vendors[i] + upper; - } - } + for ( var i=0; i < length; i++ ) { + if (typeof(document.body.style[vendors[i] + upper]) != 'undefined') { + return vendors[i] + upper; + } + } - return unprefixed; + return unprefixed; }; function defaults(obj) { - for (var i = 1, length = arguments.length; i < length; i++) { - var source = arguments[i]; - for (var prop in source) { - if (obj[prop] === void 0) obj[prop] = source[prop]; - } - } - return obj; + for (var i = 1, length = arguments.length; i < length; i++) { + var source = arguments[i]; + for (var prop in source) { + if (obj[prop] === void 0) obj[prop] = source[prop]; + } + } + return obj; }; function extend(target) { - var sources = [].slice.call(arguments, 1); - sources.forEach(function (source) { - if(!source) return; - Object.getOwnPropertyNames(source).forEach(function(propName) { - Object.defineProperty(target, propName, Object.getOwnPropertyDescriptor(source, propName)); - }); - }); - return target; + var sources = [].slice.call(arguments, 1); + sources.forEach(function (source) { + if(!source) return; + Object.getOwnPropertyNames(source).forEach(function(propName) { + Object.defineProperty(target, propName, Object.getOwnPropertyDescriptor(source, propName)); + }); + }); + return target; }; // Fast quicksort insert for sorted array -- based on: // http://stackoverflow.com/questions/1344500/efficient-way-to-insert-a-number-into-a-sorted-array-of-numbers function insert(item, array, compareFunction) { - var location = locationOf(item, array, compareFunction); - array.splice(location, 0, item); + var location = locationOf(item, array, compareFunction); + array.splice(location, 0, item); - return location; + return location; }; // Returns where something would fit in function locationOf(item, array, compareFunction, _start, _end) { - var start = _start || 0; - var end = _end || array.length; - var pivot = parseInt(start + (end - start) / 2); - var compared; - if(!compareFunction){ - compareFunction = function(a, b) { - if(a > b) return 1; - if(a < b) return -1; - if(a = b) return 0; - }; - } - if(end-start <= 0) { - return pivot; - } + var start = _start || 0; + var end = _end || array.length; + var pivot = parseInt(start + (end - start) / 2); + var compared; + if(!compareFunction){ + compareFunction = function(a, b) { + if(a > b) return 1; + if(a < b) return -1; + if(a = b) return 0; + }; + } + if(end-start <= 0) { + return pivot; + } - compared = compareFunction(array[pivot], item); - if(end-start === 1) { - return compared > 0 ? pivot : pivot + 1; - } + compared = compareFunction(array[pivot], item); + if(end-start === 1) { + return compared > 0 ? pivot : pivot + 1; + } - if(compared === 0) { - return pivot; - } - if(compared === -1) { - return locationOf(item, array, compareFunction, pivot, end); - } else{ - return locationOf(item, array, compareFunction, start, pivot); - } + if(compared === 0) { + return pivot; + } + if(compared === -1) { + return locationOf(item, array, compareFunction, pivot, end); + } else{ + return locationOf(item, array, compareFunction, start, pivot); + } }; // Returns -1 of mpt found function indexOfSorted(item, array, compareFunction, _start, _end) { - var start = _start || 0; - var end = _end || array.length; - var pivot = parseInt(start + (end - start) / 2); - var compared; - if(!compareFunction){ - compareFunction = function(a, b) { - if(a > b) return 1; - if(a < b) return -1; - if(a = b) return 0; - }; - } - if(end-start <= 0) { - return -1; // Not found - } + var start = _start || 0; + var end = _end || array.length; + var pivot = parseInt(start + (end - start) / 2); + var compared; + if(!compareFunction){ + compareFunction = function(a, b) { + if(a > b) return 1; + if(a < b) return -1; + if(a = b) return 0; + }; + } + if(end-start <= 0) { + return -1; // Not found + } - compared = compareFunction(array[pivot], item); - if(end-start === 1) { - return compared === 0 ? pivot : -1; - } - if(compared === 0) { - return pivot; // Found - } - if(compared === -1) { - return indexOfSorted(item, array, compareFunction, pivot, end); - } else{ - return indexOfSorted(item, array, compareFunction, start, pivot); - } + compared = compareFunction(array[pivot], item); + if(end-start === 1) { + return compared === 0 ? pivot : -1; + } + if(compared === 0) { + return pivot; // Found + } + if(compared === -1) { + return indexOfSorted(item, array, compareFunction, pivot, end); + } else{ + return indexOfSorted(item, array, compareFunction, start, pivot); + } }; function bounds(el) { - var style = window.getComputedStyle(el); - var widthProps = ["width", "paddingRight", "paddingLeft", "marginRight", "marginLeft", "borderRightWidth", "borderLeftWidth"]; - var heightProps = ["height", "paddingTop", "paddingBottom", "marginTop", "marginBottom", "borderTopWidth", "borderBottomWidth"]; + var style = window.getComputedStyle(el); + var widthProps = ["width", "paddingRight", "paddingLeft", "marginRight", "marginLeft", "borderRightWidth", "borderLeftWidth"]; + var heightProps = ["height", "paddingTop", "paddingBottom", "marginTop", "marginBottom", "borderTopWidth", "borderBottomWidth"]; - var width = 0; - var height = 0; + var width = 0; + var height = 0; - widthProps.forEach(function(prop){ - width += parseFloat(style[prop]) || 0; - }); + widthProps.forEach(function(prop){ + width += parseFloat(style[prop]) || 0; + }); - heightProps.forEach(function(prop){ - height += parseFloat(style[prop]) || 0; - }); + heightProps.forEach(function(prop){ + height += parseFloat(style[prop]) || 0; + }); - return { - height: height, - width: width - }; + return { + height: height, + width: width + }; }; function borders(el) { - var style = window.getComputedStyle(el); - var widthProps = ["paddingRight", "paddingLeft", "marginRight", "marginLeft", "borderRightWidth", "borderLeftWidth"]; - var heightProps = ["paddingTop", "paddingBottom", "marginTop", "marginBottom", "borderTopWidth", "borderBottomWidth"]; + var style = window.getComputedStyle(el); + var widthProps = ["paddingRight", "paddingLeft", "marginRight", "marginLeft", "borderRightWidth", "borderLeftWidth"]; + var heightProps = ["paddingTop", "paddingBottom", "marginTop", "marginBottom", "borderTopWidth", "borderBottomWidth"]; - var width = 0; - var height = 0; + var width = 0; + var height = 0; - widthProps.forEach(function(prop){ - width += parseFloat(style[prop]) || 0; - }); + widthProps.forEach(function(prop){ + width += parseFloat(style[prop]) || 0; + }); - heightProps.forEach(function(prop){ - height += parseFloat(style[prop]) || 0; - }); + heightProps.forEach(function(prop){ + height += parseFloat(style[prop]) || 0; + }); - return { - height: height, - width: width - }; + return { + height: height, + width: width + }; }; function windowBounds() { - var width = window.innerWidth; - var height = window.innerHeight; + var width = window.innerWidth; + var height = window.innerHeight; - return { - top: 0, - left: 0, - right: width, - bottom: height, - width: width, - height: height - }; + return { + top: 0, + left: 0, + right: width, + bottom: height, + width: width, + height: height + }; }; //https://stackoverflow.com/questions/13482352/xquery-looking-for-text-with-single-quote/13483496#13483496 function cleanStringForXpath(str) { - var parts = str.match(/[^'"]+|['"]/g); - parts = parts.map(function(part){ - if (part === "'") { - return '\"\'\"'; // output "'" - } + var parts = str.match(/[^'"]+|['"]/g); + parts = parts.map(function(part){ + if (part === "'") { + return '\"\'\"'; // output "'" + } - if (part === '"') { - return "\'\"\'"; // output '"' - } - return "\'" + part + "\'"; - }); - return "concat(\'\'," + parts.join(",") + ")"; + if (part === '"') { + return "\'\"\'"; // output '"' + } + return "\'" + part + "\'"; + }); + return "concat(\'\'," + parts.join(",") + ")"; }; function indexOfTextNode(textNode){ - var parent = textNode.parentNode; - var children = parent.childNodes; - var sib; - var index = -1; - for (var i = 0; i < children.length; i++) { - sib = children[i]; - if(sib.nodeType === Node.TEXT_NODE){ - index++; - } - if(sib == textNode) break; - } + var parent = textNode.parentNode; + var children = parent.childNodes; + var sib; + var index = -1; + for (var i = 0; i < children.length; i++) { + sib = children[i]; + if(sib.nodeType === Node.TEXT_NODE){ + index++; + } + if(sib == textNode) break; + } - return index; + return index; }; function isXml(ext) { - return ['xml', 'opf', 'ncx'].indexOf(ext) > -1; + return ['xml', 'opf', 'ncx'].indexOf(ext) > -1; } function createBlob(content, mime){ var blob = new Blob([content], {type : mime }); - return blob; + return blob; }; function createBlobUrl(content, mime){ - var _URL = window.URL || window.webkitURL || window.mozURL; + var _URL = window.URL || window.webkitURL || window.mozURL; var tempUrl; var blob = this.createBlob(content, mime); - tempUrl = _URL.createObjectURL(blob); + tempUrl = _URL.createObjectURL(blob); - return tempUrl; + return tempUrl; }; function createBase64Url(content, mime){ - var string; - var data; - var datauri; + var string; + var data; + var datauri; - if (typeof(content) !== "string") { - // Only handles strings - return; - } + if (typeof(content) !== "string") { + // Only handles strings + return; + } - data = btoa(content); + data = btoa(content); - datauri = "data:" + mime + ";base64," + data; + datauri = "data:" + mime + ";base64," + data; - return datauri; + return datauri; }; function type(obj){ - return Object.prototype.toString.call(obj).slice(8, -1); + return Object.prototype.toString.call(obj).slice(8, -1); } function parse(markup, mime) { - var doc; - // console.log("parse", markup); + var doc; + // console.log("parse", markup); - if (typeof DOMParser === "undefined") { - DOMParser = require('xmldom').DOMParser; - } + if (typeof DOMParser === "undefined") { + DOMParser = require('xmldom').DOMParser; + } - doc = new DOMParser().parseFromString(markup, mime); + doc = new DOMParser().parseFromString(markup, mime); - return doc; + return doc; } function qs(el, sel) { - var elements; + var elements; - if (typeof el.querySelector != "undefined") { - return el.querySelector(sel); - } else { - elements = el.getElementsByTagName(sel); - if (elements.length) { - return elements[0]; - } - } + if (typeof el.querySelector != "undefined") { + return el.querySelector(sel); + } else { + elements = el.getElementsByTagName(sel); + if (elements.length) { + return elements[0]; + } + } } function qsa(el, sel) { - if (typeof el.querySelector != "undefined") { - return el.querySelectorAll(sel); - } else { - return el.getElementsByTagName(sel); - } + if (typeof el.querySelector != "undefined") { + return el.querySelectorAll(sel); + } else { + return el.getElementsByTagName(sel); + } } function qsp(el, sel, props) { - var q, filtered; - if (typeof el.querySelector != "undefined") { - sel += '['; - for (var prop in props) { - sel += prop + "='" + props[prop] + "'"; - } - sel += ']'; - return el.querySelector(sel); - } else { - q = el.getElementsByTagName(sel); - filtered = Array.prototype.slice.call(q, 0).filter(function(el) { - for (var prop in props) { - if(el.getAttribute(prop) === props[prop]){ - return true; - } - } - return false; - }); + var q, filtered; + if (typeof el.querySelector != "undefined") { + sel += '['; + for (var prop in props) { + sel += prop + "='" + props[prop] + "'"; + } + sel += ']'; + return el.querySelector(sel); + } else { + q = el.getElementsByTagName(sel); + filtered = Array.prototype.slice.call(q, 0).filter(function(el) { + for (var prop in props) { + if(el.getAttribute(prop) === props[prop]){ + return true; + } + } + return false; + }); - if (filtered) { - return filtered[0]; - } - } + if (filtered) { + return filtered[0]; + } + } } function blob2base64(blob, cb) { - var reader = new FileReader(); - reader.readAsDataURL(blob); - reader.onloadend = function() { - cb(reader.result); - } + var reader = new FileReader(); + reader.readAsDataURL(blob); + reader.onloadend = function() { + cb(reader.result); + } } module.exports = { - // 'uri': uri, - // 'folder': folder, - 'isElement': isElement, - 'uuid': uuid, - 'values': values, - 'resolveUrl': resolveUrl, - 'indexOfSorted': indexOfSorted, - 'documentHeight': documentHeight, - 'isNumber': isNumber, - 'prefixed': prefixed, - 'defaults': defaults, - 'extend': extend, - 'insert': insert, - 'locationOf': locationOf, - 'indexOfSorted': indexOfSorted, - 'requestAnimationFrame': requestAnimationFrame, - 'bounds': bounds, - 'borders': borders, - 'windowBounds': windowBounds, - 'cleanStringForXpath': cleanStringForXpath, - 'indexOfTextNode': indexOfTextNode, - 'isXml': isXml, - 'createBlob': createBlob, - 'createBlobUrl': createBlobUrl, - 'type': type, - 'parse' : parse, - 'qs' : qs, - 'qsa' : qsa, - 'qsp' : qsp, - 'blob2base64' : blob2base64, - 'createBase64Url': createBase64Url + // 'uri': uri, + // 'folder': folder, + 'isElement': isElement, + 'uuid': uuid, + 'values': values, + 'resolveUrl': resolveUrl, + 'indexOfSorted': indexOfSorted, + 'documentHeight': documentHeight, + 'isNumber': isNumber, + 'prefixed': prefixed, + 'defaults': defaults, + 'extend': extend, + 'insert': insert, + 'locationOf': locationOf, + 'indexOfSorted': indexOfSorted, + 'requestAnimationFrame': requestAnimationFrame, + 'bounds': bounds, + 'borders': borders, + 'windowBounds': windowBounds, + 'cleanStringForXpath': cleanStringForXpath, + 'indexOfTextNode': indexOfTextNode, + 'isXml': isXml, + 'createBlob': createBlob, + 'createBlobUrl': createBlobUrl, + 'type': type, + 'parse' : parse, + 'qs' : qs, + 'qsa' : qsa, + 'qsp' : qsp, + 'blob2base64' : blob2base64, + 'createBase64Url': createBase64Url }; },{"base64-js":2,"rsvp":5,"xmldom":"xmldom"}],11:[function(require,module,exports){ @@ -6987,730 +6988,730 @@ var URI = require('urijs'); var core = require('./core'); /** - EPUB CFI spec: http://www.idpf.org/epub/linking/cfi/epub-cfi.html + EPUB CFI spec: http://www.idpf.org/epub/linking/cfi/epub-cfi.html - Implements: - - Character Offset: epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3) - - Simple Ranges : epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4) + Implements: + - Character Offset: epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3) + - Simple Ranges : epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4) - Does Not Implement: - - Temporal Offset (~) - - Spatial Offset (@) - - Temporal-Spatial Offset (~ + @) - - Text Location Assertion ([) + Does Not Implement: + - Temporal Offset (~) + - Spatial Offset (@) + - Temporal-Spatial Offset (~ + @) + - Text Location Assertion ([) */ function EpubCFI(cfiFrom, base, ignoreClass){ - var type; + var type; - this.str = ''; + this.str = ''; - this.base = {}; - this.spinePos = 0; // For compatibility + this.base = {}; + this.spinePos = 0; // For compatibility - this.range = false; // true || false; + this.range = false; // true || false; - this.path = {}; - this.start = null; - this.end = null; + this.path = {}; + this.start = null; + this.end = null; - // Allow instantiation without the 'new' keyword - if (!(this instanceof EpubCFI)) { - return new EpubCFI(cfiFrom, base, ignoreClass); - } + // Allow instantiation without the 'new' keyword + if (!(this instanceof EpubCFI)) { + return new EpubCFI(cfiFrom, base, ignoreClass); + } - if(typeof base === 'string') { - this.base = this.parseComponent(base); - } else if(typeof base === 'object' && base.steps) { - this.base = base; - } + if(typeof base === 'string') { + this.base = this.parseComponent(base); + } else if(typeof base === 'object' && base.steps) { + this.base = base; + } - type = this.checkType(cfiFrom); + type = this.checkType(cfiFrom); - if(type === 'string') { - this.str = cfiFrom; - return core.extend(this, this.parse(cfiFrom)); - } else if (type === 'range') { - return core.extend(this, this.fromRange(cfiFrom, this.base, ignoreClass)); - } else if (type === 'node') { - return core.extend(this, this.fromNode(cfiFrom, this.base, ignoreClass)); - } else if (type === 'EpubCFI' && cfiFrom.path) { - return cfiFrom; - } else if (!cfiFrom) { - return this; - } else { - throw new TypeError('not a valid argument for EpubCFI'); - } + if(type === 'string') { + this.str = cfiFrom; + return core.extend(this, this.parse(cfiFrom)); + } else if (type === 'range') { + return core.extend(this, this.fromRange(cfiFrom, this.base, ignoreClass)); + } else if (type === 'node') { + return core.extend(this, this.fromNode(cfiFrom, this.base, ignoreClass)); + } else if (type === 'EpubCFI' && cfiFrom.path) { + return cfiFrom; + } else if (!cfiFrom) { + return this; + } else { + throw new TypeError('not a valid argument for EpubCFI'); + } }; EpubCFI.prototype.checkType = function(cfi) { - if (this.isCfiString(cfi)) { - return 'string'; - // Is a range object - } else if (typeof cfi === 'object' && core.type(cfi) === "Range"){ - return 'range'; - } else if (typeof cfi === 'object' && typeof(cfi.nodeType) != "undefined" ){ // || typeof cfi === 'function' - return 'node'; - } else if (typeof cfi === 'object' && cfi instanceof EpubCFI){ - return 'EpubCFI'; - } else { - return false; - } + if (this.isCfiString(cfi)) { + return 'string'; + // Is a range object + } else if (typeof cfi === 'object' && core.type(cfi) === "Range"){ + return 'range'; + } else if (typeof cfi === 'object' && typeof(cfi.nodeType) != "undefined" ){ // || typeof cfi === 'function' + return 'node'; + } else if (typeof cfi === 'object' && cfi instanceof EpubCFI){ + return 'EpubCFI'; + } else { + return false; + } }; EpubCFI.prototype.parse = function(cfiStr) { - var cfi = { - spinePos: -1, - range: false, - base: {}, - path: {}, - start: null, - end: null - }; - var baseComponent, pathComponent, range; + var cfi = { + spinePos: -1, + range: false, + base: {}, + path: {}, + start: null, + end: null + }; + var baseComponent, pathComponent, range; - if(typeof cfiStr !== "string") { - return {spinePos: -1}; - } + if(typeof cfiStr !== "string") { + return {spinePos: -1}; + } - if(cfiStr.indexOf("epubcfi(") === 0 && cfiStr[cfiStr.length-1] === ")") { - // Remove intial epubcfi( and ending ) - cfiStr = cfiStr.slice(8, cfiStr.length-1); - } + if(cfiStr.indexOf("epubcfi(") === 0 && cfiStr[cfiStr.length-1] === ")") { + // Remove intial epubcfi( and ending ) + cfiStr = cfiStr.slice(8, cfiStr.length-1); + } - baseComponent = this.getChapterComponent(cfiStr); + baseComponent = this.getChapterComponent(cfiStr); - // Make sure this is a valid cfi or return - if(!baseComponent) { - return {spinePos: -1}; - } + // Make sure this is a valid cfi or return + if(!baseComponent) { + return {spinePos: -1}; + } - cfi.base = this.parseComponent(baseComponent); + cfi.base = this.parseComponent(baseComponent); - pathComponent = this.getPathComponent(cfiStr); - cfi.path = this.parseComponent(pathComponent); + pathComponent = this.getPathComponent(cfiStr); + cfi.path = this.parseComponent(pathComponent); - range = this.getRange(cfiStr); + range = this.getRange(cfiStr); - if(range) { - cfi.range = true; - cfi.start = this.parseComponent(range[0]); - cfi.end = this.parseComponent(range[1]); - } + if(range) { + cfi.range = true; + cfi.start = this.parseComponent(range[0]); + cfi.end = this.parseComponent(range[1]); + } - // Get spine node position - // cfi.spineSegment = cfi.base.steps[1]; + // Get spine node position + // cfi.spineSegment = cfi.base.steps[1]; - // Chapter segment is always the second step - cfi.spinePos = cfi.base.steps[1].index; + // Chapter segment is always the second step + cfi.spinePos = cfi.base.steps[1].index; - return cfi; + return cfi; }; EpubCFI.prototype.parseComponent = function(componentStr){ - var component = { - steps: [], - terminal: { - offset: null, - assertion: null - } - }; - var parts = componentStr.split(':'); - var steps = parts[0].split('/'); - var terminal; + var component = { + steps: [], + terminal: { + offset: null, + assertion: null + } + }; + var parts = componentStr.split(':'); + var steps = parts[0].split('/'); + var terminal; - if(parts.length > 1) { - terminal = parts[1]; - component.terminal = this.parseTerminal(terminal); - } + if(parts.length > 1) { + terminal = parts[1]; + component.terminal = this.parseTerminal(terminal); + } - if (steps[0] === '') { - steps.shift(); // Ignore the first slash - } + if (steps[0] === '') { + steps.shift(); // Ignore the first slash + } - component.steps = steps.map(function(step){ - return this.parseStep(step); - }.bind(this)); + component.steps = steps.map(function(step){ + return this.parseStep(step); + }.bind(this)); - return component; + return component; }; EpubCFI.prototype.parseStep = function(stepStr){ - var type, num, index, has_brackets, id; + var type, num, index, has_brackets, id; - has_brackets = stepStr.match(/\[(.*)\]/); - if(has_brackets && has_brackets[1]){ - id = has_brackets[1]; - } + has_brackets = stepStr.match(/\[(.*)\]/); + if(has_brackets && has_brackets[1]){ + id = has_brackets[1]; + } - //-- Check if step is a text node or element - num = parseInt(stepStr); + //-- Check if step is a text node or element + num = parseInt(stepStr); - if(isNaN(num)) { - return; - } + if(isNaN(num)) { + return; + } - if(num % 2 === 0) { // Even = is an element - type = "element"; - index = num / 2 - 1; - } else { - type = "text"; - index = (num - 1 ) / 2; - } + if(num % 2 === 0) { // Even = is an element + type = "element"; + index = num / 2 - 1; + } else { + type = "text"; + index = (num - 1 ) / 2; + } - return { - "type" : type, - 'index' : index, - 'id' : id || null - }; + return { + "type" : type, + 'index' : index, + 'id' : id || null + }; }; EpubCFI.prototype.parseTerminal = function(termialStr){ - var characterOffset, textLocationAssertion; - var assertion = termialStr.match(/\[(.*)\]/); + var characterOffset, textLocationAssertion; + var assertion = termialStr.match(/\[(.*)\]/); - if(assertion && assertion[1]){ - characterOffset = parseInt(termialStr.split('[')[0]) || null; - textLocationAssertion = assertion[1]; - } else { - characterOffset = parseInt(termialStr) || null; - } + if(assertion && assertion[1]){ + characterOffset = parseInt(termialStr.split('[')[0]) || null; + textLocationAssertion = assertion[1]; + } else { + characterOffset = parseInt(termialStr) || null; + } - return { - 'offset': characterOffset, - 'assertion': textLocationAssertion - }; + return { + 'offset': characterOffset, + 'assertion': textLocationAssertion + }; }; EpubCFI.prototype.getChapterComponent = function(cfiStr) { - var indirection = cfiStr.split("!"); + var indirection = cfiStr.split("!"); - return indirection[0]; + return indirection[0]; }; EpubCFI.prototype.getPathComponent = function(cfiStr) { - var indirection = cfiStr.split("!"); + var indirection = cfiStr.split("!"); - if(indirection[1]) { - ranges = indirection[1].split(','); - return ranges[0]; - } + if(indirection[1]) { + ranges = indirection[1].split(','); + return ranges[0]; + } }; EpubCFI.prototype.getRange = function(cfiStr) { - var ranges = cfiStr.split(","); + var ranges = cfiStr.split(","); - if(ranges.length === 3){ - return [ - ranges[1], - ranges[2] - ]; - } + if(ranges.length === 3){ + return [ + ranges[1], + ranges[2] + ]; + } - return false; + return false; }; EpubCFI.prototype.getCharecterOffsetComponent = function(cfiStr) { - var splitStr = cfiStr.split(":"); - return splitStr[1] || ''; + var splitStr = cfiStr.split(":"); + return splitStr[1] || ''; }; EpubCFI.prototype.joinSteps = function(steps) { - if(!steps) { - return ""; - } - - return steps.map(function(part){ - var segment = ''; + if(!steps) { + return ""; + } - if(part.type === 'element') { - segment += (part.index + 1) * 2; - } + return steps.map(function(part){ + var segment = ''; - if(part.type === 'text') { - segment += 1 + (2 * part.index); // TODO: double check that this is odd - } + if(part.type === 'element') { + segment += (part.index + 1) * 2; + } - if(part.id) { - segment += "[" + part.id + "]"; - } + if(part.type === 'text') { + segment += 1 + (2 * part.index); // TODO: double check that this is odd + } - return segment; + if(part.id) { + segment += "[" + part.id + "]"; + } - }).join('/'); + return segment; + + }).join('/'); }; EpubCFI.prototype.segmentString = function(segment) { - var segmentString = '/'; + var segmentString = '/'; - segmentString += this.joinSteps(segment.steps); + segmentString += this.joinSteps(segment.steps); - if(segment.terminal && segment.terminal.offset != null){ - segmentString += ':' + segment.terminal.offset; - } + if(segment.terminal && segment.terminal.offset != null){ + segmentString += ':' + segment.terminal.offset; + } - if(segment.terminal && segment.terminal.assertion != null){ - segmentString += '[' + segment.terminal.assertion + ']'; - } + if(segment.terminal && segment.terminal.assertion != null){ + segmentString += '[' + segment.terminal.assertion + ']'; + } - return segmentString; + return segmentString; }; EpubCFI.prototype.toString = function() { - var cfiString = 'epubcfi('; + var cfiString = 'epubcfi('; - cfiString += this.segmentString(this.base); + cfiString += this.segmentString(this.base); - cfiString += '!'; - cfiString += this.segmentString(this.path); + cfiString += '!'; + cfiString += this.segmentString(this.path); - // Add Range, if present - if(this.start) { - cfiString += ','; - cfiString += this.segmentString(this.start); - } + // Add Range, if present + if(this.start) { + cfiString += ','; + cfiString += this.segmentString(this.start); + } - if(this.end) { - cfiString += ','; - cfiString += this.segmentString(this.end); - } + if(this.end) { + cfiString += ','; + cfiString += this.segmentString(this.end); + } - cfiString += ")"; + cfiString += ")"; - return cfiString; + return cfiString; }; EpubCFI.prototype.compare = function(cfiOne, cfiTwo) { - if(typeof cfiOne === 'string') { - cfiOne = new EpubCFI(cfiOne); - } - if(typeof cfiTwo === 'string') { - cfiTwo = new EpubCFI(cfiTwo); - } - // Compare Spine Positions - if(cfiOne.spinePos > cfiTwo.spinePos) { - return 1; - } - if(cfiOne.spinePos < cfiTwo.spinePos) { - return -1; - } + if(typeof cfiOne === 'string') { + cfiOne = new EpubCFI(cfiOne); + } + if(typeof cfiTwo === 'string') { + cfiTwo = new EpubCFI(cfiTwo); + } + // Compare Spine Positions + if(cfiOne.spinePos > cfiTwo.spinePos) { + return 1; + } + if(cfiOne.spinePos < cfiTwo.spinePos) { + return -1; + } - // Compare Each Step in the First item - for (var i = 0; i < cfiOne.path.steps.length; i++) { - if(!cfiTwo.path.steps[i]) { - return 1; - } - if(cfiOne.path.steps[i].index > cfiTwo.path.steps[i].index) { - return 1; - } - if(cfiOne.path.steps[i].index < cfiTwo.path.steps[i].index) { - return -1; - } - // Otherwise continue checking - } + // Compare Each Step in the First item + for (var i = 0; i < cfiOne.path.steps.length; i++) { + if(!cfiTwo.path.steps[i]) { + return 1; + } + if(cfiOne.path.steps[i].index > cfiTwo.path.steps[i].index) { + return 1; + } + if(cfiOne.path.steps[i].index < cfiTwo.path.steps[i].index) { + return -1; + } + // Otherwise continue checking + } - // All steps in First equal to Second and First is Less Specific - if(cfiOne.path.steps.length < cfiTwo.path.steps.length) { - return 1; - } + // All steps in First equal to Second and First is Less Specific + if(cfiOne.path.steps.length < cfiTwo.path.steps.length) { + return 1; + } - // Compare the charecter offset of the text node - if(cfiOne.path.terminal.offset > cfiTwo.path.terminal.offset) { - return 1; - } - if(cfiOne.path.terminal.offset < cfiTwo.path.terminal.offset) { - return -1; - } + // Compare the charecter offset of the text node + if(cfiOne.path.terminal.offset > cfiTwo.path.terminal.offset) { + return 1; + } + if(cfiOne.path.terminal.offset < cfiTwo.path.terminal.offset) { + return -1; + } - // TODO: compare ranges + // TODO: compare ranges - // CFI's are equal - return 0; + // CFI's are equal + return 0; }; EpubCFI.prototype.step = function(node) { - var nodeType = (node.nodeType === Node.TEXT_NODE) ? 'text' : 'element'; + var nodeType = (node.nodeType === Node.TEXT_NODE) ? 'text' : 'element'; - return { - 'id' : node.id, - 'tagName' : node.tagName, - 'type' : nodeType, - 'index' : this.position(node) - }; + return { + 'id' : node.id, + 'tagName' : node.tagName, + 'type' : nodeType, + 'index' : this.position(node) + }; }; EpubCFI.prototype.filteredStep = function(node, ignoreClass) { - var filteredNode = this.filter(node, ignoreClass); - var nodeType; + var filteredNode = this.filter(node, ignoreClass); + var nodeType; - // Node filtered, so ignore - if (!filteredNode) { - return; - } + // Node filtered, so ignore + if (!filteredNode) { + return; + } - // Otherwise add the filter node in - nodeType = (filteredNode.nodeType === Node.TEXT_NODE) ? 'text' : 'element'; + // Otherwise add the filter node in + nodeType = (filteredNode.nodeType === Node.TEXT_NODE) ? 'text' : 'element'; - return { - 'id' : filteredNode.id, - 'tagName' : filteredNode.tagName, - 'type' : nodeType, - 'index' : this.filteredPosition(filteredNode, ignoreClass) - }; + return { + 'id' : filteredNode.id, + 'tagName' : filteredNode.tagName, + 'type' : nodeType, + 'index' : this.filteredPosition(filteredNode, ignoreClass) + }; }; EpubCFI.prototype.pathTo = function(node, offset, ignoreClass) { - var segment = { - steps: [], - terminal: { - offset: null, - assertion: null - } - }; - var currentNode = node; - var step; + var segment = { + steps: [], + terminal: { + offset: null, + assertion: null + } + }; + var currentNode = node; + var step; - while(currentNode && currentNode.parentNode && - currentNode.parentNode.nodeType != Node.DOCUMENT_NODE) { + while(currentNode && currentNode.parentNode && + currentNode.parentNode.nodeType != Node.DOCUMENT_NODE) { - if (ignoreClass) { - step = this.filteredStep(currentNode, ignoreClass); - } else { - step = this.step(currentNode); - } + if (ignoreClass) { + step = this.filteredStep(currentNode, ignoreClass); + } else { + step = this.step(currentNode); + } - if (step) { - segment.steps.unshift(step); - } + if (step) { + segment.steps.unshift(step); + } - currentNode = currentNode.parentNode; + currentNode = currentNode.parentNode; - } + } - if (offset != null && offset >= 0) { + if (offset != null && offset >= 0) { - segment.terminal.offset = offset; + segment.terminal.offset = offset; - // Make sure we are getting to a textNode if there is an offset - if(segment.steps[segment.steps.length-1].type != "text") { - segment.steps.push({ - 'type' : "text", - 'index' : 0 - }); - } + // Make sure we are getting to a textNode if there is an offset + if(segment.steps[segment.steps.length-1].type != "text") { + segment.steps.push({ + 'type' : "text", + 'index' : 0 + }); + } - } + } - return segment; + return segment; } EpubCFI.prototype.equalStep = function(stepA, stepB) { - if (!stepA || !stepB) { - return false; - } + if (!stepA || !stepB) { + return false; + } - if(stepA.index === stepB.index && - stepA.id === stepB.id && - stepA.type === stepB.type) { - return true; - } + if(stepA.index === stepB.index && + stepA.id === stepB.id && + stepA.type === stepB.type) { + return true; + } - return false; + return false; }; EpubCFI.prototype.fromRange = function(range, base, ignoreClass) { - var cfi = { - range: false, - base: {}, - path: {}, - start: null, - end: null - }; + var cfi = { + range: false, + base: {}, + path: {}, + start: null, + end: null + }; - var start = range.startContainer; - var end = range.endContainer; + var start = range.startContainer; + var end = range.endContainer; - var startOffset = range.startOffset; - var endOffset = range.endOffset; + var startOffset = range.startOffset; + var endOffset = range.endOffset; - var needsIgnoring = false; + var needsIgnoring = false; - if (ignoreClass) { - // Tell pathTo if / what to ignore - needsIgnoring = (start.ownerDocument.querySelector('.' + ignoreClass) != null); - } + if (ignoreClass) { + // Tell pathTo if / what to ignore + needsIgnoring = (start.ownerDocument.querySelector('.' + ignoreClass) != null); + } - if (typeof base === 'string') { - cfi.base = this.parseComponent(base); - cfi.spinePos = cfi.base.steps[1].index; - } else if (typeof base === 'object') { - cfi.base = base; - } + if (typeof base === 'string') { + cfi.base = this.parseComponent(base); + cfi.spinePos = cfi.base.steps[1].index; + } else if (typeof base === 'object') { + cfi.base = base; + } - if (range.collapsed) { - if (needsIgnoring) { - startOffset = this.patchOffset(start, startOffset, ignoreClass); - } - cfi.path = this.pathTo(start, startOffset, ignoreClass); - } else { - cfi.range = true; + if (range.collapsed) { + if (needsIgnoring) { + startOffset = this.patchOffset(start, startOffset, ignoreClass); + } + cfi.path = this.pathTo(start, startOffset, ignoreClass); + } else { + cfi.range = true; - if (needsIgnoring) { - startOffset = this.patchOffset(start, startOffset, ignoreClass); - } + if (needsIgnoring) { + startOffset = this.patchOffset(start, startOffset, ignoreClass); + } - cfi.start = this.pathTo(start, startOffset, ignoreClass); + cfi.start = this.pathTo(start, startOffset, ignoreClass); - if (needsIgnoring) { - endOffset = this.patchOffset(end, endOffset, ignoreClass); - } + if (needsIgnoring) { + endOffset = this.patchOffset(end, endOffset, ignoreClass); + } - cfi.end = this.pathTo(end, endOffset, ignoreClass); + cfi.end = this.pathTo(end, endOffset, ignoreClass); - // Create a new empty path - cfi.path = { - steps: [], - terminal: null - }; + // Create a new empty path + cfi.path = { + steps: [], + terminal: null + }; - // Push steps that are shared between start and end to the common path - var len = cfi.start.steps.length; - var i; + // Push steps that are shared between start and end to the common path + var len = cfi.start.steps.length; + var i; - for (i = 0; i < len; i++) { - if (this.equalStep(cfi.start.steps[i], cfi.end.steps[i])) { - if(i == len-1) { - // Last step is equal, check terminals - if(cfi.start.terminal === cfi.end.terminal) { - // CFI's are equal - cfi.path.steps.push(cfi.start.steps[i]); - // Not a range - cfi.range = false; - } - } else { - cfi.path.steps.push(cfi.start.steps[i]); - } + for (i = 0; i < len; i++) { + if (this.equalStep(cfi.start.steps[i], cfi.end.steps[i])) { + if(i == len-1) { + // Last step is equal, check terminals + if(cfi.start.terminal === cfi.end.terminal) { + // CFI's are equal + cfi.path.steps.push(cfi.start.steps[i]); + // Not a range + cfi.range = false; + } + } else { + cfi.path.steps.push(cfi.start.steps[i]); + } - } else { - break; - } - }; + } else { + break; + } + }; - cfi.start.steps = cfi.start.steps.slice(cfi.path.steps.length); - cfi.end.steps = cfi.end.steps.slice(cfi.path.steps.length); + cfi.start.steps = cfi.start.steps.slice(cfi.path.steps.length); + cfi.end.steps = cfi.end.steps.slice(cfi.path.steps.length); - // TODO: Add Sanity check to make sure that the end if greater than the start - } + // TODO: Add Sanity check to make sure that the end if greater than the start + } - return cfi; + return cfi; } EpubCFI.prototype.fromNode = function(anchor, base, ignoreClass) { - var cfi = { - range: false, - base: {}, - path: {}, - start: null, - end: null - }; + var cfi = { + range: false, + base: {}, + path: {}, + start: null, + end: null + }; - var needsIgnoring = false; + var needsIgnoring = false; - if (ignoreClass) { - // Tell pathTo if / what to ignore - needsIgnoring = (anchor.ownerDocument.querySelector('.' + ignoreClass) != null); - } + if (ignoreClass) { + // Tell pathTo if / what to ignore + needsIgnoring = (anchor.ownerDocument.querySelector('.' + ignoreClass) != null); + } - if (typeof base === 'string') { - cfi.base = this.parseComponent(base); - cfi.spinePos = cfi.base.steps[1].index; - } else if (typeof base === 'object') { - cfi.base = base; - } + if (typeof base === 'string') { + cfi.base = this.parseComponent(base); + cfi.spinePos = cfi.base.steps[1].index; + } else if (typeof base === 'object') { + cfi.base = base; + } - cfi.path = this.pathTo(anchor, null, ignoreClass); + cfi.path = this.pathTo(anchor, null, ignoreClass); - return cfi; + return cfi; }; EpubCFI.prototype.filter = function(anchor, ignoreClass) { - var needsIgnoring; - var sibling; // to join with - var parent, prevSibling, nextSibling; - var isText = false; + var needsIgnoring; + var sibling; // to join with + var parent, prevSibling, nextSibling; + var isText = false; - if (anchor.nodeType === Node.TEXT_NODE) { - isText = true; - parent = anchor.parentNode; - needsIgnoring = anchor.parentNode.classList.contains(ignoreClass); - } else { - isText = false; - needsIgnoring = anchor.classList.contains(ignoreClass); - } + if (anchor.nodeType === Node.TEXT_NODE) { + isText = true; + parent = anchor.parentNode; + needsIgnoring = anchor.parentNode.classList.contains(ignoreClass); + } else { + isText = false; + needsIgnoring = anchor.classList.contains(ignoreClass); + } - if (needsIgnoring && isText) { - previousSibling = parent.previousSibling; - nextSibling = parent.nextSibling; + if (needsIgnoring && isText) { + previousSibling = parent.previousSibling; + nextSibling = parent.nextSibling; - // If the sibling is a text node, join the nodes - if (previousSibling && previousSibling.nodeType === Node.TEXT_NODE) { - sibling = previousSibling; - } else if (nextSibling && nextSibling.nodeType === Node.TEXT_NODE) { - sibling = nextSibling; - } + // If the sibling is a text node, join the nodes + if (previousSibling && previousSibling.nodeType === Node.TEXT_NODE) { + sibling = previousSibling; + } else if (nextSibling && nextSibling.nodeType === Node.TEXT_NODE) { + sibling = nextSibling; + } - if (sibling) { - return sibling; - } else { - // Parent will be ignored on next step - return anchor; - } + if (sibling) { + return sibling; + } else { + // Parent will be ignored on next step + return anchor; + } - } else if (needsIgnoring && !isText) { - // Otherwise just skip the element node - return false; - } else { - // No need to filter - return anchor; - } + } else if (needsIgnoring && !isText) { + // Otherwise just skip the element node + return false; + } else { + // No need to filter + return anchor; + } }; EpubCFI.prototype.patchOffset = function(anchor, offset, ignoreClass) { - var needsIgnoring; - var sibling; + var needsIgnoring; + var sibling; - if (anchor.nodeType != Node.TEXT_NODE) { - console.error("Anchor must be a text node"); - return; - } + if (anchor.nodeType != Node.TEXT_NODE) { + console.error("Anchor must be a text node"); + return; + } - var curr = anchor; - var totalOffset = offset; + var curr = anchor; + var totalOffset = offset; - // If the parent is a ignored node, get offset from it's start - if (anchor.parentNode.classList.contains(ignoreClass)) { - curr = anchor.parentNode; - } + // If the parent is a ignored node, get offset from it's start + if (anchor.parentNode.classList.contains(ignoreClass)) { + curr = anchor.parentNode; + } - while (curr.previousSibling) { - if(curr.previousSibling.nodeType === Node.ELEMENT_NODE) { - // Originally a text node, so join - if(curr.previousSibling.classList.contains(ignoreClass)){ - totalOffset += curr.previousSibling.textContent.length; - } else { - break; // Normal node, dont join - } - } else { - // If the previous sibling is a text node, join the nodes - totalOffset += curr.previousSibling.textContent.length; - } + while (curr.previousSibling) { + if(curr.previousSibling.nodeType === Node.ELEMENT_NODE) { + // Originally a text node, so join + if(curr.previousSibling.classList.contains(ignoreClass)){ + totalOffset += curr.previousSibling.textContent.length; + } else { + break; // Normal node, dont join + } + } else { + // If the previous sibling is a text node, join the nodes + totalOffset += curr.previousSibling.textContent.length; + } - curr = curr.previousSibling; - } + curr = curr.previousSibling; + } - return totalOffset; + return totalOffset; }; EpubCFI.prototype.normalizedMap = function(children, nodeType, ignoreClass) { - var output = {}; - var prevIndex = -1; - var i, len = children.length; - var currNodeType; - var prevNodeType; + var output = {}; + var prevIndex = -1; + var i, len = children.length; + var currNodeType; + var prevNodeType; - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) { - currNodeType = children[i].nodeType; + currNodeType = children[i].nodeType; - // Check if needs ignoring - if (currNodeType === Node.ELEMENT_NODE && - children[i].classList.contains(ignoreClass)) { - currNodeType = Node.TEXT_NODE; - } + // Check if needs ignoring + if (currNodeType === Node.ELEMENT_NODE && + children[i].classList.contains(ignoreClass)) { + currNodeType = Node.TEXT_NODE; + } - if (i > 0 && - currNodeType === Node.TEXT_NODE && - prevNodeType === Node.TEXT_NODE) { - // join text nodes - output[i] = prevIndex; - } else if (nodeType === currNodeType){ - prevIndex = prevIndex + 1; - output[i] = prevIndex; - } + if (i > 0 && + currNodeType === Node.TEXT_NODE && + prevNodeType === Node.TEXT_NODE) { + // join text nodes + output[i] = prevIndex; + } else if (nodeType === currNodeType){ + prevIndex = prevIndex + 1; + output[i] = prevIndex; + } - prevNodeType = currNodeType; + prevNodeType = currNodeType; - } + } - return output; + return output; }; EpubCFI.prototype.position = function(anchor) { - var children, index, map; + var children, index, map; - if (anchor.nodeType === Node.ELEMENT_NODE) { - children = anchor.parentNode.children; - index = Array.prototype.indexOf.call(children, anchor); - } else { - children = this.textNodes(anchor.parentNode); - index = children.indexOf(anchor); - } + if (anchor.nodeType === Node.ELEMENT_NODE) { + children = anchor.parentNode.children; + index = Array.prototype.indexOf.call(children, anchor); + } else { + children = this.textNodes(anchor.parentNode); + index = children.indexOf(anchor); + } - return index; + return index; }; EpubCFI.prototype.filteredPosition = function(anchor, ignoreClass) { - var children, index, map; + var children, index, map; - if (anchor.nodeType === Node.ELEMENT_NODE) { - children = anchor.parentNode.children; - map = this.normalizedMap(children, Node.ELEMENT_NODE, ignoreClass); - } else { - children = anchor.parentNode.childNodes; - // Inside an ignored node - if(anchor.parentNode.classList.contains(ignoreClass)) { - anchor = anchor.parentNode; - children = anchor.parentNode.childNodes; - } - map = this.normalizedMap(children, Node.TEXT_NODE, ignoreClass); - } + if (anchor.nodeType === Node.ELEMENT_NODE) { + children = anchor.parentNode.children; + map = this.normalizedMap(children, Node.ELEMENT_NODE, ignoreClass); + } else { + children = anchor.parentNode.childNodes; + // Inside an ignored node + if(anchor.parentNode.classList.contains(ignoreClass)) { + anchor = anchor.parentNode; + children = anchor.parentNode.childNodes; + } + map = this.normalizedMap(children, Node.TEXT_NODE, ignoreClass); + } - index = Array.prototype.indexOf.call(children, anchor); + index = Array.prototype.indexOf.call(children, anchor); - return map[index]; + return map[index]; }; EpubCFI.prototype.stepsToXpath = function(steps) { - var xpath = [".", "*"]; + var xpath = [".", "*"]; - steps.forEach(function(step){ - var position = step.index + 1; + steps.forEach(function(step){ + var position = step.index + 1; - if(step.id){ - xpath.push("*[position()=" + position + " and @id='" + step.id + "']"); - } else if(step.type === "text") { - xpath.push("text()[" + position + "]"); - } else { - xpath.push("*[" + position + "]"); - } - }); + if(step.id){ + xpath.push("*[position()=" + position + " and @id='" + step.id + "']"); + } else if(step.type === "text") { + xpath.push("text()[" + position + "]"); + } else { + xpath.push("*[" + position + "]"); + } + }); - return xpath.join("/"); + return xpath.join("/"); }; @@ -7726,198 +7727,198 @@ query = this.stepsToQuery(steps); startContainerParent = doc.querySelector(query); // Find the text node within that element if(startContainerParent && lastStep.type == "text") { - container = startContainerParent.childNodes[lastStep.index]; + container = startContainerParent.childNodes[lastStep.index]; } */ EpubCFI.prototype.stepsToQuerySelector = function(steps) { - var query = ["html"]; + var query = ["html"]; - steps.forEach(function(step){ - var position = step.index + 1; + steps.forEach(function(step){ + var position = step.index + 1; - if(step.id){ - query.push("#" + step.id); - } else if(step.type === "text") { - // unsupported in querySelector - // query.push("text()[" + position + "]"); - } else { - query.push("*:nth-child(" + position + ")"); - } - }); + if(step.id){ + query.push("#" + step.id); + } else if(step.type === "text") { + // unsupported in querySelector + // query.push("text()[" + position + "]"); + } else { + query.push("*:nth-child(" + position + ")"); + } + }); - return query.join(">"); + return query.join(">"); }; EpubCFI.prototype.textNodes = function(container, ignoreClass) { - return Array.prototype.slice.call(container.childNodes). - filter(function (node) { - if (node.nodeType === Node.TEXT_NODE) { - return true; - } else if (ignoreClass && node.classList.contains(ignoreClass)) { - return true; - } - return false; - }); + return Array.prototype.slice.call(container.childNodes). + filter(function (node) { + if (node.nodeType === Node.TEXT_NODE) { + return true; + } else if (ignoreClass && node.classList.contains(ignoreClass)) { + return true; + } + return false; + }); }; EpubCFI.prototype.walkToNode = function(steps, _doc, ignoreClass) { - var doc = _doc || document; - var container = doc.documentElement; - var step; - var len = steps.length; - var i; + var doc = _doc || document; + var container = doc.documentElement; + var step; + var len = steps.length; + var i; - for (i = 0; i < len; i++) { - step = steps[i]; + for (i = 0; i < len; i++) { + step = steps[i]; - if(step.type === "element") { - container = container.children[step.index]; - } else if(step.type === "text"){ - container = this.textNodes(container, ignoreClass)[step.index]; - } + if(step.type === "element") { + container = container.children[step.index]; + } else if(step.type === "text"){ + container = this.textNodes(container, ignoreClass)[step.index]; + } - }; + }; - return container; + return container; }; EpubCFI.prototype.findNode = function(steps, _doc, ignoreClass) { - var doc = _doc || document; - var container; - var xpath; + var doc = _doc || document; + var container; + var xpath; - if(!ignoreClass && typeof doc.evaluate != 'undefined') { - xpath = this.stepsToXpath(steps); - container = doc.evaluate(xpath, doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; - } else if(ignoreClass) { - container = this.walkToNode(steps, doc, ignoreClass); - } else { - container = this.walkToNode(steps, doc); - } + if(!ignoreClass && typeof doc.evaluate != 'undefined') { + xpath = this.stepsToXpath(steps); + container = doc.evaluate(xpath, doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; + } else if(ignoreClass) { + container = this.walkToNode(steps, doc, ignoreClass); + } else { + container = this.walkToNode(steps, doc); + } - return container; + return container; }; EpubCFI.prototype.fixMiss = function(steps, offset, _doc, ignoreClass) { - var container = this.findNode(steps.slice(0,-1), _doc, ignoreClass); - var children = container.childNodes; - var map = this.normalizedMap(children, Node.TEXT_NODE, ignoreClass); - var i; - var child; - var len; - var childIndex; - var lastStepIndex = steps[steps.length-1].index; + var container = this.findNode(steps.slice(0,-1), _doc, ignoreClass); + var children = container.childNodes; + var map = this.normalizedMap(children, Node.TEXT_NODE, ignoreClass); + var i; + var child; + var len; + var childIndex; + var lastStepIndex = steps[steps.length-1].index; - for (var childIndex in map) { - if (!map.hasOwnProperty(childIndex)) return; + for (var childIndex in map) { + if (!map.hasOwnProperty(childIndex)) return; - if(map[childIndex] === lastStepIndex) { - child = children[childIndex]; - len = child.textContent.length; - if(offset > len) { - offset = offset - len; - } else { - if (child.nodeType === Node.ELEMENT_NODE) { - container = child.childNodes[0]; - } else { - container = child; - } - break; - } - } - } + if(map[childIndex] === lastStepIndex) { + child = children[childIndex]; + len = child.textContent.length; + if(offset > len) { + offset = offset - len; + } else { + if (child.nodeType === Node.ELEMENT_NODE) { + container = child.childNodes[0]; + } else { + container = child; + } + break; + } + } + } - return { - container: container, - offset: offset - }; + return { + container: container, + offset: offset + }; }; EpubCFI.prototype.toRange = function(_doc, ignoreClass) { - var doc = _doc || document; - var range = doc.createRange(); - var start, end, startContainer, endContainer; - var cfi = this; - var startSteps, endSteps; - var needsIgnoring = ignoreClass ? (doc.querySelector('.' + ignoreClass) != null) : false; - var missed; + var doc = _doc || document; + var range = doc.createRange(); + var start, end, startContainer, endContainer; + var cfi = this; + var startSteps, endSteps; + var needsIgnoring = ignoreClass ? (doc.querySelector('.' + ignoreClass) != null) : false; + var missed; - if (cfi.range) { - start = cfi.start; - startSteps = cfi.path.steps.concat(start.steps); - startContainer = this.findNode(startSteps, doc, needsIgnoring ? ignoreClass : null); - end = cfi.end; - endSteps = cfi.path.steps.concat(end.steps); - endContainer = this.findNode(endSteps, doc, needsIgnoring ? ignoreClass : null); - } else { - start = cfi.path; - startSteps = cfi.path.steps; - startContainer = this.findNode(cfi.path.steps, doc, needsIgnoring ? ignoreClass : null); - } + if (cfi.range) { + start = cfi.start; + startSteps = cfi.path.steps.concat(start.steps); + startContainer = this.findNode(startSteps, doc, needsIgnoring ? ignoreClass : null); + end = cfi.end; + endSteps = cfi.path.steps.concat(end.steps); + endContainer = this.findNode(endSteps, doc, needsIgnoring ? ignoreClass : null); + } else { + start = cfi.path; + startSteps = cfi.path.steps; + startContainer = this.findNode(cfi.path.steps, doc, needsIgnoring ? ignoreClass : null); + } - if(startContainer) { - try { + if(startContainer) { + try { - if(start.terminal.offset != null) { - range.setStart(startContainer, start.terminal.offset); - } else { - range.setStart(startContainer, 0); - } + if(start.terminal.offset != null) { + range.setStart(startContainer, start.terminal.offset); + } else { + range.setStart(startContainer, 0); + } - } catch (e) { - missed = this.fixMiss(startSteps, start.terminal.offset, doc, needsIgnoring ? ignoreClass : null); - range.setStart(missed.container, missed.offset); - } - } else { - // No start found - return null; - } + } catch (e) { + missed = this.fixMiss(startSteps, start.terminal.offset, doc, needsIgnoring ? ignoreClass : null); + range.setStart(missed.container, missed.offset); + } + } else { + // No start found + return null; + } - if (endContainer) { - try { + if (endContainer) { + try { - if(end.terminal.offset != null) { - range.setEnd(endContainer, end.terminal.offset); - } else { - range.setEnd(endContainer, 0); - } + if(end.terminal.offset != null) { + range.setEnd(endContainer, end.terminal.offset); + } else { + range.setEnd(endContainer, 0); + } - } catch (e) { - missed = this.fixMiss(endSteps, cfi.end.terminal.offset, doc, needsIgnoring ? ignoreClass : null); - range.setEnd(missed.container, missed.offset); - } - } + } catch (e) { + missed = this.fixMiss(endSteps, cfi.end.terminal.offset, doc, needsIgnoring ? ignoreClass : null); + range.setEnd(missed.container, missed.offset); + } + } - // doc.defaultView.getSelection().addRange(range); - return range; + // doc.defaultView.getSelection().addRange(range); + return range; }; // is a cfi string, should be wrapped with "epubcfi()" EpubCFI.prototype.isCfiString = function(str) { - if(typeof str === 'string' && - str.indexOf("epubcfi(") === 0 && - str[str.length-1] === ")") { - return true; - } + if(typeof str === 'string' && + str.indexOf("epubcfi(") === 0 && + str[str.length-1] === ")") { + return true; + } - return false; + return false; }; EpubCFI.prototype.generateChapterComponent = function(_spineNodeIndex, _pos, id) { - var pos = parseInt(_pos), - spineNodeIndex = _spineNodeIndex + 1, - cfi = '/'+spineNodeIndex+'/'; + var pos = parseInt(_pos), + spineNodeIndex = _spineNodeIndex + 1, + cfi = '/'+spineNodeIndex+'/'; - cfi += (pos + 1) * 2; + cfi += (pos + 1) * 2; - if(id) { - cfi += "[" + id + "]"; - } + if(id) { + cfi += "[" + id + "]"; + } - return cfi; + return cfi; }; module.exports = EpubCFI; @@ -7934,51 +7935,51 @@ var RSVP = require('rsvp'); // this.content.trigger(args).then(function(){}); function Hook(context){ - this.context = context || this; - this.hooks = []; + this.context = context || this; + this.hooks = []; }; // Adds a function to be run before a hook completes Hook.prototype.register = function(){ - for(var i = 0; i < arguments.length; ++i) { - if (typeof arguments[i] === "function") { - this.hooks.push(arguments[i]); - } else { - // unpack array - for(var j = 0; j < arguments[i].length; ++j) { - this.hooks.push(arguments[i][j]); - } - } - } + for(var i = 0; i < arguments.length; ++i) { + if (typeof arguments[i] === "function") { + this.hooks.push(arguments[i]); + } else { + // unpack array + for(var j = 0; j < arguments[i].length; ++j) { + this.hooks.push(arguments[i][j]); + } + } + } }; // Triggers a hook to run all functions Hook.prototype.trigger = function(){ - var args = arguments; - var context = this.context; - var promises = []; + var args = arguments; + var context = this.context; + var promises = []; - this.hooks.forEach(function(task, i) { - var executing = task.apply(context, args); + this.hooks.forEach(function(task, i) { + var executing = task.apply(context, args); - if(executing && typeof executing["then"] === "function") { - // Task is a function that returns a promise - promises.push(executing); - } - // Otherwise Task resolves immediately, continue - }); + if(executing && typeof executing["then"] === "function") { + // Task is a function that returns a promise + promises.push(executing); + } + // Otherwise Task resolves immediately, continue + }); - return RSVP.all(promises); + return RSVP.all(promises); }; // Adds a function to be run before a hook completes Hook.prototype.list = function(){ - return this.hooks; + return this.hooks; }; Hook.prototype.clear = function(){ - return this.hooks = []; + return this.hooks = []; }; module.exports = Hook; @@ -7988,120 +7989,120 @@ var core = require('./core'); var RSVP = require('rsvp'); function Layout(settings){ - this.name = settings.layout || "reflowable"; - this._spread = (settings.spread === "none") ? false : true; - this._minSpreadWidth = settings.spread || 800; - this._evenSpreads = settings.evenSpreads || false; + this.name = settings.layout || "reflowable"; + this._spread = (settings.spread === "none") ? false : true; + this._minSpreadWidth = settings.spread || 800; + this._evenSpreads = settings.evenSpreads || false; - if (settings.flow === "scrolled-continuous" || - settings.flow === "scrolled-doc") { - this._flow = "scrolled"; - } else { - this._flow = "paginated"; - } + if (settings.flow === "scrolled-continuous" || + settings.flow === "scrolled-doc") { + this._flow = "scrolled"; + } else { + this._flow = "paginated"; + } - this.width = 0; - this.height = 0; - this.spreadWidth = 0; - this.delta = 0; + this.width = 0; + this.height = 0; + this.spreadWidth = 0; + this.delta = 0; - this.columnWidth = 0; - this.gap = 0; - this.divisor = 1; + this.columnWidth = 0; + this.gap = 0; + this.divisor = 1; }; // paginated | scrolled Layout.prototype.flow = function(flow) { - this._flow = (flow === "paginated") ? "paginated" : "scrolled"; + this._flow = (flow === "paginated") ? "paginated" : "scrolled"; } // true | false Layout.prototype.spread = function(spread, min) { - this._spread = (spread === "none") ? false : true; + this._spread = (spread === "none") ? false : true; - if (min >= 0) { - this._minSpreadWidth = min; - } + if (min >= 0) { + this._minSpreadWidth = min; + } } Layout.prototype.calculate = function(_width, _height, _gap){ - var divisor = 1; - var gap = _gap || 0; + var divisor = 1; + var gap = _gap || 0; - //-- Check the width and create even width columns - var fullWidth = Math.floor(_width); - var width = _width; + //-- Check the width and create even width columns + var fullWidth = Math.floor(_width); + var width = _width; - var section = Math.floor(width / 8); + var section = Math.floor(width / 8); - var colWidth; - var spreadWidth; - var delta; + var colWidth; + var spreadWidth; + var delta; - if (this._spread && width >= this._minSpreadWidth) { - divisor = 2; - } else { - divisor = 1; - } + if (this._spread && width >= this._minSpreadWidth) { + divisor = 2; + } else { + divisor = 1; + } - if (this.name === "reflowable" && this._flow === "paginated" && !(_gap >= 0)) { - gap = ((section % 2 === 0) ? section : section - 1); - } + if (this.name === "reflowable" && this._flow === "paginated" && !(_gap >= 0)) { + gap = ((section % 2 === 0) ? section : section - 1); + } - if (this.name === "pre-paginated" ) { - gap = 0; - } + if (this.name === "pre-paginated" ) { + gap = 0; + } - //-- Double Page - if(divisor > 1) { - colWidth = Math.floor((width - gap) / divisor); - } else { - colWidth = width; - } + //-- Double Page + if(divisor > 1) { + colWidth = Math.floor((width - gap) / divisor); + } else { + colWidth = width; + } - if (this.name === "pre-paginated" && divisor > 1) { - width = colWidth; - } + if (this.name === "pre-paginated" && divisor > 1) { + width = colWidth; + } - spreadWidth = colWidth * divisor; + spreadWidth = colWidth * divisor; - delta = (colWidth + gap) * divisor; + delta = (colWidth + gap) * divisor; - this.width = width; - this.height = _height; - this.spreadWidth = spreadWidth; - this.delta = delta; + this.width = width; + this.height = _height; + this.spreadWidth = spreadWidth; + this.delta = delta; - this.columnWidth = colWidth; - this.gap = gap; - this.divisor = divisor; + this.columnWidth = colWidth; + this.gap = gap; + this.divisor = divisor; }; Layout.prototype.format = function(contents){ - var formating; + var formating; - if (this.name === "pre-paginated") { - formating = contents.fit(this.columnWidth, this.height); - } else if (this._flow === "paginated") { - formating = contents.columns(this.width, this.height, this.columnWidth, this.gap); - } else { // scrolled - formating = contents.size(this.width, null); - } + if (this.name === "pre-paginated") { + formating = contents.fit(this.columnWidth, this.height); + } else if (this._flow === "paginated") { + formating = contents.columns(this.width, this.height, this.columnWidth, this.gap); + } else { // scrolled + formating = contents.size(this.width, null); + } - return formating; // might be a promise in some View Managers + return formating; // might be a promise in some View Managers }; Layout.prototype.count = function(totalWidth) { - // var totalWidth = contents.scrollWidth(); - var spreads = Math.ceil( totalWidth / this.spreadWidth); + // var totalWidth = contents.scrollWidth(); + var spreads = Math.ceil( totalWidth / this.spreadWidth); - return { - spreads : spreads, - pages : spreads * this.divisor - }; + return { + spreads : spreads, + pages : spreads * this.divisor + }; }; module.exports = Layout; @@ -8113,114 +8114,114 @@ var EpubCFI = require('./epubcfi'); var RSVP = require('rsvp'); function Locations(spine, request) { - this.spine = spine; - this.request = request; + this.spine = spine; + this.request = request; - this.q = new Queue(this); - this.epubcfi = new EpubCFI(); + this.q = new Queue(this); + this.epubcfi = new EpubCFI(); - this._locations = []; - this.total = 0; + this._locations = []; + this.total = 0; - this.break = 150; + this.break = 150; - this._current = 0; + this._current = 0; }; // Load all of sections in the book Locations.prototype.generate = function(chars) { - if (chars) { - this.break = chars; - } + if (chars) { + this.break = chars; + } - this.q.pause(); + this.q.pause(); - this.spine.each(function(section) { + this.spine.each(function(section) { - this.q.enqueue(this.process, section); + this.q.enqueue(this.process, section); - }.bind(this)); + }.bind(this)); - return this.q.run().then(function() { - this.total = this._locations.length-1; + return this.q.run().then(function() { + this.total = this._locations.length-1; - if (this._currentCfi) { - this.currentLocation = this._currentCfi; - } + if (this._currentCfi) { + this.currentLocation = this._currentCfi; + } - return this._locations; - // console.log(this.precentage(this.book.rendition.location.start), this.precentage(this.book.rendition.location.end)); - }.bind(this)); + return this._locations; + // console.log(this.precentage(this.book.rendition.location.start), this.precentage(this.book.rendition.location.end)); + }.bind(this)); }; Locations.prototype.process = function(section) { - return section.load(this.request) - .then(function(contents) { + return section.load(this.request) + .then(function(contents) { - var range; - var doc = contents.ownerDocument; - var counter = 0; + var range; + var doc = contents.ownerDocument; + var counter = 0; - this.sprint(contents, function(node) { - var len = node.length; - var dist; - var pos = 0; + this.sprint(contents, function(node) { + var len = node.length; + var dist; + var pos = 0; - // Start range - if (counter == 0) { - range = doc.createRange(); - range.setStart(node, 0); - } + // Start range + if (counter == 0) { + range = doc.createRange(); + range.setStart(node, 0); + } - dist = this.break - counter; + dist = this.break - counter; - // Node is smaller than a break - if(dist > len){ - counter += len; - pos = len; - } + // Node is smaller than a break + if(dist > len){ + counter += len; + pos = len; + } - while (pos < len) { - counter = this.break; - pos += this.break; + while (pos < len) { + counter = this.break; + pos += this.break; - // Gone over - if(pos >= len){ - // Continue counter for next node - counter = len - (pos - this.break); + // Gone over + if(pos >= len){ + // Continue counter for next node + counter = len - (pos - this.break); - // At End - } else { - // End the previous range - range.setEnd(node, pos); - cfi = section.cfiFromRange(range); - this._locations.push(cfi); - counter = 0; + // At End + } else { + // End the previous range + range.setEnd(node, pos); + cfi = section.cfiFromRange(range); + this._locations.push(cfi); + counter = 0; - // Start new range - pos += 1; - range = doc.createRange(); - range.setStart(node, pos); - } - } + // Start new range + pos += 1; + range = doc.createRange(); + range.setStart(node, pos); + } + } - }.bind(this)); + }.bind(this)); - // Close remaining - if (range) { - range.setEnd(prev, prev.length); - cfi = section.cfiFromRange(range); - this._locations.push(cfi) - counter = 0; - } + // Close remaining + if (range) { + range.setEnd(prev, prev.length); + cfi = section.cfiFromRange(range); + this._locations.push(cfi) + counter = 0; + } - }.bind(this)); + }.bind(this)); }; @@ -8234,26 +8235,26 @@ Locations.prototype.sprint = function(root, func) { }; Locations.prototype.locationFromCfi = function(cfi){ - // Check if the location has not been set yet + // Check if the location has not been set yet if(this._locations.length === 0) { return -1; } - return core.locationOf(cfi, this._locations, this.epubcfi.compare); + return core.locationOf(cfi, this._locations, this.epubcfi.compare); }; Locations.prototype.precentageFromCfi = function(cfi) { - // Find closest cfi - var loc = this.locationFromCfi(cfi); - // Get percentage in total - return this.precentageFromLocation(loc); + // Find closest cfi + var loc = this.locationFromCfi(cfi); + // Get percentage in total + return this.precentageFromLocation(loc); }; Locations.prototype.percentageFromLocation = function(loc) { - if (!loc || !this.total) { - return 0; - } - return (loc / this.total); + if (!loc || !this.total) { + return 0; + } + return (loc / this.total); }; Locations.prototype.cfiFromLocation = function(loc){ @@ -8271,7 +8272,7 @@ Locations.prototype.cfiFromLocation = function(loc){ }; Locations.prototype.cfiFromPercentage = function(value){ - var percentage = (value > 1) ? value / 100 : value; // Normalize value to 0-1 + var percentage = (value > 1) ? value / 100 : value; // Normalize value to 0-1 var loc = Math.ceil(this.total * percentage); return this.cfiFromLocation(loc); @@ -8279,8 +8280,8 @@ Locations.prototype.cfiFromPercentage = function(value){ Locations.prototype.load = function(locations){ this._locations = JSON.parse(locations); - this.total = this._locations.length-1; - return this._locations; + this.total = this._locations.length-1; + return this._locations; }; Locations.prototype.save = function(json){ @@ -8292,39 +8293,39 @@ Locations.prototype.getCurrent = function(json){ }; Locations.prototype.setCurrent = function(curr){ - var loc; + var loc; - if(typeof curr == "string"){ - this._currentCfi = curr; - } else if (typeof curr == "number") { - this._current = curr; - } else { - return; - } - - if(this._locations.length === 0) { - return; + if(typeof curr == "string"){ + this._currentCfi = curr; + } else if (typeof curr == "number") { + this._current = curr; + } else { + return; } - if(typeof curr == "string"){ - loc = this.locationFromCfi(curr); - this._current = loc; - } else { - loc = curr; - } + if(this._locations.length === 0) { + return; + } - this.trigger("changed", { - percentage: this.precentageFromLocation(loc) - }); + if(typeof curr == "string"){ + loc = this.locationFromCfi(curr); + this._current = loc; + } else { + loc = curr; + } + + this.trigger("changed", { + percentage: this.precentageFromLocation(loc) + }); }; Object.defineProperty(Locations.prototype, 'currentLocation', { - get: function () { - return this._current; - }, - set: function (curr) { - this.setCurrent(curr); - } + get: function () { + return this._current; + }, + set: function (curr) { + this.setCurrent(curr); + } }); RSVP.EventTarget.mixin(Locations.prototype); @@ -8355,9 +8356,9 @@ function ContinuousViewManager(options) { core.extend(this.settings, options.settings || {}); // Gap can be 0, byt defaults doesn't handle that - if (options.settings.gap != "undefined" && options.settings.gap === 0) { - this.settings.gap = options.settings.gap; - } + if (options.settings.gap != "undefined" && options.settings.gap === 0) { + this.settings.gap = options.settings.gap; + } // this.viewSettings.axis = this.settings.axis; this.viewSettings = { @@ -8377,7 +8378,7 @@ ContinuousViewManager.prototype = Object.create(SingleViewManager.prototype); ContinuousViewManager.prototype.constructor = ContinuousViewManager; ContinuousViewManager.prototype.display = function(section, target){ - return SingleViewManager.prototype.display.call(this, section, target) + return SingleViewManager.prototype.display.call(this, section, target) .then(function () { return this.fill(); }.bind(this)); @@ -8398,8 +8399,8 @@ ContinuousViewManager.prototype.fill = function(_full){ } ContinuousViewManager.prototype.moveTo = function(offset){ - // var bounds = this.stage.bounds(); - // var dist = Math.floor(offset.top / bounds.height) * bounds.height; + // var bounds = this.stage.bounds(); + // var dist = Math.floor(offset.top / bounds.height) * bounds.height; var distX = 0, distY = 0; @@ -8414,10 +8415,10 @@ ContinuousViewManager.prototype.moveTo = function(offset){ offsetX = distX+this.settings.offset; } - return this.check(offsetX, offsetY) + return this.check(offsetX, offsetY) .then(function(){ - this.scrollBy(distX, distY); - }.bind(this)); + this.scrollBy(distX, distY); + }.bind(this)); }; /* @@ -8447,7 +8448,7 @@ ContinuousViewManager.prototype.afterDisplayed = function(currView){ ContinuousViewManager.prototype.resize = function(width, height){ // Clear the queue - this.q.clear(); + this.q.clear(); this._stageSize = this.stage.size(width, height); this._bounds = this.bounds(); @@ -8461,27 +8462,27 @@ ContinuousViewManager.prototype.resize = function(width, height){ view.size(this._stageSize.width, this._stageSize.height); }.bind(this)); - this.updateLayout(); + this.updateLayout(); - // if(this.location) { - // this.rendition.display(this.location.start); - // } + // if(this.location) { + // this.rendition.display(this.location.start); + // } - this.trigger("resized", { - width: this.stage.width, - height: this.stage.height - }); + this.trigger("resized", { + width: this.stage.width, + height: this.stage.height + }); }; ContinuousViewManager.prototype.onResized = function(e) { - // this.views.clear(); + // this.views.clear(); - clearTimeout(this.resizeTimeout); - this.resizeTimeout = setTimeout(function(){ - this.resize(); - }.bind(this), 150); + clearTimeout(this.resizeTimeout); + this.resizeTimeout = setTimeout(function(){ + this.resize(); + }.bind(this), 150); }; ContinuousViewManager.prototype.afterResized = function(view){ @@ -8554,34 +8555,34 @@ ContinuousViewManager.prototype.update = function(_offset){ var promises = []; for (var i = 0; i < viewsLength; i++) { - view = views[i]; + view = views[i]; - isVisible = this.isVisible(view, offset, offset, container); + isVisible = this.isVisible(view, offset, offset, container); - if(isVisible === true) { + if(isVisible === true) { if (!view.displayed) { promises.push(view.display(this.request).then(function (view) { view.show(); })); } - visible.push(view); - } else { + visible.push(view); + } else { this.q.enqueue(view.destroy.bind(view)); clearTimeout(this.trimTimeout); this.trimTimeout = setTimeout(function(){ this.q.enqueue(this.trim.bind(this)); }.bind(this), 250); - } + } - } + } if(promises.length){ - return RSVP.all(promises); - } else { - updating.resolve(); - return updating.promise; - } + return RSVP.all(promises); + } else { + updating.resolve(); + return updating.promise; + } }; @@ -8610,61 +8611,61 @@ ContinuousViewManager.prototype.check = function(_offsetLeft, _offsetTop){ if (offset + visibleLength + delta >= contentLength) { last = this.views.last(); - next = last && last.section.next(); - if(next) { - newViews.push(this.append(next)); - } - } + next = last && last.section.next(); + if(next) { + newViews.push(this.append(next)); + } + } - if (offset - delta < 0 ) { + if (offset - delta < 0 ) { first = this.views.first(); - prev = first && first.section.prev(); - if(prev) { - newViews.push(this.prepend(prev)); - } - } + prev = first && first.section.prev(); + if(prev) { + newViews.push(this.prepend(prev)); + } + } - if(newViews.length){ - // RSVP.all(promises) - // .then(function() { - // Check to see if anything new is on screen after rendering - return this.q.enqueue(function(){ + if(newViews.length){ + // RSVP.all(promises) + // .then(function() { + // Check to see if anything new is on screen after rendering + return this.q.enqueue(function(){ return this.update(delta); }.bind(this)); - // }.bind(this)); + // }.bind(this)); - } else { - checking.resolve(false); + } else { + checking.resolve(false); return checking.promise; - } + } }; ContinuousViewManager.prototype.trim = function(){ - var task = new RSVP.defer(); - var displayed = this.views.displayed(); - var first = displayed[0]; - var last = displayed[displayed.length-1]; - var firstIndex = this.views.indexOf(first); - var lastIndex = this.views.indexOf(last); - var above = this.views.slice(0, firstIndex); - var below = this.views.slice(lastIndex+1); + var task = new RSVP.defer(); + var displayed = this.views.displayed(); + var first = displayed[0]; + var last = displayed[displayed.length-1]; + var firstIndex = this.views.indexOf(first); + var lastIndex = this.views.indexOf(last); + var above = this.views.slice(0, firstIndex); + var below = this.views.slice(lastIndex+1); - // Erase all but last above - for (var i = 0; i < above.length-1; i++) { - this.erase(above[i], above); - } + // Erase all but last above + for (var i = 0; i < above.length-1; i++) { + this.erase(above[i], above); + } - // Erase all except first below - for (var j = 1; j < below.length; j++) { - this.erase(below[j]); - } + // Erase all except first below + for (var j = 1; j < below.length; j++) { + this.erase(below[j]); + } - task.resolve(); - return task.promise; + task.resolve(); + return task.promise; }; ContinuousViewManager.prototype.erase = function(view, above){ //Trim @@ -8673,12 +8674,12 @@ ContinuousViewManager.prototype.erase = function(view, above){ //Trim var prevLeft; if(this.settings.height) { - prevTop = this.container.scrollTop; + prevTop = this.container.scrollTop; prevLeft = this.container.scrollLeft; - } else { - prevTop = window.scrollY; + } else { + prevTop = window.scrollY; prevLeft = window.scrollX; - } + } var bounds = view.bounds(); @@ -8707,60 +8708,60 @@ ContinuousViewManager.prototype.addEventListeners = function(stage){ }; ContinuousViewManager.prototype.addScrollListeners = function() { - var scroller; + var scroller; - this.tick = core.requestAnimationFrame; + this.tick = core.requestAnimationFrame; - if(this.settings.height) { - this.prevScrollTop = this.container.scrollTop; - this.prevScrollLeft = this.container.scrollLeft; - } else { - this.prevScrollTop = window.scrollY; + if(this.settings.height) { + this.prevScrollTop = this.container.scrollTop; + this.prevScrollLeft = this.container.scrollLeft; + } else { + this.prevScrollTop = window.scrollY; this.prevScrollLeft = window.scrollX; - } + } - this.scrollDeltaVert = 0; - this.scrollDeltaHorz = 0; + this.scrollDeltaVert = 0; + this.scrollDeltaHorz = 0; - if(this.settings.height) { - scroller = this.container; + if(this.settings.height) { + scroller = this.container; this.scrollTop = this.container.scrollTop; this.scrollLeft = this.container.scrollLeft; - } else { - scroller = window; + } else { + scroller = window; this.scrollTop = window.scrollY; this.scrollLeft = window.scrollX; - } + } - scroller.addEventListener("scroll", this.onScroll.bind(this)); + scroller.addEventListener("scroll", this.onScroll.bind(this)); - // this.tick.call(window, this.onScroll.bind(this)); + // this.tick.call(window, this.onScroll.bind(this)); - this.scrolled = false; + this.scrolled = false; }; ContinuousViewManager.prototype.onScroll = function(){ - // if(!this.ignore) { + // if(!this.ignore) { - if(this.settings.height) { - scrollTop = this.container.scrollTop; - scrollLeft = this.container.scrollLeft; - } else { - scrollTop = window.scrollY; + if(this.settings.height) { + scrollTop = this.container.scrollTop; + scrollLeft = this.container.scrollLeft; + } else { + scrollTop = window.scrollY; scrollLeft = window.scrollX; - } + } this.scrollTop = scrollTop; this.scrollLeft = scrollLeft; - if(!this.ignore) { + if(!this.ignore) { - if((this.scrollDeltaVert === 0 && - this.scrollDeltaHorz === 0) || - this.scrollDeltaVert > this.settings.offsetDelta || - this.scrollDeltaHorz > this.settings.offsetDelta) { + if((this.scrollDeltaVert === 0 && + this.scrollDeltaHorz === 0) || + this.scrollDeltaVert > this.settings.offsetDelta || + this.scrollDeltaHorz > this.settings.offsetDelta) { this.q.enqueue(function() { this.check(); @@ -8768,44 +8769,44 @@ ContinuousViewManager.prototype.onScroll = function(){ // this.check(); this.scrollDeltaVert = 0; - this.scrollDeltaHorz = 0; + this.scrollDeltaHorz = 0; this.trigger("scroll", { - top: scrollTop, - left: scrollLeft - }); + top: scrollTop, + left: scrollLeft + }); clearTimeout(this.afterScrolled); this.afterScrolled = setTimeout(function () { this.trigger("scrolled", { - top: this.scrollTop, - left: this.scrollLeft - }); + top: this.scrollTop, + left: this.scrollLeft + }); }.bind(this)); } } else { - this.ignore = false; + this.ignore = false; } - this.scrollDeltaVert += Math.abs(scrollTop-this.prevScrollTop); - this.scrollDeltaHorz += Math.abs(scrollLeft-this.prevScrollLeft); + this.scrollDeltaVert += Math.abs(scrollTop-this.prevScrollTop); + this.scrollDeltaHorz += Math.abs(scrollLeft-this.prevScrollLeft); this.prevScrollTop = scrollTop; this.prevScrollLeft = scrollLeft; - clearTimeout(this.scrollTimeout); + clearTimeout(this.scrollTimeout); this.scrollTimeout = setTimeout(function(){ this.scrollDeltaVert = 0; - this.scrollDeltaHorz = 0; + this.scrollDeltaHorz = 0; }.bind(this), 150); - this.scrolled = false; - // } + this.scrolled = false; + // } - // this.tick.call(window, this.onScroll.bind(this)); + // this.tick.call(window, this.onScroll.bind(this)); }; @@ -8822,9 +8823,9 @@ ContinuousViewManager.prototype.onScroll = function(){ ContinuousViewManager.prototype.currentLocation = function(){ - if (this.settings.axis === "vertical") { - this.location = this.scrolledLocation(); - } else { + if (this.settings.axis === "vertical") { + this.location = this.scrolledLocation(); + } else { this.location = this.paginatedLocation(); } @@ -8833,104 +8834,104 @@ ContinuousViewManager.prototype.currentLocation = function(){ ContinuousViewManager.prototype.scrolledLocation = function(){ - var visible = this.visible(); - var startPage, endPage; + var visible = this.visible(); + var startPage, endPage; - var container = this.container.getBoundingClientRect(); + var container = this.container.getBoundingClientRect(); - if(visible.length === 1) { - return this.mapping.page(visible[0].contents, visible[0].section.cfiBase); - } + if(visible.length === 1) { + return this.mapping.page(visible[0].contents, visible[0].section.cfiBase); + } - if(visible.length > 1) { + if(visible.length > 1) { - startPage = this.mapping.page(visible[0].contents, visible[0].section.cfiBase); - endPage = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase); + startPage = this.mapping.page(visible[0].contents, visible[0].section.cfiBase); + endPage = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase); - return { - start: startPage.start, - end: endPage.end - }; - } + return { + start: startPage.start, + end: endPage.end + }; + } }; ContinuousViewManager.prototype.paginatedLocation = function(){ - var visible = this.visible(); - var startA, startB, endA, endB; - var pageLeft, pageRight; - var container = this.container.getBoundingClientRect(); + var visible = this.visible(); + var startA, startB, endA, endB; + var pageLeft, pageRight; + var container = this.container.getBoundingClientRect(); - if(visible.length === 1) { - startA = container.left - visible[0].position().left; - endA = startA + this.layout.spreadWidth; + if(visible.length === 1) { + startA = container.left - visible[0].position().left; + endA = startA + this.layout.spreadWidth; - return this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA); - } + return this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA); + } - if(visible.length > 1) { + if(visible.length > 1) { - // Left Col - startA = container.left - visible[0].position().left; - endA = startA + this.layout.columnWidth; + // Left Col + startA = container.left - visible[0].position().left; + endA = startA + this.layout.columnWidth; - // Right Col - startB = container.left + this.layout.spreadWidth - visible[visible.length-1].position().left; - endB = startB + this.layout.columnWidth; + // Right Col + startB = container.left + this.layout.spreadWidth - visible[visible.length-1].position().left; + endB = startB + this.layout.columnWidth; - pageLeft = this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA); - pageRight = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase, startB, endB); + pageLeft = this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA); + pageRight = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase, startB, endB); - return { - start: pageLeft.start, - end: pageRight.end - }; - } + return { + start: pageLeft.start, + end: pageRight.end + }; + } }; /* Continuous.prototype.current = function(what){ - var view, top; - var container = this.container.getBoundingClientRect(); - var length = this.views.length - 1; + var view, top; + var container = this.container.getBoundingClientRect(); + var length = this.views.length - 1; - if(this.settings.axis === "horizontal") { + if(this.settings.axis === "horizontal") { - for (var i = length; i >= 0; i--) { - view = this.views[i]; - left = view.position().left; + for (var i = length; i >= 0; i--) { + view = this.views[i]; + left = view.position().left; - if(left < container.right) { + if(left < container.right) { - if(this._current == view) { - break; - } + if(this._current == view) { + break; + } - this._current = view; - break; - } - } + this._current = view; + break; + } + } - } else { + } else { - for (var i = length; i >= 0; i--) { - view = this.views[i]; - top = view.bounds().top; - if(top < container.bottom) { + for (var i = length; i >= 0; i--) { + view = this.views[i]; + top = view.bounds().top; + if(top < container.bottom) { - if(this._current == view) { - break; - } + if(this._current == view) { + break; + } - this._current = view; + this._current = view; - break; - } - } + break; + } + } - } + } - return this._current; + return this._current; }; */ @@ -8960,7 +8961,7 @@ ContinuousViewManager.prototype.updateLayout = function() { this.viewSettings.width = this.layout.width; this.viewSettings.height = this.layout.height; - this.setLayout(this.layout); + this.setLayout(this.layout); }; @@ -8968,15 +8969,15 @@ ContinuousViewManager.prototype.next = function(){ if(this.settings.axis === "horizontal") { - this.scrollLeft = this.container.scrollLeft; + this.scrollLeft = this.container.scrollLeft; - if(this.container.scrollLeft + - this.container.offsetWidth + - this.layout.delta < this.container.scrollWidth) { - this.scrollBy(this.layout.delta, 0); - } else { - this.scrollTo(this.container.scrollWidth - this.layout.delta, 0); - } + if(this.container.scrollLeft + + this.container.offsetWidth + + this.layout.delta < this.container.scrollWidth) { + this.scrollBy(this.layout.delta, 0); + } else { + this.scrollTo(this.container.scrollWidth - this.layout.delta, 0); + } } else { this.scrollBy(0, this.layout.height); @@ -8985,7 +8986,7 @@ ContinuousViewManager.prototype.next = function(){ ContinuousViewManager.prototype.prev = function(){ if(this.settings.axis === "horizontal") { - this.scrollBy(-this.layout.delta, 0); + this.scrollBy(-this.layout.delta, 0); } else { this.scrollBy(0, -this.layout.height); } @@ -9006,7 +9007,7 @@ ContinuousViewManager.prototype.updateFlow = function(flow){ if (this.settings.axis === "vertical") { this.settings.infinite = true; - } else { + } else { this.settings.infinite = false; } @@ -9109,15 +9110,15 @@ SingleViewManager.prototype.destroy = function(){ SingleViewManager.prototype.onResized = function(e) { clearTimeout(this.resizeTimeout); - this.resizeTimeout = setTimeout(function(){ - this.resize(); - }.bind(this), 150); + this.resizeTimeout = setTimeout(function(){ + this.resize(); + }.bind(this), 150); }; SingleViewManager.prototype.resize = function(width, height){ // Clear the queue - this.q.clear(); + this.q.clear(); this._stageSize = this.stage.size(width, height); this._bounds = this.bounds(); @@ -9131,12 +9132,12 @@ SingleViewManager.prototype.resize = function(width, height){ view.size(this._stageSize.width, this._stageSize.height); }.bind(this)); - this.updateLayout(); + this.updateLayout(); - this.trigger("resized", { - width: this.stage.width, - height: this.stage.height - }); + this.trigger("resized", { + width: this.stage.width, + height: this.stage.height + }); }; @@ -9224,7 +9225,7 @@ SingleViewManager.prototype.moveTo = function(offset){ } } - this.scrollTo(distX, distY); + this.scrollTo(distX, distY); }; SingleViewManager.prototype.add = function(section){ @@ -9365,20 +9366,20 @@ SingleViewManager.prototype.current = function(){ // Current is the last visible view return visible[visible.length-1]; } - return null; + return null; }; SingleViewManager.prototype.currentLocation = function(){ - var view; - var start, end; + var view; + var start, end; - if(this.views.length) { - view = this.views.first(); - start = container.left - view.position().left; - end = start + this.layout.spread; + if(this.views.length) { + view = this.views.first(); + start = container.left - view.position().left; + end = start + this.layout.spread; - return this.mapping.page(view, view.section.cfiBase); - } + return this.mapping.page(view, view.section.cfiBase); + } }; @@ -9392,12 +9393,12 @@ SingleViewManager.prototype.isVisible = function(view, offsetPrev, offsetNext, _ return true; - } else if(this.settings.axis === "vertical" && - position.bottom > container.top - offsetPrev && + } else if(this.settings.axis === "vertical" && + position.bottom > container.top - offsetPrev && position.top < container.bottom + offsetNext) { return true; - } + } return false; @@ -9408,60 +9409,60 @@ SingleViewManager.prototype.visible = function(){ var container = this.bounds(); var views = this.views.displayed(); var viewsLength = views.length; - var visible = []; - var isVisible; - var view; + var visible = []; + var isVisible; + var view; - for (var i = 0; i < viewsLength; i++) { - view = views[i]; - isVisible = this.isVisible(view, 0, 0, container); + for (var i = 0; i < viewsLength; i++) { + view = views[i]; + isVisible = this.isVisible(view, 0, 0, container); - if(isVisible === true) { - visible.push(view); - } + if(isVisible === true) { + visible.push(view); + } - } - return visible; + } + return visible; }; SingleViewManager.prototype.scrollBy = function(x, y, silent){ - if(silent) { - this.ignore = true; - } + if(silent) { + this.ignore = true; + } - if(this.settings.height) { + if(this.settings.height) { - if(x) this.container.scrollLeft += x; - if(y) this.container.scrollTop += y; + if(x) this.container.scrollLeft += x; + if(y) this.container.scrollTop += y; - } else { - window.scrollBy(x,y); - } - // console.log("scrollBy", x, y); - this.scrolled = true; + } else { + window.scrollBy(x,y); + } + // console.log("scrollBy", x, y); + this.scrolled = true; this.onScroll(); }; SingleViewManager.prototype.scrollTo = function(x, y, silent){ - if(silent) { - this.ignore = true; - } + if(silent) { + this.ignore = true; + } - if(this.settings.height) { - this.container.scrollLeft = x; - this.container.scrollTop = y; - } else { - window.scrollTo(x,y); - } - // console.log("scrollTo", x, y); - this.scrolled = true; + if(this.settings.height) { + this.container.scrollLeft = x; + this.container.scrollTop = y; + } else { + window.scrollTo(x,y); + } + // console.log("scrollTo", x, y); + this.scrolled = true; this.onScroll(); - // if(this.container.scrollLeft != x){ - // setTimeout(function() { - // this.scrollTo(x, y, silent); - // }.bind(this), 10); - // return; - // }; + // if(this.container.scrollLeft != x){ + // setTimeout(function() { + // this.scrollTo(x, y, silent); + // }.bind(this), 10); + // return; + // }; }; SingleViewManager.prototype.onScroll = function(){ @@ -9482,7 +9483,7 @@ SingleViewManager.prototype.applyLayout = function(layout) { this.updateLayout(); this.mapping = new Mapping(this.layout); - // this.manager.layout(this.layout.format); + // this.manager.layout(this.layout.format); }; SingleViewManager.prototype.updateLayout = function() { @@ -9553,297 +9554,297 @@ SingleViewManager.prototype.updateFlow = function(flow){ var EpubCFI = require('./epubcfi'); function Mapping(layout){ - this.layout = layout; + this.layout = layout; }; Mapping.prototype.section = function(view) { - var ranges = this.findRanges(view); - var map = this.rangeListToCfiList(view.section.cfiBase, ranges); + var ranges = this.findRanges(view); + var map = this.rangeListToCfiList(view.section.cfiBase, ranges); - return map; + return map; }; Mapping.prototype.page = function(contents, cfiBase, start, end) { - var root = contents && contents.document ? contents.document.body : false; + var root = contents && contents.document ? contents.document.body : false; - if (!root) { - return; - } + if (!root) { + return; + } - return this.rangePairToCfiPair(cfiBase, { - start: this.findStart(root, start, end), - end: this.findEnd(root, start, end) - }); + return this.rangePairToCfiPair(cfiBase, { + start: this.findStart(root, start, end), + end: this.findEnd(root, start, end) + }); }; Mapping.prototype.walk = function(root, func) { - //var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, null, false); - var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, { - acceptNode: function (node) { - if ( node.data.trim().length > 0 ) { - return NodeFilter.FILTER_ACCEPT; - } else { - return NodeFilter.FILTER_REJECT; - } - } - }, false); - var node; - var result; - while ((node = treeWalker.nextNode())) { - result = func(node); - if(result) break; - } + //var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, null, false); + var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, { + acceptNode: function (node) { + if ( node.data.trim().length > 0 ) { + return NodeFilter.FILTER_ACCEPT; + } else { + return NodeFilter.FILTER_REJECT; + } + } + }, false); + var node; + var result; + while ((node = treeWalker.nextNode())) { + result = func(node); + if(result) break; + } - return result; + return result; }; Mapping.prototype.findRanges = function(view){ - var columns = []; - var scrollWidth = view.contents.scrollWidth(); - var count = this.layout.count(scrollWidth); - var column = this.layout.column; - var gap = this.layout.gap; - var start, end; + var columns = []; + var scrollWidth = view.contents.scrollWidth(); + var count = this.layout.count(scrollWidth); + var column = this.layout.column; + var gap = this.layout.gap; + var start, end; - for (var i = 0; i < count.pages; i++) { - start = (column + gap) * i; - end = (column * (i+1)) + (gap * i); - columns.push({ - start: this.findStart(view.document.body, start, end), - end: this.findEnd(view.document.body, start, end) - }); - } + for (var i = 0; i < count.pages; i++) { + start = (column + gap) * i; + end = (column * (i+1)) + (gap * i); + columns.push({ + start: this.findStart(view.document.body, start, end), + end: this.findEnd(view.document.body, start, end) + }); + } - return columns; + return columns; }; Mapping.prototype.findStart = function(root, start, end){ - var stack = [root]; - var $el; - var found; - var $prev = root; - while (stack.length) { + var stack = [root]; + var $el; + var found; + var $prev = root; + while (stack.length) { - $el = stack.shift(); + $el = stack.shift(); - found = this.walk($el, function(node){ - var left, right; - var elPos; - var elRange; + found = this.walk($el, function(node){ + var left, right; + var elPos; + var elRange; - if(node.nodeType == Node.TEXT_NODE){ - elRange = document.createRange(); - elRange.selectNodeContents(node); - elPos = elRange.getBoundingClientRect(); - } else { - elPos = node.getBoundingClientRect(); - } + if(node.nodeType == Node.TEXT_NODE){ + elRange = document.createRange(); + elRange.selectNodeContents(node); + elPos = elRange.getBoundingClientRect(); + } else { + elPos = node.getBoundingClientRect(); + } - left = elPos.left; - right = elPos.right; + left = elPos.left; + right = elPos.right; - if( left >= start && left <= end ) { - return node; - } else if (right > start) { - return node; - } else { - $prev = node; - stack.push(node); - } + if( left >= start && left <= end ) { + return node; + } else if (right > start) { + return node; + } else { + $prev = node; + stack.push(node); + } - }); + }); - if(found) { - return this.findTextStartRange(found, start, end); - } + if(found) { + return this.findTextStartRange(found, start, end); + } - } + } - // Return last element - return this.findTextStartRange($prev, start, end); + // Return last element + return this.findTextStartRange($prev, start, end); }; Mapping.prototype.findEnd = function(root, start, end){ - var stack = [root]; - var $el; - var $prev = root; - var found; + var stack = [root]; + var $el; + var $prev = root; + var found; - while (stack.length) { + while (stack.length) { - $el = stack.shift(); + $el = stack.shift(); - found = this.walk($el, function(node){ + found = this.walk($el, function(node){ - var left, right; - var elPos; - var elRange; + var left, right; + var elPos; + var elRange; - if(node.nodeType == Node.TEXT_NODE){ - elRange = document.createRange(); - elRange.selectNodeContents(node); - elPos = elRange.getBoundingClientRect(); - } else { - elPos = node.getBoundingClientRect(); - } + if(node.nodeType == Node.TEXT_NODE){ + elRange = document.createRange(); + elRange.selectNodeContents(node); + elPos = elRange.getBoundingClientRect(); + } else { + elPos = node.getBoundingClientRect(); + } - left = elPos.left; - right = elPos.right; + left = elPos.left; + right = elPos.right; - if(left > end && $prev) { - return $prev; - } else if(right > end) { - return node; - } else { - $prev = node; - stack.push(node); - } + if(left > end && $prev) { + return $prev; + } else if(right > end) { + return node; + } else { + $prev = node; + stack.push(node); + } - }); + }); - if(found){ - return this.findTextEndRange(found, start, end); - } + if(found){ + return this.findTextEndRange(found, start, end); + } - } + } - // end of chapter - return this.findTextEndRange($prev, start, end); + // end of chapter + return this.findTextEndRange($prev, start, end); }; Mapping.prototype.findTextStartRange = function(node, start, end){ - var ranges = this.splitTextNodeIntoRanges(node); - var prev; - var range; - var pos; + var ranges = this.splitTextNodeIntoRanges(node); + var prev; + var range; + var pos; - for (var i = 0; i < ranges.length; i++) { - range = ranges[i]; + for (var i = 0; i < ranges.length; i++) { + range = ranges[i]; - pos = range.getBoundingClientRect(); + pos = range.getBoundingClientRect(); - if( pos.left >= start ) { - return range; - } + if( pos.left >= start ) { + return range; + } - prev = range; + prev = range; - } + } - return ranges[0]; + return ranges[0]; }; Mapping.prototype.findTextEndRange = function(node, start, end){ - var ranges = this.splitTextNodeIntoRanges(node); - var prev; - var range; - var pos; + var ranges = this.splitTextNodeIntoRanges(node); + var prev; + var range; + var pos; - for (var i = 0; i < ranges.length; i++) { - range = ranges[i]; + for (var i = 0; i < ranges.length; i++) { + range = ranges[i]; - pos = range.getBoundingClientRect(); + pos = range.getBoundingClientRect(); - if(pos.left > end && prev) { - return prev; - } else if(pos.right > end) { - return range; - } + if(pos.left > end && prev) { + return prev; + } else if(pos.right > end) { + return range; + } - prev = range; + prev = range; - } + } - // Ends before limit - return ranges[ranges.length-1]; + // Ends before limit + return ranges[ranges.length-1]; }; Mapping.prototype.splitTextNodeIntoRanges = function(node, _splitter){ - var ranges = []; - var textContent = node.textContent || ""; - var text = textContent.trim(); - var range; - var rect; - var list; - var doc = node.ownerDocument; - var splitter = _splitter || " "; + var ranges = []; + var textContent = node.textContent || ""; + var text = textContent.trim(); + var range; + var rect; + var list; + var doc = node.ownerDocument; + var splitter = _splitter || " "; - pos = text.indexOf(splitter); + pos = text.indexOf(splitter); - if(pos === -1 || node.nodeType != Node.TEXT_NODE) { - range = doc.createRange(); - range.selectNodeContents(node); - return [range]; - } + if(pos === -1 || node.nodeType != Node.TEXT_NODE) { + range = doc.createRange(); + range.selectNodeContents(node); + return [range]; + } - range = doc.createRange(); - range.setStart(node, 0); - range.setEnd(node, pos); - ranges.push(range); - range = false; + range = doc.createRange(); + range.setStart(node, 0); + range.setEnd(node, pos); + ranges.push(range); + range = false; - while ( pos != -1 ) { + while ( pos != -1 ) { - pos = text.indexOf(splitter, pos + 1); - if(pos > 0) { + pos = text.indexOf(splitter, pos + 1); + if(pos > 0) { - if(range) { - range.setEnd(node, pos); - ranges.push(range); - } + if(range) { + range.setEnd(node, pos); + ranges.push(range); + } - range = doc.createRange(); - range.setStart(node, pos+1); - } - } + range = doc.createRange(); + range.setStart(node, pos+1); + } + } - if(range) { - range.setEnd(node, text.length); - ranges.push(range); - } + if(range) { + range.setEnd(node, text.length); + ranges.push(range); + } - return ranges; + return ranges; }; Mapping.prototype.rangePairToCfiPair = function(cfiBase, rangePair){ - var startRange = rangePair.start; - var endRange = rangePair.end; + var startRange = rangePair.start; + var endRange = rangePair.end; - startRange.collapse(true); - endRange.collapse(true); + startRange.collapse(true); + endRange.collapse(true); - // startCfi = section.cfiFromRange(startRange); - // endCfi = section.cfiFromRange(endRange); - startCfi = new EpubCFI(startRange, cfiBase).toString(); - endCfi = new EpubCFI(endRange, cfiBase).toString(); + // startCfi = section.cfiFromRange(startRange); + // endCfi = section.cfiFromRange(endRange); + startCfi = new EpubCFI(startRange, cfiBase).toString(); + endCfi = new EpubCFI(endRange, cfiBase).toString(); - return { - start: startCfi, - end: endCfi - }; + return { + start: startCfi, + end: endCfi + }; }; Mapping.prototype.rangeListToCfiList = function(cfiBase, columns){ - var map = []; - var rangePair, cifPair; + var map = []; + var rangePair, cifPair; - for (var i = 0; i < columns.length; i++) { - cifPair = this.rangePairToCfiPair(cfiBase, columns[i]); + for (var i = 0; i < columns.length; i++) { + cifPair = this.rangePairToCfiPair(cfiBase, columns[i]); - map.push(cifPair); + map.push(cifPair); - } + } - return map; + return map; }; module.exports = Mapping; @@ -9855,99 +9856,99 @@ var RSVP = require('rsvp'); var URI = require('urijs'); function Navigation(_package, _request){ - var navigation = this; - var parse = new Parser(); - var request = _request || require('./request'); + var navigation = this; + var parse = new Parser(); + var request = _request || require('./request'); - this.package = _package; - this.toc = []; - this.tocByHref = {}; - this.tocById = {}; + this.package = _package; + this.toc = []; + this.tocByHref = {}; + this.tocById = {}; - if(_package.navPath) { - this.navUrl = URI(_package.navPath).absoluteTo(_package.baseUrl).toString(); - this.nav = {}; + if(_package.navPath) { + this.navUrl = URI(_package.navPath).absoluteTo(_package.baseUrl).toString(); + this.nav = {}; - this.nav.load = function(_request){ - var loading = new RSVP.defer(); - var loaded = loading.promise; + this.nav.load = function(_request){ + var loading = new RSVP.defer(); + var loaded = loading.promise; - request(navigation.navUrl, 'xml').then(function(xml){ - navigation.toc = parse.nav(xml); - navigation.loaded(navigation.toc); - loading.resolve(navigation.toc); - }); + request(navigation.navUrl, 'xml').then(function(xml){ + navigation.toc = parse.nav(xml); + navigation.loaded(navigation.toc); + loading.resolve(navigation.toc); + }); - return loaded; - }; + return loaded; + }; - } + } - if(_package.ncxPath) { - this.ncxUrl = URI(_package.ncxPath).absoluteTo(_package.baseUrl).toString(); - this.ncx = {}; + if(_package.ncxPath) { + this.ncxUrl = URI(_package.ncxPath).absoluteTo(_package.baseUrl).toString(); + this.ncx = {}; - this.ncx.load = function(_request){ - var loading = new RSVP.defer(); - var loaded = loading.promise; + this.ncx.load = function(_request){ + var loading = new RSVP.defer(); + var loaded = loading.promise; - request(navigation.ncxUrl, 'xml').then(function(xml){ - navigation.toc = parse.toc(xml); - navigation.loaded(navigation.toc); - loading.resolve(navigation.toc); - }); + request(navigation.ncxUrl, 'xml').then(function(xml){ + navigation.toc = parse.toc(xml); + navigation.loaded(navigation.toc); + loading.resolve(navigation.toc); + }); - return loaded; - }; + return loaded; + }; - } + } }; // Load the navigation Navigation.prototype.load = function(_request) { - var request = _request || require('./request'); - var loading, loaded; + var request = _request || require('./request'); + var loading, loaded; - if(this.nav) { - loading = this.nav.load(); - } else if(this.ncx) { - loading = this.ncx.load(); - } else { - loaded = new RSVP.defer(); - loaded.resolve([]); - loading = loaded.promise; - } + if(this.nav) { + loading = this.nav.load(); + } else if(this.ncx) { + loading = this.ncx.load(); + } else { + loaded = new RSVP.defer(); + loaded.resolve([]); + loading = loaded.promise; + } - return loading; + return loading; }; Navigation.prototype.loaded = function(toc) { - var item; + var item; - for (var i = 0; i < toc.length; i++) { - item = toc[i]; - this.tocByHref[item.href] = i; - this.tocById[item.id] = i; - } + for (var i = 0; i < toc.length; i++) { + item = toc[i]; + this.tocByHref[item.href] = i; + this.tocById[item.id] = i; + } }; // Get an item from the navigation Navigation.prototype.get = function(target) { - var index; + var index; - if(!target) { - return this.toc; - } + if(!target) { + return this.toc; + } - if(target.indexOf("#") === 0) { - index = this.tocById[target.substring(1)]; - } else if(target in this.tocByHref){ - index = this.tocByHref[target]; - } + if(target.indexOf("#") === 0) { + index = this.tocById[target.substring(1)]; + } else if(target in this.tocByHref){ + index = this.tocByHref[target]; + } - return this.toc[index]; + return this.toc[index]; }; module.exports = Navigation; @@ -9961,120 +9962,120 @@ var EpubCFI = require('./epubcfi'); function Parser(){}; Parser.prototype.container = function(containerXml){ - //-- - var rootfile, fullpath, folder, encoding; + //-- + var rootfile, fullpath, folder, encoding; - if(!containerXml) { - console.error("Container File Not Found"); - return; - } + if(!containerXml) { + console.error("Container File Not Found"); + return; + } - rootfile = core.qs(containerXml, "rootfile"); + rootfile = core.qs(containerXml, "rootfile"); - if(!rootfile) { - console.error("No RootFile Found"); - return; - } + if(!rootfile) { + console.error("No RootFile Found"); + return; + } - fullpath = rootfile.getAttribute('full-path'); - folder = URI(fullpath).directory(); - encoding = containerXml.xmlEncoding; + fullpath = rootfile.getAttribute('full-path'); + folder = URI(fullpath).directory(); + encoding = containerXml.xmlEncoding; - //-- Now that we have the path we can parse the contents - return { - 'packagePath' : fullpath, - 'basePath' : folder, - 'encoding' : encoding - }; + //-- Now that we have the path we can parse the contents + return { + 'packagePath' : fullpath, + 'basePath' : folder, + 'encoding' : encoding + }; }; Parser.prototype.identifier = function(packageXml){ - var metadataNode; + var metadataNode; - if(!packageXml) { - console.error("Package File Not Found"); - return; - } + if(!packageXml) { + console.error("Package File Not Found"); + return; + } - metadataNode = core.qs(packageXml, "metadata"); + metadataNode = core.qs(packageXml, "metadata"); - if(!metadataNode) { - console.error("No Metadata Found"); - return; - } + if(!metadataNode) { + console.error("No Metadata Found"); + return; + } - return this.getElementText(metadataNode, "identifier"); + return this.getElementText(metadataNode, "identifier"); }; Parser.prototype.packageContents = function(packageXml){ - var parse = this; - var metadataNode, manifestNode, spineNode; - var manifest, navPath, ncxPath, coverPath; - var spineNodeIndex; - var spine; - var spineIndexByURL; - var metadata; + var parse = this; + var metadataNode, manifestNode, spineNode; + var manifest, navPath, ncxPath, coverPath; + var spineNodeIndex; + var spine; + var spineIndexByURL; + var metadata; - if(!packageXml) { - console.error("Package File Not Found"); - return; - } + if(!packageXml) { + console.error("Package File Not Found"); + return; + } - metadataNode = core.qs(packageXml, "metadata"); - if(!metadataNode) { - console.error("No Metadata Found"); - return; - } + metadataNode = core.qs(packageXml, "metadata"); + if(!metadataNode) { + console.error("No Metadata Found"); + return; + } - manifestNode = core.qs(packageXml, "manifest"); - if(!manifestNode) { - console.error("No Manifest Found"); - return; - } + manifestNode = core.qs(packageXml, "manifest"); + if(!manifestNode) { + console.error("No Manifest Found"); + return; + } - spineNode = core.qs(packageXml, "spine"); - if(!spineNode) { - console.error("No Spine Found"); - return; - } + spineNode = core.qs(packageXml, "spine"); + if(!spineNode) { + console.error("No Spine Found"); + return; + } - manifest = parse.manifest(manifestNode); - navPath = parse.findNavPath(manifestNode); - ncxPath = parse.findNcxPath(manifestNode, spineNode); - coverPath = parse.findCoverPath(packageXml); + manifest = parse.manifest(manifestNode); + navPath = parse.findNavPath(manifestNode); + ncxPath = parse.findNcxPath(manifestNode, spineNode); + coverPath = parse.findCoverPath(packageXml); - spineNodeIndex = Array.prototype.indexOf.call(spineNode.parentNode.childNodes, spineNode); + spineNodeIndex = Array.prototype.indexOf.call(spineNode.parentNode.childNodes, spineNode); - spine = parse.spine(spineNode, manifest); + spine = parse.spine(spineNode, manifest); - metadata = parse.metadata(metadataNode); + metadata = parse.metadata(metadataNode); metadata.direction = spineNode.getAttribute("page-progression-direction"); - return { - 'metadata' : metadata, - 'spine' : spine, - 'manifest' : manifest, - 'navPath' : navPath, - 'ncxPath' : ncxPath, - 'coverPath': coverPath, - 'spineNodeIndex' : spineNodeIndex - }; + return { + 'metadata' : metadata, + 'spine' : spine, + 'manifest' : manifest, + 'navPath' : navPath, + 'ncxPath' : ncxPath, + 'coverPath': coverPath, + 'spineNodeIndex' : spineNodeIndex + }; }; //-- Find TOC NAV Parser.prototype.findNavPath = function(manifestNode){ // Find item with property 'nav' // Should catch nav irregardless of order - // var node = manifestNode.querySelector("item[properties$='nav'], item[properties^='nav '], item[properties*=' nav ']"); - var node = core.qsp(manifestNode, "item", {"properties":"nav"}); - return node ? node.getAttribute('href') : false; + // var node = manifestNode.querySelector("item[properties$='nav'], item[properties^='nav '], item[properties*=' nav ']"); + var node = core.qsp(manifestNode, "item", {"properties":"nav"}); + return node ? node.getAttribute('href') : false; }; //-- Find TOC NCX: media-type="application/x-dtbncx+xml" href="toc.ncx" Parser.prototype.findNcxPath = function(manifestNode, spineNode){ // var node = manifestNode.querySelector("item[media-type='application/x-dtbncx+xml']"); - var node = core.qsp(manifestNode, "item", {"media-type":"application/x-dtbncx+xml"}); + var node = core.qsp(manifestNode, "item", {"media-type":"application/x-dtbncx+xml"}); var tocId; // If we can't find the toc by media-type then try to look for id of the item in the spine attributes as @@ -10084,7 +10085,7 @@ Parser.prototype.findNcxPath = function(manifestNode, spineNode){ tocId = spineNode.getAttribute("toc"); if(tocId) { // node = manifestNode.querySelector("item[id='" + tocId + "']"); - node = manifestNode.getElementById(tocId); + node = manifestNode.getElementById(tocId); } } @@ -10093,36 +10094,36 @@ Parser.prototype.findNcxPath = function(manifestNode, spineNode){ //-- Expanded to match Readium web components Parser.prototype.metadata = function(xml){ - var metadata = {}, - p = this; + var metadata = {}, + p = this; - metadata.title = p.getElementText(xml, 'title'); - metadata.creator = p.getElementText(xml, 'creator'); - metadata.description = p.getElementText(xml, 'description'); + metadata.title = p.getElementText(xml, 'title'); + metadata.creator = p.getElementText(xml, 'creator'); + metadata.description = p.getElementText(xml, 'description'); - metadata.pubdate = p.getElementText(xml, 'date'); + metadata.pubdate = p.getElementText(xml, 'date'); - metadata.publisher = p.getElementText(xml, 'publisher'); + metadata.publisher = p.getElementText(xml, 'publisher'); - metadata.identifier = p.getElementText(xml, "identifier"); - metadata.language = p.getElementText(xml, "language"); - metadata.rights = p.getElementText(xml, "rights"); + metadata.identifier = p.getElementText(xml, "identifier"); + metadata.language = p.getElementText(xml, "language"); + metadata.rights = p.getElementText(xml, "rights"); - metadata.modified_date = p.getPropertyText(xml, 'dcterms:modified'); + metadata.modified_date = p.getPropertyText(xml, 'dcterms:modified'); - metadata.layout = p.getPropertyText(xml, "rendition:layout"); - metadata.orientation = p.getPropertyText(xml, 'rendition:orientation'); - metadata.flow = p.getPropertyText(xml, 'rendition:flow'); - metadata.viewport = p.getPropertyText(xml, 'rendition:viewport'); - // metadata.page_prog_dir = packageXml.querySelector("spine").getAttribute("page-progression-direction"); + metadata.layout = p.getPropertyText(xml, "rendition:layout"); + metadata.orientation = p.getPropertyText(xml, 'rendition:orientation'); + metadata.flow = p.getPropertyText(xml, 'rendition:flow'); + metadata.viewport = p.getPropertyText(xml, 'rendition:viewport'); + // metadata.page_prog_dir = packageXml.querySelector("spine").getAttribute("page-progression-direction"); - return metadata; + return metadata; }; //-- Find Cover: //-- Fallback for Epub 2.0 Parser.prototype.findCoverPath = function(packageXml){ - var pkg = core.qs(packageXml, "package"); + var pkg = core.qs(packageXml, "package"); var epubVersion = pkg.getAttribute('version'); if (epubVersion === '2.0') { @@ -10130,7 +10131,7 @@ Parser.prototype.findCoverPath = function(packageXml){ if (metaCover) { var coverId = metaCover.getAttribute('content'); // var cover = packageXml.querySelector("item[id='" + coverId + "']"); - var cover = packageXml.getElementById(coverId); + var cover = packageXml.getElementById(coverId); return cover ? cover.getAttribute('href') : false; } else { @@ -10138,113 +10139,113 @@ Parser.prototype.findCoverPath = function(packageXml){ } } else { - // var node = packageXml.querySelector("item[properties='cover-image']"); - var node = core.qsp(packageXml, 'item', {'properties':'cover-image'}); + // var node = packageXml.querySelector("item[properties='cover-image']"); + var node = core.qsp(packageXml, 'item', {'properties':'cover-image'}); return node ? node.getAttribute('href') : false; } }; Parser.prototype.getElementText = function(xml, tag){ - var found = xml.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", tag), - el; + var found = xml.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", tag), + el; - if(!found || found.length === 0) return ''; + if(!found || found.length === 0) return ''; - el = found[0]; + el = found[0]; - if(el.childNodes.length){ - return el.childNodes[0].nodeValue; - } + if(el.childNodes.length){ + return el.childNodes[0].nodeValue; + } - return ''; + return ''; }; Parser.prototype.getPropertyText = function(xml, property){ - var el = core.qsp(xml, "meta", {"property":property}); + var el = core.qsp(xml, "meta", {"property":property}); - if(el && el.childNodes.length){ - return el.childNodes[0].nodeValue; - } + if(el && el.childNodes.length){ + return el.childNodes[0].nodeValue; + } - return ''; + return ''; }; Parser.prototype.querySelectorText = function(xml, q){ - var el = xml.querySelector(q); + var el = xml.querySelector(q); - if(el && el.childNodes.length){ - return el.childNodes[0].nodeValue; - } + if(el && el.childNodes.length){ + return el.childNodes[0].nodeValue; + } - return ''; + return ''; }; Parser.prototype.manifest = function(manifestXml){ - var manifest = {}; + var manifest = {}; - //-- Turn items into an array - // var selected = manifestXml.querySelectorAll("item"); - var selected = core.qsa(manifestXml, "item"); - var items = Array.prototype.slice.call(selected); + //-- Turn items into an array + // var selected = manifestXml.querySelectorAll("item"); + var selected = core.qsa(manifestXml, "item"); + var items = Array.prototype.slice.call(selected); - //-- Create an object with the id as key - items.forEach(function(item){ - var id = item.getAttribute('id'), - href = item.getAttribute('href') || '', - type = item.getAttribute('media-type') || '', - properties = item.getAttribute('properties') || ''; + //-- Create an object with the id as key + items.forEach(function(item){ + var id = item.getAttribute('id'), + href = item.getAttribute('href') || '', + type = item.getAttribute('media-type') || '', + properties = item.getAttribute('properties') || ''; - manifest[id] = { - 'href' : href, - // 'url' : href, - 'type' : type, - 'properties' : properties.length ? properties.split(' ') : [] - }; + manifest[id] = { + 'href' : href, + // 'url' : href, + 'type' : type, + 'properties' : properties.length ? properties.split(' ') : [] + }; - }); + }); - return manifest; + return manifest; }; Parser.prototype.spine = function(spineXml, manifest){ - var spine = []; + var spine = []; - var selected = spineXml.getElementsByTagName("itemref"), - items = Array.prototype.slice.call(selected); + var selected = spineXml.getElementsByTagName("itemref"), + items = Array.prototype.slice.call(selected); - var epubcfi = new EpubCFI(); + var epubcfi = new EpubCFI(); - //-- Add to array to mantain ordering and cross reference with manifest - items.forEach(function(item, index){ - var idref = item.getAttribute('idref'); - // var cfiBase = epubcfi.generateChapterComponent(spineNodeIndex, index, Id); - var props = item.getAttribute('properties') || ''; - var propArray = props.length ? props.split(' ') : []; - // var manifestProps = manifest[Id].properties; - // var manifestPropArray = manifestProps.length ? manifestProps.split(' ') : []; + //-- Add to array to mantain ordering and cross reference with manifest + items.forEach(function(item, index){ + var idref = item.getAttribute('idref'); + // var cfiBase = epubcfi.generateChapterComponent(spineNodeIndex, index, Id); + var props = item.getAttribute('properties') || ''; + var propArray = props.length ? props.split(' ') : []; + // var manifestProps = manifest[Id].properties; + // var manifestPropArray = manifestProps.length ? manifestProps.split(' ') : []; - var itemref = { - 'idref' : idref, - 'linear' : item.getAttribute('linear') || '', - 'properties' : propArray, - // 'href' : manifest[Id].href, - // 'url' : manifest[Id].url, - 'index' : index - // 'cfiBase' : cfiBase - }; - spine.push(itemref); - }); + var itemref = { + 'idref' : idref, + 'linear' : item.getAttribute('linear') || '', + 'properties' : propArray, + // 'href' : manifest[Id].href, + // 'url' : manifest[Id].url, + 'index' : index + // 'cfiBase' : cfiBase + }; + spine.push(itemref); + }); - return spine; + return spine; }; Parser.prototype.querySelectorByType = function(html, element, type){ - var query; - if (typeof html.querySelector != "undefined") { - query = html.querySelector(element+'[*|type="'+type+'"]'); - } + var query; + if (typeof html.querySelector != "undefined") { + query = html.querySelector(element+'[*|type="'+type+'"]'); + } // Handle IE not supporting namespaced epub:type in querySelector if(!query || query.length === 0) { query = core.qsa(html, element); @@ -10260,7 +10261,7 @@ Parser.prototype.querySelectorByType = function(html, element, type){ Parser.prototype.nav = function(navHtml, spineIndexByURL, bookSpine){ var navElement = this.querySelectorByType(navHtml, "nav", "toc"); - // var navItems = navElement ? navElement.querySelectorAll("ol li") : []; + // var navItems = navElement ? navElement.querySelectorAll("ol li") : []; var navItems = navElement ? core.qsa(navElement, "li") : []; var length = navItems.length; var i; @@ -10287,7 +10288,7 @@ Parser.prototype.nav = function(navHtml, spineIndexByURL, bookSpine){ Parser.prototype.navItem = function(item, spineIndexByURL, bookSpine){ var id = item.getAttribute('id') || false, // content = item.querySelector("a, span"), - content = core.qs(item, "a"), + content = core.qs(item, "a"), src = content.getAttribute('href') || '', text = content.textContent || "", // split = src.split("#"), @@ -10303,7 +10304,7 @@ Parser.prototype.navItem = function(item, spineIndexByURL, bookSpine){ parent = parentNode.getAttribute('id'); } - /* + /* if(!id) { if(spinePos) { spineItem = bookSpine[spinePos]; @@ -10314,7 +10315,7 @@ Parser.prototype.navItem = function(item, spineIndexByURL, bookSpine){ item.setAttribute('id', id); } } - */ + */ return { "id": id, @@ -10327,7 +10328,7 @@ Parser.prototype.navItem = function(item, spineIndexByURL, bookSpine){ Parser.prototype.ncx = function(tocXml, spineIndexByURL, bookSpine){ // var navPoints = tocXml.querySelectorAll("navMap navPoint"); - var navPoints = core.qsa(tocXml, "navPoint"); + var navPoints = core.qsa(tocXml, "navPoint"); var length = navPoints.length; var i; var toc = {}; @@ -10355,8 +10356,8 @@ Parser.prototype.ncxItem = function(item, spineIndexByURL, bookSpine){ // content = item.querySelector("content"), content = core.qs(item, "content"), src = content.getAttribute('src'), - // navLabel = item.querySelector("navLabel"), - navLabel = core.qs(item, "navLabel"), + // navLabel = item.querySelector("navLabel"), + navLabel = core.qs(item, "navLabel"), text = navLabel.textContent ? navLabel.textContent : "", // split = src.split("#"), // baseUrl = split[0], @@ -10371,7 +10372,7 @@ Parser.prototype.ncxItem = function(item, spineIndexByURL, bookSpine){ parent = parentNode.getAttribute('id'); } - /* + /* if(!id) { if(spinePos) { spineItem = bookSpine[spinePos]; @@ -10382,7 +10383,7 @@ Parser.prototype.ncxItem = function(item, spineIndexByURL, bookSpine){ item.setAttribute('id', id); } } - */ + */ return { "id": id, @@ -10395,7 +10396,7 @@ Parser.prototype.ncxItem = function(item, spineIndexByURL, bookSpine){ Parser.prototype.pageList = function(navHtml, spineIndexByURL, bookSpine){ var navElement = this.querySelectorByType(navHtml, "nav", "page-list"); - // var navItems = navElement ? navElement.querySelectorAll("ol li") : []; + // var navItems = navElement ? navElement.querySelectorAll("ol li") : []; var navItems = navElement ? core.qsa(navElement, "li") : []; var length = navItems.length; var i; @@ -10416,7 +10417,7 @@ Parser.prototype.pageList = function(navHtml, spineIndexByURL, bookSpine){ Parser.prototype.pageListItem = function(item, spineIndexByURL, bookSpine){ var id = item.getAttribute('id') || false, // content = item.querySelector("a"), - content = core.qs(item, "a"), + content = core.qs(item, "a"), href = content.getAttribute('href') || '', text = content.textContent || "", page = parseInt(text), @@ -10450,191 +10451,191 @@ var RSVP = require('rsvp'); var core = require('./core'); function Queue(_context){ - this._q = []; - this.context = _context; - this.tick = core.requestAnimationFrame; - this.running = false; - this.paused = false; + this._q = []; + this.context = _context; + this.tick = core.requestAnimationFrame; + this.running = false; + this.paused = false; }; // Add an item to the queue Queue.prototype.enqueue = function() { - var deferred, promise; - var queued; - var task = [].shift.call(arguments); - var args = arguments; + var deferred, promise; + var queued; + var task = [].shift.call(arguments); + var args = arguments; - // Handle single args without context - // if(args && !Array.isArray(args)) { - // args = [args]; - // } - if(!task) { - return console.error("No Task Provided"); - } + // Handle single args without context + // if(args && !Array.isArray(args)) { + // args = [args]; + // } + if(!task) { + return console.error("No Task Provided"); + } - if(typeof task === "function"){ + if(typeof task === "function"){ - deferred = new RSVP.defer(); - promise = deferred.promise; + deferred = new RSVP.defer(); + promise = deferred.promise; - queued = { - "task" : task, - "args" : args, - //"context" : context, - "deferred" : deferred, - "promise" : promise - }; + queued = { + "task" : task, + "args" : args, + //"context" : context, + "deferred" : deferred, + "promise" : promise + }; - } else { - // Task is a promise - queued = { - "promise" : task - }; + } else { + // Task is a promise + queued = { + "promise" : task + }; - } + } - this._q.push(queued); + this._q.push(queued); - // Wait to start queue flush - if (this.paused == false && !this.running) { - // setTimeout(this.flush.bind(this), 0); - // this.tick.call(window, this.run.bind(this)); - this.run(); - } + // Wait to start queue flush + if (this.paused == false && !this.running) { + // setTimeout(this.flush.bind(this), 0); + // this.tick.call(window, this.run.bind(this)); + this.run(); + } - return queued.promise; + return queued.promise; }; // Run one item Queue.prototype.dequeue = function(){ - var inwait, task, result; + var inwait, task, result; - if(this._q.length) { - inwait = this._q.shift(); - task = inwait.task; - if(task){ - // console.log(task) + if(this._q.length) { + inwait = this._q.shift(); + task = inwait.task; + if(task){ + // console.log(task) - result = task.apply(this.context, inwait.args); + result = task.apply(this.context, inwait.args); - if(result && typeof result["then"] === "function") { - // Task is a function that returns a promise - return result.then(function(){ - inwait.deferred.resolve.apply(this.context, arguments); - }.bind(this)); - } else { - // Task resolves immediately - inwait.deferred.resolve.apply(this.context, result); - return inwait.promise; - } + if(result && typeof result["then"] === "function") { + // Task is a function that returns a promise + return result.then(function(){ + inwait.deferred.resolve.apply(this.context, arguments); + }.bind(this)); + } else { + // Task resolves immediately + inwait.deferred.resolve.apply(this.context, result); + return inwait.promise; + } - } else if(inwait.promise) { - // Task is a promise - return inwait.promise; - } + } else if(inwait.promise) { + // Task is a promise + return inwait.promise; + } - } else { - inwait = new RSVP.defer(); - inwait.deferred.resolve(); - return inwait.promise; - } + } else { + inwait = new RSVP.defer(); + inwait.deferred.resolve(); + return inwait.promise; + } }; // Run All Immediately Queue.prototype.dump = function(){ - while(this._q.length) { - this.dequeue(); - } + while(this._q.length) { + this.dequeue(); + } }; // Run all sequentially, at convince Queue.prototype.run = function(){ - if(!this.running){ - this.running = true; - this.defered = new RSVP.defer(); - } + if(!this.running){ + this.running = true; + this.defered = new RSVP.defer(); + } - this.tick.call(window, function() { + this.tick.call(window, function() { - if(this._q.length) { + if(this._q.length) { - this.dequeue() - .then(function(){ - this.run(); - }.bind(this)); + this.dequeue() + .then(function(){ + this.run(); + }.bind(this)); - } else { - this.defered.resolve(); - this.running = undefined; - } + } else { + this.defered.resolve(); + this.running = undefined; + } - }.bind(this)); + }.bind(this)); - // Unpause - if(this.paused == true) { - this.paused = false; - } + // Unpause + if(this.paused == true) { + this.paused = false; + } - return this.defered.promise; + return this.defered.promise; }; // Flush all, as quickly as possible Queue.prototype.flush = function(){ - if(this.running){ - return this.running; - } + if(this.running){ + return this.running; + } - if(this._q.length) { - this.running = this.dequeue() - .then(function(){ - this.running = undefined; - return this.flush(); - }.bind(this)); + if(this._q.length) { + this.running = this.dequeue() + .then(function(){ + this.running = undefined; + return this.flush(); + }.bind(this)); - return this.running; - } + return this.running; + } }; // Clear all items in wait Queue.prototype.clear = function(){ - this._q = []; - this.running = false; + this._q = []; + this.running = false; }; Queue.prototype.length = function(){ - return this._q.length; + return this._q.length; }; Queue.prototype.pause = function(){ - this.paused = true; + this.paused = true; }; // Create a new task from a callback function Task(task, args, context){ - return function(){ - var toApply = arguments || []; + return function(){ + var toApply = arguments || []; - return new RSVP.Promise(function(resolve, reject) { - var callback = function(value){ - resolve(value); - }; - // Add the callback to the arguments list - toApply.push(callback); + return new RSVP.Promise(function(resolve, reject) { + var callback = function(value){ + resolve(value); + }; + // Add the callback to the arguments list + toApply.push(callback); - // Apply all arguments to the functions - task.apply(this, toApply); + // Apply all arguments to the functions + task.apply(this, toApply); - }.bind(this)); + }.bind(this)); - }; + }; }; @@ -10692,7 +10693,7 @@ function Rendition(book, options) { // this.hooks.display.register(this.afterDisplay.bind(this)); - this.epubcfi = new EpubCFI(); + this.epubcfi = new EpubCFI(); this.q = new Queue(this); @@ -10726,7 +10727,7 @@ Rendition.prototype.requireManager = function(manager) { viewManager = manager } - return viewManager; + return viewManager; }; Rendition.prototype.requireView = function(view) { @@ -10739,7 +10740,7 @@ Rendition.prototype.requireView = function(view) { View = view } - return View; + return View; }; Rendition.prototype.start = function(){ @@ -11005,24 +11006,24 @@ Rendition.prototype.spread = function(spread, min){ Rendition.prototype.reportLocation = function(){ - return this.q.enqueue(function(){ - var location = this.manager.currentLocation(); + return this.q.enqueue(function(){ + var location = this.manager.currentLocation(); if (location && location.then && typeof location.then === 'function') { location.then(function(result) { this.location = result; - this.trigger("locationChanged", this.location); + this.trigger("locationChanged", this.location); }.bind(this)); } else if (location) { this.location = location; - this.trigger("locationChanged", this.location); + this.trigger("locationChanged", this.location); } - }.bind(this)); + }.bind(this)); }; Rendition.prototype.destroy = function(){ - // Clear the queue + // Clear the queue this.q.clear(); this.views.clear(); @@ -11037,7 +11038,7 @@ Rendition.prototype.destroy = function(){ }; Rendition.prototype.passViewEvents = function(view){ - view.contents.listenedEvents.forEach(function(e){ + view.contents.listenedEvents.forEach(function(e){ view.on(e, this.triggerViewEvent.bind(this)); }.bind(this)); @@ -11045,11 +11046,11 @@ Rendition.prototype.passViewEvents = function(view){ }; Rendition.prototype.triggerViewEvent = function(e){ - this.trigger(e.type, e); + this.trigger(e.type, e); }; Rendition.prototype.triggerSelectedEvent = function(cfirange){ - this.trigger("selected", cfirange); + this.trigger("selected", cfirange); }; Rendition.prototype.replacements = function(){ @@ -11057,27 +11058,27 @@ Rendition.prototype.replacements = function(){ // return this.q.enqueue(function () { // Get thes books manifest var manifest = this.book.package.manifest; - var manifestArray = Object.keys(manifest). - map(function (key){ - return manifest[key]; - }); + var manifestArray = Object.keys(manifest). + map(function (key){ + return manifest[key]; + }); - // Exclude HTML - var items = manifestArray. - filter(function (item){ - if (item.type != "application/xhtml+xml" && - item.type != "text/html") { - return true; - } - }); + // Exclude HTML + var items = manifestArray. + filter(function (item){ + if (item.type != "application/xhtml+xml" && + item.type != "text/html") { + return true; + } + }); - // Only CSS - var css = items. - filter(function (item){ - if (item.type === "text/css") { - return true; - } - }); + // Only CSS + var css = items. + filter(function (item){ + if (item.type === "text/css") { + return true; + } + }); // Css Urls var cssUrls = css.map(function(item) { @@ -11085,18 +11086,18 @@ Rendition.prototype.replacements = function(){ }); // All Assets Urls - var urls = items. - map(function(item) { - return item.href; - }.bind(this)); + var urls = items. + map(function(item) { + return item.href; + }.bind(this)); // Create blob urls for all the assets - var processing = urls. - map(function(url) { + var processing = urls. + map(function(url) { var absolute = URI(url).absoluteTo(this.book.baseUrl).toString(); // Full url from archive base - return this.book.unarchived.createUrl(absolute, {"base64": this.settings.useBase64}); - }.bind(this)); + return this.book.unarchived.createUrl(absolute, {"base64": this.settings.useBase64}); + }.bind(this)); var replacementUrls; @@ -11110,11 +11111,11 @@ Rendition.prototype.replacements = function(){ // Replace Asset Urls in the text of all css files cssUrls.forEach(function(href) { replaced.push(this.replaceCss(href, urls, replacementUrls)); - }.bind(this)); + }.bind(this)); return RSVP.all(replaced); - }.bind(this)) + }.bind(this)) .then(function () { // Replace Asset Urls in chapters // by registering a hook after the sections contents has been serialized @@ -11126,8 +11127,8 @@ Rendition.prototype.replacements = function(){ }.bind(this)) .catch(function(reason){ - console.error(reason); - }); + console.error(reason); + }); // }.bind(this)); }; @@ -11188,31 +11189,31 @@ Rendition.prototype.replaceAssets = function(section, urls, replacementUrls){ }; Rendition.prototype.range = function(_cfi, ignoreClass){ - var cfi = new EpubCFI(_cfi); - var found = this.visible().filter(function (view) { + var cfi = new EpubCFI(_cfi); + var found = this.visible().filter(function (view) { if(cfi.spinePos === view.index) return true; }); // Should only every return 1 item - if (found.length) { - return found[0].range(cfi, ignoreClass); - } + if (found.length) { + return found[0].range(cfi, ignoreClass); + } }; Rendition.prototype.adjustImages = function(view) { - view.addStylesheetRules([ - ["img", - ["max-width", (view.layout.spreadWidth) + "px"], - ["max-height", (view.layout.height) + "px"] - ] - ]); - return new RSVP.Promise(function(resolve, reject){ - // Wait to apply - setTimeout(function() { - resolve(); - }, 1); - }); + view.addStylesheetRules([ + ["img", + ["max-width", (view.layout.spreadWidth) + "px"], + ["max-height", (view.layout.height) + "px"] + ] + ]); + return new RSVP.Promise(function(resolve, reject){ + // Wait to apply + setTimeout(function() { + resolve(); + }, 1); + }); }; //-- Enable binding events to Renderer @@ -11225,69 +11226,69 @@ var URI = require('urijs'); var core = require('./core'); function base(doc, section){ - var base; - var head; + var base; + var head; - if(!doc){ - return; - } + if(!doc){ + return; + } - // head = doc.querySelector("head"); - // base = head.querySelector("base"); - head = core.qs(doc, "head"); - base = core.qs(head, "base"); + // head = doc.querySelector("head"); + // base = head.querySelector("base"); + head = core.qs(doc, "head"); + base = core.qs(head, "base"); - if(!base) { - base = doc.createElement("base"); - head.insertBefore(base, head.firstChild); - } + if(!base) { + base = doc.createElement("base"); + head.insertBefore(base, head.firstChild); + } - base.setAttribute("href", section.url); + base.setAttribute("href", section.url); } function canonical(doc, section){ - var head; - var link; - var url = section.url; // window.location.origin + window.location.pathname + "?loc=" + encodeURIComponent(section.url); + var head; + var link; + var url = section.url; // window.location.origin + window.location.pathname + "?loc=" + encodeURIComponent(section.url); - if(!doc){ - return; - } + if(!doc){ + return; + } - head = core.qs(doc, "head"); - link = core.qs(head, "link[rel='canonical']"); + head = core.qs(doc, "head"); + link = core.qs(head, "link[rel='canonical']"); - if (link) { - link.setAttribute("href", url); - } else { - link = doc.createElement("link"); - link.setAttribute("rel", "canonical"); - link.setAttribute("href", url); - head.appendChild(link); - } + if (link) { + link.setAttribute("href", url); + } else { + link = doc.createElement("link"); + link.setAttribute("rel", "canonical"); + link.setAttribute("href", url); + head.appendChild(link); + } } function links(view, renderer) { - var links = view.document.querySelectorAll("a[href]"); - var replaceLinks = function(link){ - var href = link.getAttribute("href"); + var links = view.document.querySelectorAll("a[href]"); + var replaceLinks = function(link){ + var href = link.getAttribute("href"); - if(href.indexOf("mailto:") === 0){ - return; - } + if(href.indexOf("mailto:") === 0){ + return; + } - var linkUri = URI(href); - var absolute = linkUri.absoluteTo(view.section.url); - var relative = absolute.relativeTo(this.book.baseUrl).toString(); + var linkUri = URI(href); + var absolute = linkUri.absoluteTo(view.section.url); + var relative = absolute.relativeTo(this.book.baseUrl).toString(); - if(linkUri.protocol()){ + if(linkUri.protocol()){ - link.setAttribute("target", "_blank"); + link.setAttribute("target", "_blank"); - }else{ - /* - if(baseDirectory) { + }else{ + /* + if(baseDirectory) { // We must ensure that the file:// protocol is preserved for // local file links, as in certain contexts (such as under // Titanium), file links without the file:// protocol will not @@ -11300,40 +11301,40 @@ function links(view, renderer) { } else { relative = href; } - */ + */ - if(linkUri.fragment()) { - // do nothing with fragment yet - } else { - link.onclick = function(){ - renderer.display(relative); - return false; - }; - } + if(linkUri.fragment()) { + // do nothing with fragment yet + } else { + link.onclick = function(){ + renderer.display(relative); + return false; + }; + } - } - }.bind(this); + } + }.bind(this); - for (var i = 0; i < links.length; i++) { - replaceLinks(links[i]); - } + for (var i = 0; i < links.length; i++) { + replaceLinks(links[i]); + } }; function substitute(content, urls, replacements) { - urls.forEach(function(url, i){ - if (url && replacements[i]) { - content = content.replace(new RegExp(url, 'g'), replacements[i]); - } - }); - return content; + urls.forEach(function(url, i){ + if (url && replacements[i]) { + content = content.replace(new RegExp(url, 'g'), replacements[i]); + } + }); + return content; } module.exports = { - 'base': base, - 'canonical' : canonical, - 'links': links, - 'substitute': substitute + 'base': base, + 'canonical' : canonical, + 'links': links, + 'substitute': substitute }; },{"./core":10,"urijs":7}],23:[function(require,module,exports){ @@ -11342,55 +11343,55 @@ var URI = require('urijs'); var core = require('./core'); function request(url, type, withCredentials, headers) { - var supportsURL = (typeof window != "undefined") ? window.URL : false; // TODO: fallback for url if window isn't defined - var BLOB_RESPONSE = supportsURL ? "blob" : "arraybuffer"; - var uri; + var supportsURL = (typeof window != "undefined") ? window.URL : false; // TODO: fallback for url if window isn't defined + var BLOB_RESPONSE = supportsURL ? "blob" : "arraybuffer"; + var uri; - var deferred = new RSVP.defer(); + var deferred = new RSVP.defer(); - var xhr = new XMLHttpRequest(); + var xhr = new XMLHttpRequest(); - //-- Check from PDF.js: - // https://github.com/mozilla/pdf.js/blob/master/web/compatibility.js - var xhrPrototype = XMLHttpRequest.prototype; + //-- Check from PDF.js: + // https://github.com/mozilla/pdf.js/blob/master/web/compatibility.js + var xhrPrototype = XMLHttpRequest.prototype; - var header; + var header; - if (!('overrideMimeType' in xhrPrototype)) { - // IE10 might have response, but not overrideMimeType - Object.defineProperty(xhrPrototype, 'overrideMimeType', { - value: function xmlHttpRequestOverrideMimeType(mimeType) {} - }); - } - if(withCredentials) { - xhr.withCredentials = true; - } + if (!('overrideMimeType' in xhrPrototype)) { + // IE10 might have response, but not overrideMimeType + Object.defineProperty(xhrPrototype, 'overrideMimeType', { + value: function xmlHttpRequestOverrideMimeType(mimeType) {} + }); + } + if(withCredentials) { + xhr.withCredentials = true; + } - xhr.onreadystatechange = handler; - xhr.onerror = err; + xhr.onreadystatechange = handler; + xhr.onerror = err; - xhr.open("GET", url, true); + xhr.open("GET", url, true); - for(header in headers) { - xhr.setRequestHeader(header, headers[header]); - } + for(header in headers) { + xhr.setRequestHeader(header, headers[header]); + } - if(type == "json") { - xhr.setRequestHeader("Accept", "application/json"); - } + if(type == "json") { + xhr.setRequestHeader("Accept", "application/json"); + } - // If type isn't set, determine it from the file extension + // If type isn't set, determine it from the file extension if(!type) { uri = URI(url); type = uri.suffix(); } - if(type == 'blob'){ - xhr.responseType = BLOB_RESPONSE; - } + if(type == 'blob'){ + xhr.responseType = BLOB_RESPONSE; + } - if(core.isXml(type)) { + if(core.isXml(type)) { // xhr.responseType = "document"; xhr.overrideMimeType('text/xml'); // for OPF parsing } @@ -11401,89 +11402,89 @@ function request(url, type, withCredentials, headers) { if(type == 'html' || type == 'htm') { // xhr.responseType = "document"; - } + } - if(type == "binary") { - xhr.responseType = "arraybuffer"; - } + if(type == "binary") { + xhr.responseType = "arraybuffer"; + } - xhr.send(); + xhr.send(); - function err(e) { - console.error(e); - deferred.reject(e); - } + function err(e) { + console.error(e); + deferred.reject(e); + } - function handler() { - if (this.readyState === XMLHttpRequest.DONE) { + function handler() { + if (this.readyState === XMLHttpRequest.DONE) { - if (this.status === 200 || this.responseXML ) { //-- Firefox is reporting 0 for blob urls - var r; + if (this.status === 200 || this.responseXML ) { //-- Firefox is reporting 0 for blob urls + var r; - if (!this.response && !this.responseXML) { - deferred.reject({ - status: this.status, - message : "Empty Response", - stack : new Error().stack - }); - return deferred.promise; - } + if (!this.response && !this.responseXML) { + deferred.reject({ + status: this.status, + message : "Empty Response", + stack : new Error().stack + }); + return deferred.promise; + } - if (this.status === 403) { - deferred.reject({ - status: this.status, - response: this.response, - message : "Forbidden", - stack : new Error().stack - }); - return deferred.promise; - } + if (this.status === 403) { + deferred.reject({ + status: this.status, + response: this.response, + message : "Forbidden", + stack : new Error().stack + }); + return deferred.promise; + } - if((this.responseType == '' || this.responseType == 'document') - && this.responseXML){ - r = this.responseXML; - } else - if(core.isXml(type)){ - // xhr.overrideMimeType('text/xml'); // for OPF parsing - // If this.responseXML wasn't set, try to parse using a DOMParser from text - r = core.parse(this.response, "text/xml"); - }else - if(type == 'xhtml'){ - r = core.parse(this.response, "application/xhtml+xml"); - }else - if(type == 'html' || type == 'htm'){ - r = core.parse(this.response, "text/html"); - }else - if(type == 'json'){ - r = JSON.parse(this.response); - }else - if(type == 'blob'){ + if((this.responseType == '' || this.responseType == 'document') + && this.responseXML){ + r = this.responseXML; + } else + if(core.isXml(type)){ + // xhr.overrideMimeType('text/xml'); // for OPF parsing + // If this.responseXML wasn't set, try to parse using a DOMParser from text + r = core.parse(this.response, "text/xml"); + }else + if(type == 'xhtml'){ + r = core.parse(this.response, "application/xhtml+xml"); + }else + if(type == 'html' || type == 'htm'){ + r = core.parse(this.response, "text/html"); + }else + if(type == 'json'){ + r = JSON.parse(this.response); + }else + if(type == 'blob'){ - if(supportsURL) { - r = this.response; - } else { - //-- Safari doesn't support responseType blob, so create a blob from arraybuffer - r = new Blob([this.response]); - } + if(supportsURL) { + r = this.response; + } else { + //-- Safari doesn't support responseType blob, so create a blob from arraybuffer + r = new Blob([this.response]); + } - }else{ - r = this.response; - } + }else{ + r = this.response; + } - deferred.resolve(r); - } else { + deferred.resolve(r); + } else { - deferred.reject({ - status: this.status, - message : this.response, - stack : new Error().stack - }); + deferred.reject({ + status: this.status, + message : this.response, + stack : new Error().stack + }); - } - } - } + } + } + } - return deferred.promise; + return deferred.promise; }; module.exports = request; @@ -11496,110 +11497,110 @@ var EpubCFI = require('./epubcfi'); var Hook = require('./hook'); function Section(item, hooks){ - this.idref = item.idref; - this.linear = item.linear; - this.properties = item.properties; - this.index = item.index; - this.href = item.href; - this.url = item.url; - this.next = item.next; - this.prev = item.prev; + this.idref = item.idref; + this.linear = item.linear; + this.properties = item.properties; + this.index = item.index; + this.href = item.href; + this.url = item.url; + this.next = item.next; + this.prev = item.prev; - this.cfiBase = item.cfiBase; + this.cfiBase = item.cfiBase; - if (hooks) { - this.hooks = hooks; - } else { - this.hooks = {}; - this.hooks.serialize = new Hook(this); - this.hooks.content = new Hook(this); - } + if (hooks) { + this.hooks = hooks; + } else { + this.hooks = {}; + this.hooks.serialize = new Hook(this); + this.hooks.content = new Hook(this); + } }; Section.prototype.load = function(_request){ - var request = _request || this.request || require('./request'); - var loading = new RSVP.defer(); - var loaded = loading.promise; + var request = _request || this.request || require('./request'); + var loading = new RSVP.defer(); + var loaded = loading.promise; - if(this.contents) { - loading.resolve(this.contents); - } else { - request(this.url) - .then(function(xml){ - var base; - var directory = URI(this.url).directory(); + if(this.contents) { + loading.resolve(this.contents); + } else { + request(this.url) + .then(function(xml){ + var base; + var directory = URI(this.url).directory(); - this.document = xml; - this.contents = xml.documentElement; + this.document = xml; + this.contents = xml.documentElement; - return this.hooks.content.trigger(this.document, this); - }.bind(this)) - .then(function(){ - loading.resolve(this.contents); - }.bind(this)) - .catch(function(error){ - loading.reject(error); - }); - } + return this.hooks.content.trigger(this.document, this); + }.bind(this)) + .then(function(){ + loading.resolve(this.contents); + }.bind(this)) + .catch(function(error){ + loading.reject(error); + }); + } - return loaded; + return loaded; }; Section.prototype.base = function(_document){ - var task = new RSVP.defer(); - var base = _document.createElement("base"); // TODO: check if exists - var head; - console.log(window.location.origin + "/" +this.url); + var task = new RSVP.defer(); + var base = _document.createElement("base"); // TODO: check if exists + var head; + console.log(window.location.origin + "/" +this.url); - base.setAttribute("href", window.location.origin + "/" +this.url); + base.setAttribute("href", window.location.origin + "/" +this.url); - if(_document) { - head = _document.querySelector("head"); - } - if(head) { - head.insertBefore(base, head.firstChild); - task.resolve(); - } else { - task.reject(new Error("No head to insert into")); - } + if(_document) { + head = _document.querySelector("head"); + } + if(head) { + head.insertBefore(base, head.firstChild); + task.resolve(); + } else { + task.reject(new Error("No head to insert into")); + } - return task.promise; + return task.promise; }; Section.prototype.beforeSectionLoad = function(){ - // Stub for a hook - replace me for now + // Stub for a hook - replace me for now }; Section.prototype.render = function(_request){ - var rendering = new RSVP.defer(); - var rendered = rendering.promise; - this.output; // TODO: better way to return this from hooks? + var rendering = new RSVP.defer(); + var rendered = rendering.promise; + this.output; // TODO: better way to return this from hooks? - this.load(_request). - then(function(contents){ - var serializer; + this.load(_request). + then(function(contents){ + var serializer; - if (typeof XMLSerializer === "undefined") { - XMLSerializer = require('xmldom').XMLSerializer; - } - serializer = new XMLSerializer(); - this.output = serializer.serializeToString(contents); - return this.output; - }.bind(this)). - then(function(){ - return this.hooks.serialize.trigger(this.output, this); - }.bind(this)). - then(function(){ - rendering.resolve(this.output); - }.bind(this)) - .catch(function(error){ - rendering.reject(error); - }); + if (typeof XMLSerializer === "undefined") { + XMLSerializer = require('xmldom').XMLSerializer; + } + serializer = new XMLSerializer(); + this.output = serializer.serializeToString(contents); + return this.output; + }.bind(this)). + then(function(){ + return this.hooks.serialize.trigger(this.output, this); + }.bind(this)). + then(function(){ + rendering.resolve(this.output); + }.bind(this)) + .catch(function(error){ + rendering.reject(error); + }); - return rendered; + return rendered; }; Section.prototype.find = function(_query){ @@ -11613,35 +11614,35 @@ Section.prototype.find = function(_query){ * Returns: Object with layout properties */ Section.prototype.reconcileLayoutSettings = function(global){ - //-- Get the global defaults - var settings = { - layout : global.layout, - spread : global.spread, - orientation : global.orientation - }; + //-- Get the global defaults + var settings = { + layout : global.layout, + spread : global.spread, + orientation : global.orientation + }; - //-- Get the chapter's display type - this.properties.forEach(function(prop){ - var rendition = prop.replace("rendition:", ''); - var split = rendition.indexOf("-"); - var property, value; + //-- Get the chapter's display type + this.properties.forEach(function(prop){ + var rendition = prop.replace("rendition:", ''); + var split = rendition.indexOf("-"); + var property, value; - if(split != -1){ - property = rendition.slice(0, split); - value = rendition.slice(split+1); + if(split != -1){ + property = rendition.slice(0, split); + value = rendition.slice(split+1); - settings[property] = value; - } - }); + settings[property] = value; + } + }); return settings; }; Section.prototype.cfiFromRange = function(_range) { - return new EpubCFI(_range, this.cfiBase).toString(); + return new EpubCFI(_range, this.cfiBase).toString(); }; Section.prototype.cfiFromElement = function(el) { - return new EpubCFI(el, this.cfiBase).toString(); + return new EpubCFI(el, this.cfiBase).toString(); }; module.exports = Section; @@ -11655,64 +11656,64 @@ var Section = require('./section'); var replacements = require('./replacements'); function Spine(_request){ - this.request = _request; - this.spineItems = []; - this.spineByHref = {}; - this.spineById = {}; + this.request = _request; + this.spineItems = []; + this.spineByHref = {}; + this.spineById = {}; - this.hooks = {}; - this.hooks.serialize = new Hook(); - this.hooks.content = new Hook(); + this.hooks = {}; + this.hooks.serialize = new Hook(); + this.hooks.content = new Hook(); - // Register replacements - this.hooks.content.register(replacements.base); - this.hooks.content.register(replacements.canonical); + // Register replacements + this.hooks.content.register(replacements.base); + this.hooks.content.register(replacements.canonical); - this.epubcfi = new EpubCFI(); + this.epubcfi = new EpubCFI(); - this.loaded = false; + this.loaded = false; }; Spine.prototype.load = function(_package) { - this.items = _package.spine; - this.manifest = _package.manifest; - this.spineNodeIndex = _package.spineNodeIndex; - this.baseUrl = _package.baseUrl || ''; - this.length = this.items.length; + this.items = _package.spine; + this.manifest = _package.manifest; + this.spineNodeIndex = _package.spineNodeIndex; + this.baseUrl = _package.baseUrl || ''; + this.length = this.items.length; - this.items.forEach(function(item, index){ - var href, url; - var manifestItem = this.manifest[item.idref]; - var spineItem; + this.items.forEach(function(item, index){ + var href, url; + var manifestItem = this.manifest[item.idref]; + var spineItem; - item.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.idref); + item.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.idref); - if(manifestItem) { - item.href = manifestItem.href; - item.url = this.baseUrl + item.href; + if(manifestItem) { + item.href = manifestItem.href; + item.url = this.baseUrl + item.href; - if(manifestItem.properties.length){ - item.properties.push.apply(item.properties, manifestItem.properties); - } - } + if(manifestItem.properties.length){ + item.properties.push.apply(item.properties, manifestItem.properties); + } + } - // if(index > 0) { - item.prev = function(){ return this.get(index-1); }.bind(this); - // } + // if(index > 0) { + item.prev = function(){ return this.get(index-1); }.bind(this); + // } - // if(index+1 < this.items.length) { - item.next = function(){ return this.get(index+1); }.bind(this); - // } + // if(index+1 < this.items.length) { + item.next = function(){ return this.get(index+1); }.bind(this); + // } - spineItem = new Section(item, this.hooks); + spineItem = new Section(item, this.hooks); - this.append(spineItem); + this.append(spineItem); - }.bind(this)); + }.bind(this)); - this.loaded = true; + this.loaded = true; }; // book.spine.get(); @@ -11720,47 +11721,47 @@ Spine.prototype.load = function(_package) { // book.spine.get("chap1.html"); // book.spine.get("#id1234"); Spine.prototype.get = function(target) { - var index = 0; + var index = 0; - if(this.epubcfi.isCfiString(target)) { - cfi = new EpubCFI(target); - index = cfi.spinePos; - } else if(target && (typeof target === "number" || isNaN(target) === false)){ - index = target; - } else if(target && target.indexOf("#") === 0) { - index = this.spineById[target.substring(1)]; - } else if(target) { - // Remove fragments - target = target.split("#")[0]; - index = this.spineByHref[target]; - } + if(this.epubcfi.isCfiString(target)) { + cfi = new EpubCFI(target); + index = cfi.spinePos; + } else if(target && (typeof target === "number" || isNaN(target) === false)){ + index = target; + } else if(target && target.indexOf("#") === 0) { + index = this.spineById[target.substring(1)]; + } else if(target) { + // Remove fragments + target = target.split("#")[0]; + index = this.spineByHref[target]; + } - return this.spineItems[index] || null; + return this.spineItems[index] || null; }; Spine.prototype.append = function(section) { - var index = this.spineItems.length; - section.index = index; + var index = this.spineItems.length; + section.index = index; - this.spineItems.push(section); + this.spineItems.push(section); - this.spineByHref[section.href] = index; - this.spineById[section.idref] = index; + this.spineByHref[section.href] = index; + this.spineById[section.idref] = index; - return index; + return index; }; Spine.prototype.prepend = function(section) { - var index = this.spineItems.unshift(section); - this.spineByHref[section.href] = 0; - this.spineById[section.idref] = 0; + var index = this.spineItems.unshift(section); + this.spineByHref[section.href] = 0; + this.spineById[section.idref] = 0; - // Re-index - this.spineItems.forEach(function(item, index){ - item.index = index; - }); + // Re-index + this.spineItems.forEach(function(item, index){ + item.index = index; + }); - return 0; + return 0; }; Spine.prototype.insert = function(section, index) { @@ -11768,14 +11769,14 @@ Spine.prototype.insert = function(section, index) { }; Spine.prototype.remove = function(section) { - var index = this.spineItems.indexOf(section); + var index = this.spineItems.indexOf(section); - if(index > -1) { - delete this.spineByHref[section.href]; - delete this.spineById[section.idref]; + if(index > -1) { + delete this.spineByHref[section.href]; + delete this.spineById[section.idref]; - return this.spineItems.splice(index, 1); - } + return this.spineItems.splice(index, 1); + } }; Spine.prototype.each = function() { @@ -11807,7 +11808,7 @@ Stage.prototype.create = function(options){ var height = options.height;// !== false ? options.height : "100%"; var width = options.width;// !== false ? options.width : "100%"; var overflow = options.overflow || false; - var axis = options.axis || "vertical"; + var axis = options.axis || "vertical"; if(options.height && core.isNumber(options.height)) { height = options.height + "px"; @@ -12010,7 +12011,7 @@ Stage.prototype.addStyleRules = function(selector, rulesArray){ } }) - this.sheet.insertRule(scope + selector + " {" + rules + "}", 0); + this.sheet.insertRule(scope + selector + " {" + rules + "}", 0); } @@ -12026,100 +12027,100 @@ var mime = require('../libs/mime/mime'); function Unarchive() { - this.checkRequirements(); - this.urlCache = {}; + this.checkRequirements(); + this.urlCache = {}; } Unarchive.prototype.checkRequirements = function(callback){ - try { - if (typeof JSZip !== 'undefined') { - this.zip = new JSZip(); - } else { - JSZip = require('jszip'); - this.zip = new JSZip(); - } - } catch (e) { - console.error("JSZip lib not loaded"); - } + try { + if (typeof JSZip !== 'undefined') { + this.zip = new JSZip(); + } else { + JSZip = require('jszip'); + this.zip = new JSZip(); + } + } catch (e) { + console.error("JSZip lib not loaded"); + } }; Unarchive.prototype.open = function(zipUrl, isBase64){ if (zipUrl instanceof ArrayBuffer || isBase64) { - return this.zip.loadAsync(zipUrl, {"base64": isBase64}); + return this.zip.loadAsync(zipUrl, {"base64": isBase64}); } else { return request(zipUrl, "binary") - .then(function(data){ - return this.zip.loadAsync(data); - }.bind(this)); + .then(function(data){ + return this.zip.loadAsync(data); + }.bind(this)); } }; Unarchive.prototype.request = function(url, type){ - var deferred = new RSVP.defer(); - var response; - var r; + var deferred = new RSVP.defer(); + var response; + var r; - // If type isn't set, determine it from the file extension + // If type isn't set, determine it from the file extension if(!type) { uri = URI(url); type = uri.suffix(); } - if(type == 'blob'){ - response = this.getBlob(url); - } else { - response = this.getText(url); - } + if(type == 'blob'){ + response = this.getBlob(url); + } else { + response = this.getText(url); + } - if (response) { - response.then(function (r) { - result = this.handleResponse(r, type); - deferred.resolve(result); - }.bind(this)); - } else { - deferred.reject({ - message : "File not found in the epub: " + url, - stack : new Error().stack - }); - } - return deferred.promise; + if (response) { + response.then(function (r) { + result = this.handleResponse(r, type); + deferred.resolve(result); + }.bind(this)); + } else { + deferred.reject({ + message : "File not found in the epub: " + url, + stack : new Error().stack + }); + } + return deferred.promise; }; Unarchive.prototype.handleResponse = function(response, type){ - var r; + var r; - if(type == "json") { - r = JSON.parse(response); - } - else - if(core.isXml(type)) { - r = core.parse(response, "text/xml"); + if(type == "json") { + r = JSON.parse(response); } - else + else + if(core.isXml(type)) { + r = core.parse(response, "text/xml"); + } + else if(type == 'xhtml') { - r = core.parse(response, "application/xhtml+xml"); + r = core.parse(response, "application/xhtml+xml"); } - else + else if(type == 'html' || type == 'htm') { - r = core.parse(response, "text/html"); - } else { - r = response; - } + r = core.parse(response, "text/html"); + } else { + r = response; + } - return r; + return r; }; Unarchive.prototype.getBlob = function(url, _mimeType){ var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash var entry = this.zip.file(decodededUrl); - var mimeType; + var mimeType; if(entry) { - mimeType = _mimeType || mime.lookup(entry.name); - return entry.async("uint8array").then(function(uint8array) { - return new Blob([uint8array], {type : mimeType}); - }); + mimeType = _mimeType || mime.lookup(entry.name); + return entry.async("uint8array").then(function(uint8array) { + return new Blob([uint8array], {type : mimeType}); + }); } }; @@ -12128,22 +12129,22 @@ Unarchive.prototype.getText = function(url, encoding){ var entry = this.zip.file(decodededUrl); if(entry) { - return entry.async("string").then(function(text) { - return text; - }); + return entry.async("string").then(function(text) { + return text; + }); } }; Unarchive.prototype.getBase64 = function(url, _mimeType){ var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash var entry = this.zip.file(decodededUrl); - var mimeType; + var mimeType; if(entry) { - mimeType = _mimeType || mime.lookup(entry.name); - return entry.async("base64").then(function(data) { - return "data:" + mimeType + ";base64," + data; - }); + mimeType = _mimeType || mime.lookup(entry.name); + return entry.async("base64").then(function(data) { + return "data:" + mimeType + ";base64," + data; + }); } }; @@ -12151,51 +12152,51 @@ Unarchive.prototype.createUrl = function(url, options){ var deferred = new RSVP.defer(); var _URL = window.URL || window.webkitURL || window.mozURL; var tempUrl; - var blob; + var blob; var response; - var useBase64 = options && options.base64; + var useBase64 = options && options.base64; if(url in this.urlCache) { deferred.resolve(this.urlCache[url]); return deferred.promise; } - if (useBase64) { - response = this.getBase64(url); + if (useBase64) { + response = this.getBase64(url); - if (response) { - response.then(function(tempUrl) { + if (response) { + response.then(function(tempUrl) { - this.urlCache[url] = tempUrl; - deferred.resolve(tempUrl); + this.urlCache[url] = tempUrl; + deferred.resolve(tempUrl); - }.bind(this)); + }.bind(this)); - } + } - } else { + } else { - response = this.getBlob(url); + response = this.getBlob(url); - if (response) { - response.then(function(blob) { + if (response) { + response.then(function(blob) { - tempUrl = _URL.createObjectURL(blob); - this.urlCache[url] = tempUrl; - deferred.resolve(tempUrl); + tempUrl = _URL.createObjectURL(blob); + this.urlCache[url] = tempUrl; + deferred.resolve(tempUrl); - }.bind(this)); + }.bind(this)); - } - } + } + } - if (!response) { - deferred.reject({ - message : "File not found in the epub: " + url, - stack : new Error().stack - }); - } + if (!response) { + deferred.reject({ + message : "File not found in the epub: " + url, + stack : new Error().stack + }); + } return deferred.promise; }; @@ -12210,10 +12211,10 @@ module.exports = Unarchive; },{"../libs/mime/mime":1,"./core":10,"./request":23,"jszip":"jszip","rsvp":5,"urijs":7}],28:[function(require,module,exports){ function Views(container) { - this.container = container; - this._views = []; - this.length = 0; - this.hidden = false; + this.container = container; + this._views = []; + this.length = 0; + this.hidden = false; }; Views.prototype.all = function() { @@ -12242,35 +12243,35 @@ Views.prototype.get = function(i) { Views.prototype.append = function(view){ this._views.push(view); - if(this.container){ - this.container.appendChild(view.element); - } - this.length++; - return view; + if(this.container){ + this.container.appendChild(view.element); + } + this.length++; + return view; }; Views.prototype.prepend = function(view){ this._views.unshift(view); - if(this.container){ - this.container.insertBefore(view.element, this.container.firstChild); - } - this.length++; - return view; + if(this.container){ + this.container.insertBefore(view.element, this.container.firstChild); + } + this.length++; + return view; }; Views.prototype.insert = function(view, index) { this._views.splice(index, 0, view); - if(this.container){ - if(index < this.container.children.length){ - this.container.insertBefore(view.element, this.container.children[index]); - } else { - this.container.appendChild(view.element); - } - } + if(this.container){ + if(index < this.container.children.length){ + this.container.insertBefore(view.element, this.container.children[index]); + } else { + this.container.appendChild(view.element); + } + } - this.length++; - return view; + this.length++; + return view; }; Views.prototype.remove = function(view) { @@ -12283,7 +12284,7 @@ Views.prototype.remove = function(view) { this.destroy(view); - this.length--; + this.length--; }; Views.prototype.destroy = function(view) { @@ -12293,9 +12294,9 @@ Views.prototype.destroy = function(view) { view.destroy(); } - if(this.container){ - this.container.removeChild(view.element); - } + if(this.container){ + this.container.removeChild(view.element); + } view = null; }; @@ -12307,72 +12308,72 @@ Views.prototype.each = function() { Views.prototype.clear = function(){ // Remove all views - var view; - var len = this.length; + var view; + var len = this.length; - if(!this.length) return; + if(!this.length) return; - for (var i = 0; i < len; i++) { - view = this._views[i]; + for (var i = 0; i < len; i++) { + view = this._views[i]; this.destroy(view); - } + } - this._views = []; - this.length = 0; + this._views = []; + this.length = 0; }; Views.prototype.find = function(section){ - var view; - var len = this.length; + var view; + var len = this.length; - for (var i = 0; i < len; i++) { - view = this._views[i]; + for (var i = 0; i < len; i++) { + view = this._views[i]; if(view.displayed && view.section.index == section.index) { return view; } - } + } }; Views.prototype.displayed = function(){ - var displayed = []; - var view; - var len = this.length; + var displayed = []; + var view; + var len = this.length; - for (var i = 0; i < len; i++) { - view = this._views[i]; - if(view.displayed){ - displayed.push(view); - } - } - return displayed; + for (var i = 0; i < len; i++) { + view = this._views[i]; + if(view.displayed){ + displayed.push(view); + } + } + return displayed; }; Views.prototype.show = function(){ - var view; - var len = this.length; + var view; + var len = this.length; - for (var i = 0; i < len; i++) { - view = this._views[i]; - if(view.displayed){ - view.show(); - } - } - this.hidden = false; + for (var i = 0; i < len; i++) { + view = this._views[i]; + if(view.displayed){ + view.show(); + } + } + this.hidden = false; }; Views.prototype.hide = function(){ - var view; - var len = this.length; + var view; + var len = this.length; - for (var i = 0; i < len; i++) { - view = this._views[i]; - if(view.displayed){ - view.hide(); - } - } - this.hidden = true; + for (var i = 0; i < len; i++) { + view = this._views[i]; + if(view.displayed){ + view.hide(); + } + } + this.hidden = true; }; module.exports = Views; @@ -12384,110 +12385,110 @@ var EpubCFI = require('../epubcfi'); var Contents = require('../contents'); function IframeView(section, options) { - this.settings = core.extend({ - ignoreClass : '', - axis: 'vertical', - width: 0, - height: 0, - layout: undefined, - globalLayoutProperties: {}, - }, options || {}); + this.settings = core.extend({ + ignoreClass : '', + axis: 'vertical', + width: 0, + height: 0, + layout: undefined, + globalLayoutProperties: {}, + }, options || {}); - this.id = "epubjs-view-" + core.uuid(); - this.section = section; - this.index = section.index; + this.id = "epubjs-view-" + core.uuid(); + this.section = section; + this.index = section.index; - this.element = this.container(this.settings.axis); + this.element = this.container(this.settings.axis); - this.added = false; - this.displayed = false; - this.rendered = false; + this.added = false; + this.displayed = false; + this.rendered = false; - this.width = this.settings.width; - this.height = this.settings.height; + this.width = this.settings.width; + this.height = this.settings.height; - this.fixedWidth = 0; - this.fixedHeight = 0; + this.fixedWidth = 0; + this.fixedHeight = 0; - // Blank Cfi for Parsing - this.epubcfi = new EpubCFI(); + // Blank Cfi for Parsing + this.epubcfi = new EpubCFI(); - this.layout = this.settings.layout; - // Dom events to listen for - // this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"]; + this.layout = this.settings.layout; + // Dom events to listen for + // this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"]; }; IframeView.prototype.container = function(axis) { - var element = document.createElement('div'); + var element = document.createElement('div'); - element.classList.add("epub-view"); + element.classList.add("epub-view"); - // this.element.style.minHeight = "100px"; - element.style.height = "0px"; - element.style.width = "0px"; - element.style.overflow = "hidden"; + // this.element.style.minHeight = "100px"; + element.style.height = "0px"; + element.style.width = "0px"; + element.style.overflow = "hidden"; - if(axis && axis == "horizontal"){ - element.style.display = "inline-block"; - } else { - element.style.display = "block"; - } + if(axis && axis == "horizontal"){ + element.style.display = "inline-block"; + } else { + element.style.display = "block"; + } - return element; + return element; }; IframeView.prototype.create = function() { - if(this.iframe) { - return this.iframe; - } + if(this.iframe) { + return this.iframe; + } - if(!this.element) { - this.element = this.createContainer(); - } + if(!this.element) { + this.element = this.createContainer(); + } - this.iframe = document.createElement('iframe'); - this.iframe.id = this.id; - this.iframe.scrolling = "no"; // Might need to be removed: breaks ios width calculations - this.iframe.style.overflow = "hidden"; - this.iframe.seamless = "seamless"; - // Back up if seamless isn't supported - this.iframe.style.border = "none"; + this.iframe = document.createElement('iframe'); + this.iframe.id = this.id; + this.iframe.scrolling = "no"; // Might need to be removed: breaks ios width calculations + this.iframe.style.overflow = "hidden"; + this.iframe.seamless = "seamless"; + // Back up if seamless isn't supported + this.iframe.style.border = "none"; - this.resizing = true; + this.resizing = true; - // this.iframe.style.display = "none"; - this.element.style.visibility = "hidden"; - this.iframe.style.visibility = "hidden"; + // this.iframe.style.display = "none"; + this.element.style.visibility = "hidden"; + this.iframe.style.visibility = "hidden"; - this.iframe.style.width = "0"; - this.iframe.style.height = "0"; - this._width = 0; - this._height = 0; + this.iframe.style.width = "0"; + this.iframe.style.height = "0"; + this._width = 0; + this._height = 0; - this.element.appendChild(this.iframe); - this.added = true; + this.element.appendChild(this.iframe); + this.added = true; - this.elementBounds = core.bounds(this.element); + this.elementBounds = core.bounds(this.element); - // if(width || height){ - // this.resize(width, height); - // } else if(this.width && this.height){ - // this.resize(this.width, this.height); - // } else { - // this.iframeBounds = core.bounds(this.iframe); - // } + // if(width || height){ + // this.resize(width, height); + // } else if(this.width && this.height){ + // this.resize(this.width, this.height); + // } else { + // this.iframeBounds = core.bounds(this.iframe); + // } - // Firefox has trouble with baseURI and srcdoc - // TODO: Disable for now in firefox + // Firefox has trouble with baseURI and srcdoc + // TODO: Disable for now in firefox - if(!!("srcdoc" in this.iframe)) { - this.supportsSrcdoc = true; - } else { - this.supportsSrcdoc = false; - } + if(!!("srcdoc" in this.iframe)) { + this.supportsSrcdoc = true; + } else { + this.supportsSrcdoc = false; + } - return this.iframe; + return this.iframe; }; IframeView.prototype.render = function(request, show) { @@ -12496,11 +12497,11 @@ IframeView.prototype.render = function(request, show) { this.create(); // Fit to size of the container, apply padding - this.size(); + this.size(); - if(!this.sectionRender) { - this.sectionRender = this.section.render(request); - } + if(!this.sectionRender) { + this.sectionRender = this.section.render(request); + } // Render Chain return this.sectionRender @@ -12522,14 +12523,14 @@ IframeView.prototype.render = function(request, show) { // }.bind(this)) .then(function(){ - // apply the layout function to the contents - this.settings.layout.format(this.contents); + // apply the layout function to the contents + this.settings.layout.format(this.contents); - // Expand the iframe to the full size of the content - this.expand(); + // Expand the iframe to the full size of the content + this.expand(); - // Listen for events that require an expansion of the iframe - this.addListeners(); + // Listen for events that require an expansion of the iframe + this.addListeners(); if(show !== false) { //this.q.enqueue(function(view){ @@ -12549,12 +12550,12 @@ IframeView.prototype.render = function(request, show) { // Determine locks base on settings IframeView.prototype.size = function(_width, _height) { - var width = _width || this.settings.width; - var height = _height || this.settings.height; + var width = _width || this.settings.width; + var height = _height || this.settings.height; - if(this.layout.name === "pre-paginated") { - this.lock("both", width, height); - } else if(this.settings.axis === "horizontal") { + if(this.layout.name === "pre-paginated") { + this.lock("both", width, height); + } else if(this.settings.axis === "horizontal") { this.lock("height", width, height); } else { this.lock("width", width, height); @@ -12564,41 +12565,41 @@ IframeView.prototype.size = function(_width, _height) { // Lock an axis to element dimensions, taking borders into account IframeView.prototype.lock = function(what, width, height) { - var elBorders = core.borders(this.element); - var iframeBorders; + var elBorders = core.borders(this.element); + var iframeBorders; - if(this.iframe) { - iframeBorders = core.borders(this.iframe); - } else { - iframeBorders = {width: 0, height: 0}; - } + if(this.iframe) { + iframeBorders = core.borders(this.iframe); + } else { + iframeBorders = {width: 0, height: 0}; + } - if(what == "width" && core.isNumber(width)){ - this.lockedWidth = width - elBorders.width - iframeBorders.width; - this.resize(this.lockedWidth, width); // width keeps ratio correct - } + if(what == "width" && core.isNumber(width)){ + this.lockedWidth = width - elBorders.width - iframeBorders.width; + this.resize(this.lockedWidth, width); // width keeps ratio correct + } - if(what == "height" && core.isNumber(height)){ - this.lockedHeight = height - elBorders.height - iframeBorders.height; - this.resize(width, this.lockedHeight); - } + if(what == "height" && core.isNumber(height)){ + this.lockedHeight = height - elBorders.height - iframeBorders.height; + this.resize(width, this.lockedHeight); + } - if(what === "both" && - core.isNumber(width) && - core.isNumber(height)){ + if(what === "both" && + core.isNumber(width) && + core.isNumber(height)){ - this.lockedWidth = width - elBorders.width - iframeBorders.width; - this.lockedHeight = height - elBorders.height - iframeBorders.height; + this.lockedWidth = width - elBorders.width - iframeBorders.width; + this.lockedHeight = height - elBorders.height - iframeBorders.height; - this.resize(this.lockedWidth, this.lockedHeight); - } + this.resize(this.lockedWidth, this.lockedHeight); + } - if(this.displayed && this.iframe) { + if(this.displayed && this.iframe) { - // this.contents.layout(); - this.expand(); + // this.contents.layout(); + this.expand(); - } + } @@ -12606,209 +12607,209 @@ IframeView.prototype.lock = function(what, width, height) { // Resize a single axis based on content dimensions IframeView.prototype.expand = function(force) { - var width = this.lockedWidth; - var height = this.lockedHeight; - var columns; + var width = this.lockedWidth; + var height = this.lockedHeight; + var columns; - var textWidth, textHeight; + var textWidth, textHeight; - if(!this.iframe || this._expanding) return; + if(!this.iframe || this._expanding) return; - this._expanding = true; + this._expanding = true; - // Expand Horizontally - // if(height && !width) { - if(this.settings.axis === "horizontal") { - // Get the width of the text - textWidth = this.contents.textWidth(); - // Check if the textWidth has changed - if(textWidth != this._textWidth){ - // Get the contentWidth by resizing the iframe - // Check with a min reset of the textWidth - width = this.contentWidth(textWidth); + // Expand Horizontally + // if(height && !width) { + if(this.settings.axis === "horizontal") { + // Get the width of the text + textWidth = this.contents.textWidth(); + // Check if the textWidth has changed + if(textWidth != this._textWidth){ + // Get the contentWidth by resizing the iframe + // Check with a min reset of the textWidth + width = this.contentWidth(textWidth); - columns = Math.ceil(width / (this.settings.layout.columnWidth + this.settings.layout.gap)); + columns = Math.ceil(width / (this.settings.layout.columnWidth + this.settings.layout.gap)); - if ( this.settings.layout.divisor > 1 && - this.settings.layout.name === "reflowable" && - (columns % 2 > 0)) { - // add a blank page - width += this.settings.layout.gap + this.settings.layout.columnWidth; - } + if ( this.settings.layout.divisor > 1 && + this.settings.layout.name === "reflowable" && + (columns % 2 > 0)) { + // add a blank page + width += this.settings.layout.gap + this.settings.layout.columnWidth; + } - // Save the textWdith - this._textWidth = textWidth; - // Save the contentWidth - this._contentWidth = width; - } else { - // Otherwise assume content height hasn't changed - width = this._contentWidth; - } - } // Expand Vertically - else if(this.settings.axis === "vertical") { - textHeight = this.contents.textHeight(); - if(textHeight != this._textHeight){ - height = this.contentHeight(textHeight); - this._textHeight = textHeight; - this._contentHeight = height; - } else { - height = this._contentHeight; - } + // Save the textWdith + this._textWidth = textWidth; + // Save the contentWidth + this._contentWidth = width; + } else { + // Otherwise assume content height hasn't changed + width = this._contentWidth; + } + } // Expand Vertically + else if(this.settings.axis === "vertical") { + textHeight = this.contents.textHeight(); + if(textHeight != this._textHeight){ + height = this.contentHeight(textHeight); + this._textHeight = textHeight; + this._contentHeight = height; + } else { + height = this._contentHeight; + } - } + } - // Only Resize if dimensions have changed or - // if Frame is still hidden, so needs reframing - if(this._needsReframe || width != this._width || height != this._height){ - this.resize(width, height); - } + // Only Resize if dimensions have changed or + // if Frame is still hidden, so needs reframing + if(this._needsReframe || width != this._width || height != this._height){ + this.resize(width, height); + } - this._expanding = false; + this._expanding = false; }; IframeView.prototype.contentWidth = function(min) { - var prev; - var width; + var prev; + var width; - // Save previous width - prev = this.iframe.style.width; - // Set the iframe size to min, width will only ever be greater - // Will preserve the aspect ratio - this.iframe.style.width = (min || 0) + "px"; - // Get the scroll overflow width - width = this.contents.scrollWidth(); - // Reset iframe size back - this.iframe.style.width = prev; - return width; + // Save previous width + prev = this.iframe.style.width; + // Set the iframe size to min, width will only ever be greater + // Will preserve the aspect ratio + this.iframe.style.width = (min || 0) + "px"; + // Get the scroll overflow width + width = this.contents.scrollWidth(); + // Reset iframe size back + this.iframe.style.width = prev; + return width; }; IframeView.prototype.contentHeight = function(min) { - var prev; - var height; + var prev; + var height; - prev = this.iframe.style.height; - this.iframe.style.height = (min || 0) + "px"; - height = this.contents.scrollHeight(); + prev = this.iframe.style.height; + this.iframe.style.height = (min || 0) + "px"; + height = this.contents.scrollHeight(); - this.iframe.style.height = prev; - return height; + this.iframe.style.height = prev; + return height; }; IframeView.prototype.resize = function(width, height) { - if(!this.iframe) return; + if(!this.iframe) return; - if(core.isNumber(width)){ - this.iframe.style.width = width + "px"; - this._width = width; - } + if(core.isNumber(width)){ + this.iframe.style.width = width + "px"; + this._width = width; + } - if(core.isNumber(height)){ - this.iframe.style.height = height + "px"; - this._height = height; - } + if(core.isNumber(height)){ + this.iframe.style.height = height + "px"; + this._height = height; + } - this.iframeBounds = core.bounds(this.iframe); + this.iframeBounds = core.bounds(this.iframe); - this.reframe(this.iframeBounds.width, this.iframeBounds.height); + this.reframe(this.iframeBounds.width, this.iframeBounds.height); }; IframeView.prototype.reframe = function(width, height) { - var size; + var size; - // if(!this.displayed) { - // this._needsReframe = true; - // return; - // } - if(core.isNumber(width)){ - this.element.style.width = width + "px"; - } + // if(!this.displayed) { + // this._needsReframe = true; + // return; + // } + if(core.isNumber(width)){ + this.element.style.width = width + "px"; + } - if(core.isNumber(height)){ - this.element.style.height = height + "px"; - } + if(core.isNumber(height)){ + this.element.style.height = height + "px"; + } - this.prevBounds = this.elementBounds; + this.prevBounds = this.elementBounds; - this.elementBounds = core.bounds(this.element); + this.elementBounds = core.bounds(this.element); - size = { - width: this.elementBounds.width, - height: this.elementBounds.height, - widthDelta: this.elementBounds.width - this.prevBounds.width, - heightDelta: this.elementBounds.height - this.prevBounds.height, - }; + size = { + width: this.elementBounds.width, + height: this.elementBounds.height, + widthDelta: this.elementBounds.width - this.prevBounds.width, + heightDelta: this.elementBounds.height - this.prevBounds.height, + }; - this.onResize(this, size); + this.onResize(this, size); - this.trigger("resized", size); + this.trigger("resized", size); }; IframeView.prototype.load = function(contents) { - var loading = new RSVP.defer(); - var loaded = loading.promise; + var loading = new RSVP.defer(); + var loaded = loading.promise; - if(!this.iframe) { - loading.reject(new Error("No Iframe Available")); - return loaded; - } + if(!this.iframe) { + loading.reject(new Error("No Iframe Available")); + return loaded; + } - this.iframe.onload = function(event) { + this.iframe.onload = function(event) { - this.onLoad(event, loading); + this.onLoad(event, loading); - }.bind(this); + }.bind(this); - if(this.supportsSrcdoc){ - this.iframe.srcdoc = contents; - } else { + if(this.supportsSrcdoc){ + this.iframe.srcdoc = contents; + } else { - this.document = this.iframe.contentDocument; + this.document = this.iframe.contentDocument; - if(!this.document) { - loading.reject(new Error("No Document Available")); - return loaded; - } + if(!this.document) { + loading.reject(new Error("No Document Available")); + return loaded; + } - this.iframe.contentDocument.open(); - this.iframe.contentDocument.write(contents); - this.iframe.contentDocument.close(); + this.iframe.contentDocument.open(); + this.iframe.contentDocument.write(contents); + this.iframe.contentDocument.close(); - } + } - return loaded; + return loaded; }; IframeView.prototype.onLoad = function(event, promise) { - this.window = this.iframe.contentWindow; - this.document = this.iframe.contentDocument; + this.window = this.iframe.contentWindow; + this.document = this.iframe.contentDocument; - this.contents = new Contents(this.document, this.document.body, this.section.cfiBase); + this.contents = new Contents(this.document, this.document.body, this.section.cfiBase); - this.rendering = false; + this.rendering = false; - var link = this.document.querySelector("link[rel='canonical']"); - if (link) { - link.setAttribute("href", this.section.url); - } else { - link = this.document.createElement("link"); - link.setAttribute("rel", "canonical"); - link.setAttribute("href", this.section.url); - this.document.querySelector("head").appendChild(link); - } + var link = this.document.querySelector("link[rel='canonical']"); + if (link) { + link.setAttribute("href", this.section.url); + } else { + link = this.document.createElement("link"); + link.setAttribute("rel", "canonical"); + link.setAttribute("href", this.section.url); + this.document.querySelector("head").appendChild(link); + } - this.contents.on("expand", function () { - if(this.displayed && this.iframe) { - this.expand(); - } - }); + this.contents.on("expand", function () { + if(this.displayed && this.iframe) { + this.expand(); + } + }); - promise.resolve(this.contents); + promise.resolve(this.contents); }; @@ -12835,118 +12836,118 @@ IframeView.prototype.onLoad = function(event, promise) { // }; IframeView.prototype.setLayout = function(layout) { - this.layout = layout; + this.layout = layout; }; IframeView.prototype.setAxis = function(axis) { - this.settings.axis = axis; + this.settings.axis = axis; }; IframeView.prototype.resizeListenters = function() { - // Test size again - clearTimeout(this.expanding); - this.expanding = setTimeout(this.expand.bind(this), 350); + // Test size again + clearTimeout(this.expanding); + this.expanding = setTimeout(this.expand.bind(this), 350); }; IframeView.prototype.addListeners = function() { - //TODO: Add content listeners for expanding + //TODO: Add content listeners for expanding }; IframeView.prototype.removeListeners = function(layoutFunc) { - //TODO: remove content listeners for expanding + //TODO: remove content listeners for expanding }; IframeView.prototype.display = function(request) { - var displayed = new RSVP.defer(); + var displayed = new RSVP.defer(); - if (!this.displayed) { + if (!this.displayed) { - this.render(request).then(function () { + this.render(request).then(function () { - this.trigger("displayed", this); - this.onDisplayed(this); + this.trigger("displayed", this); + this.onDisplayed(this); - this.displayed = true; - displayed.resolve(this); + this.displayed = true; + displayed.resolve(this); - }.bind(this)); + }.bind(this)); - } else { - displayed.resolve(this); - } + } else { + displayed.resolve(this); + } - return displayed.promise; + return displayed.promise; }; IframeView.prototype.show = function() { - this.element.style.visibility = "visible"; + this.element.style.visibility = "visible"; - if(this.iframe){ - this.iframe.style.visibility = "visible"; - } + if(this.iframe){ + this.iframe.style.visibility = "visible"; + } - this.trigger("shown", this); + this.trigger("shown", this); }; IframeView.prototype.hide = function() { - // this.iframe.style.display = "none"; - this.element.style.visibility = "hidden"; - this.iframe.style.visibility = "hidden"; + // this.iframe.style.display = "none"; + this.element.style.visibility = "hidden"; + this.iframe.style.visibility = "hidden"; - this.stopExpanding = true; - this.trigger("hidden", this); + this.stopExpanding = true; + this.trigger("hidden", this); }; IframeView.prototype.position = function() { - return this.element.getBoundingClientRect(); + return this.element.getBoundingClientRect(); }; IframeView.prototype.locationOf = function(target) { - var parentPos = this.iframe.getBoundingClientRect(); - var targetPos = this.contents.locationOf(target, this.settings.ignoreClass); + var parentPos = this.iframe.getBoundingClientRect(); + var targetPos = this.contents.locationOf(target, this.settings.ignoreClass); - return { - "left": window.scrollX + parentPos.left + targetPos.left, - "top": window.scrollY + parentPos.top + targetPos.top - }; + return { + "left": window.scrollX + parentPos.left + targetPos.left, + "top": window.scrollY + parentPos.top + targetPos.top + }; }; IframeView.prototype.onDisplayed = function(view) { - // Stub, override with a custom functions + // Stub, override with a custom functions }; IframeView.prototype.onResize = function(view, e) { - // Stub, override with a custom functions + // Stub, override with a custom functions }; IframeView.prototype.bounds = function() { - if(!this.elementBounds) { - this.elementBounds = core.bounds(this.element); - } - return this.elementBounds; + if(!this.elementBounds) { + this.elementBounds = core.bounds(this.element); + } + return this.elementBounds; }; IframeView.prototype.destroy = function() { - if(this.displayed){ - this.displayed = false; + if(this.displayed){ + this.displayed = false; - this.removeListeners(); + this.removeListeners(); - this.stopExpanding = true; - this.element.removeChild(this.iframe); - this.displayed = false; - this.iframe = null; + this.stopExpanding = true; + this.element.removeChild(this.iframe); + this.displayed = false; + this.iframe = null; - this._textWidth = null; - this._textHeight = null; - this._width = null; - this._height = null; - } - // this.element.style.height = "0px"; - // this.element.style.width = "0px"; + this._textWidth = null; + this._textHeight = null; + this._width = null; + this._height = null; + } + // this.element.style.height = "0px"; + // this.element.style.width = "0px"; }; RSVP.EventTarget.mixin(IframeView.prototype); @@ -12975,7 +12976,7 @@ ePub.ViewManagers = {}; ePub.Views = {}; ePub.register = { manager : function(name, manager){ - return ePub.ViewManagers[name] = manager; + return ePub.ViewManagers[name] = manager; }, view : function(name, view){ return ePub.Views[name] = view; diff --git a/dist/epub.js.map b/dist/epub.js.map index 0fb819b..cad394c 100644 --- a/dist/epub.js.map +++ b/dist/epub.js.map @@ -1 +1 @@ -{"version":3,"sources":["node_modules/browser-pack/_prelude.js","libs/mime/mime.js","node_modules/base64-js/index.js","node_modules/browserify/lib/_empty.js","node_modules/process/browser.js","node_modules/rsvp/dist/rsvp.js","node_modules/urijs/src/SecondLevelDomains.js","node_modules/urijs/src/URI.js","src/book.js","src/contents.js","src/core.js","src/epubcfi.js","src/hook.js","src/layout.js","src/locations.js","src/managers/continuous.js","src/managers/single.js","src/mapping.js","src/navigation.js","src/parser.js","src/queue.js","src/rendition.js","src/replacements.js","src/request.js","src/section.js","src/spine.js","src/stage.js","src/unarchive.js","src/views.js","src/views/iframe.js","src/epub.js"],"names":[],"mappings":"AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClHA;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;ACh8EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClqEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3VA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvpBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5hBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC16BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxqBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACthBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3eA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClkBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9jBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"epub.js","sourceRoot":"/source/","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o 0) {\n throw new Error('Invalid string. Length must be a multiple of 4')\n }\n\n // the number of equal signs (place holders)\n // if there are two placeholders, than the two characters before it\n // represent one byte\n // if there is only one, then the three characters before it represent 2 bytes\n // this is just a cheap hack to not do indexOf twice\n return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0\n}\n\nfunction byteLength (b64) {\n // base64 is 4/3 + up to two characters of the original data\n return b64.length * 3 / 4 - placeHoldersCount(b64)\n}\n\nfunction toByteArray (b64) {\n var i, j, l, tmp, placeHolders, arr\n var len = b64.length\n placeHolders = placeHoldersCount(b64)\n\n arr = new Arr(len * 3 / 4 - placeHolders)\n\n // if there are placeholders, only get up to the last complete 4 chars\n l = placeHolders > 0 ? len - 4 : len\n\n var L = 0\n\n for (i = 0, j = 0; i < l; i += 4, j += 3) {\n tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]\n arr[L++] = (tmp >> 16) & 0xFF\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n if (placeHolders === 2) {\n tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)\n arr[L++] = tmp & 0xFF\n } else if (placeHolders === 1) {\n tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n return arr\n}\n\nfunction tripletToBase64 (num) {\n return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n var tmp\n var output = []\n for (var i = start; i < end; i += 3) {\n tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n output.push(tripletToBase64(tmp))\n }\n return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n var tmp\n var len = uint8.length\n var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n var output = ''\n var parts = []\n var maxChunkLength = 16383 // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1]\n output += lookup[tmp >> 2]\n output += lookup[(tmp << 4) & 0x3F]\n output += '=='\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + (uint8[len - 1])\n output += lookup[tmp >> 10]\n output += lookup[(tmp >> 4) & 0x3F]\n output += lookup[(tmp << 2) & 0x3F]\n output += '='\n }\n\n parts.push(output)\n\n return parts.join('')\n}\n","","// shim for using process in browser\nvar process = module.exports = {};\n\n// cached from whatever global is present so that test runners that stub it\n// don't break things. But we need to wrap it in a try catch in case it is\n// wrapped in strict mode code which doesn't define any globals. It's inside a\n// function because try/catches deoptimize in certain engines.\n\nvar cachedSetTimeout;\nvar cachedClearTimeout;\n\nfunction defaultSetTimout() {\n throw new Error('setTimeout has not been defined');\n}\nfunction defaultClearTimeout () {\n throw new Error('clearTimeout has not been defined');\n}\n(function () {\n try {\n if (typeof setTimeout === 'function') {\n cachedSetTimeout = setTimeout;\n } else {\n cachedSetTimeout = defaultSetTimout;\n }\n } catch (e) {\n cachedSetTimeout = defaultSetTimout;\n }\n try {\n if (typeof clearTimeout === 'function') {\n cachedClearTimeout = clearTimeout;\n } else {\n cachedClearTimeout = defaultClearTimeout;\n }\n } catch (e) {\n cachedClearTimeout = defaultClearTimeout;\n }\n} ())\nfunction runTimeout(fun) {\n if (cachedSetTimeout === setTimeout) {\n //normal enviroments in sane situations\n return setTimeout(fun, 0);\n }\n // if setTimeout wasn't available but was latter defined\n if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\n cachedSetTimeout = setTimeout;\n return setTimeout(fun, 0);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedSetTimeout(fun, 0);\n } catch(e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedSetTimeout.call(null, fun, 0);\n } catch(e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n return cachedSetTimeout.call(this, fun, 0);\n }\n }\n\n\n}\nfunction runClearTimeout(marker) {\n if (cachedClearTimeout === clearTimeout) {\n //normal enviroments in sane situations\n return clearTimeout(marker);\n }\n // if clearTimeout wasn't available but was latter defined\n if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\n cachedClearTimeout = clearTimeout;\n return clearTimeout(marker);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedClearTimeout(marker);\n } catch (e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedClearTimeout.call(null, marker);\n } catch (e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n return cachedClearTimeout.call(this, marker);\n }\n }\n\n\n\n}\nvar queue = [];\nvar draining = false;\nvar currentQueue;\nvar queueIndex = -1;\n\nfunction cleanUpNextTick() {\n if (!draining || !currentQueue) {\n return;\n }\n draining = false;\n if (currentQueue.length) {\n queue = currentQueue.concat(queue);\n } else {\n queueIndex = -1;\n }\n if (queue.length) {\n drainQueue();\n }\n}\n\nfunction drainQueue() {\n if (draining) {\n return;\n }\n var timeout = runTimeout(cleanUpNextTick);\n draining = true;\n\n var len = queue.length;\n while(len) {\n currentQueue = queue;\n queue = [];\n while (++queueIndex < len) {\n if (currentQueue) {\n currentQueue[queueIndex].run();\n }\n }\n queueIndex = -1;\n len = queue.length;\n }\n currentQueue = null;\n draining = false;\n runClearTimeout(timeout);\n}\n\nprocess.nextTick = function (fun) {\n var args = new Array(arguments.length - 1);\n if (arguments.length > 1) {\n for (var i = 1; i < arguments.length; i++) {\n args[i - 1] = arguments[i];\n }\n }\n queue.push(new Item(fun, args));\n if (queue.length === 1 && !draining) {\n runTimeout(drainQueue);\n }\n};\n\n// v8 likes predictible objects\nfunction Item(fun, array) {\n this.fun = fun;\n this.array = array;\n}\nItem.prototype.run = function () {\n this.fun.apply(null, this.array);\n};\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\nprocess.version = ''; // empty string to avoid regexp issues\nprocess.versions = {};\n\nfunction noop() {}\n\nprocess.on = noop;\nprocess.addListener = noop;\nprocess.once = noop;\nprocess.off = noop;\nprocess.removeListener = noop;\nprocess.removeAllListeners = noop;\nprocess.emit = noop;\n\nprocess.binding = function (name) {\n throw new Error('process.binding is not supported');\n};\n\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n throw new Error('process.chdir is not supported');\n};\nprocess.umask = function() { return 0; };\n","/*!\n * @overview RSVP - a tiny implementation of Promises/A+.\n * @copyright Copyright (c) 2016 Yehuda Katz, Tom Dale, Stefan Penner and contributors\n * @license Licensed under MIT license\n * See https://raw.githubusercontent.com/tildeio/rsvp.js/master/LICENSE\n * @version 3.3.2\n */\n\n(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n typeof define === 'function' && define.amd ? define(['exports'], factory) :\n (factory((global.RSVP = global.RSVP || {})));\n}(this, (function (exports) { 'use strict';\n\nfunction indexOf(callbacks, callback) {\n for (var i = 0, l = callbacks.length; i < l; i++) {\n if (callbacks[i] === callback) {\n return i;\n }\n }\n\n return -1;\n}\n\nfunction callbacksFor(object) {\n var callbacks = object._promiseCallbacks;\n\n if (!callbacks) {\n callbacks = object._promiseCallbacks = {};\n }\n\n return callbacks;\n}\n\n/**\n @class RSVP.EventTarget\n*/\nvar EventTarget = {\n\n /**\n `RSVP.EventTarget.mixin` extends an object with EventTarget methods. For\n Example:\n ```javascript\n let object = {};\n RSVP.EventTarget.mixin(object);\n object.on('finished', function(event) {\n // handle event\n });\n object.trigger('finished', { detail: value });\n ```\n `EventTarget.mixin` also works with prototypes:\n ```javascript\n let Person = function() {};\n RSVP.EventTarget.mixin(Person.prototype);\n let yehuda = new Person();\n let tom = new Person();\n yehuda.on('poke', function(event) {\n console.log('Yehuda says OW');\n });\n tom.on('poke', function(event) {\n console.log('Tom says OW');\n });\n yehuda.trigger('poke');\n tom.trigger('poke');\n ```\n @method mixin\n @for RSVP.EventTarget\n @private\n @param {Object} object object to extend with EventTarget methods\n */\n mixin: function mixin(object) {\n object['on'] = this['on'];\n object['off'] = this['off'];\n object['trigger'] = this['trigger'];\n object._promiseCallbacks = undefined;\n return object;\n },\n\n /**\n Registers a callback to be executed when `eventName` is triggered\n ```javascript\n object.on('event', function(eventInfo){\n // handle the event\n });\n object.trigger('event');\n ```\n @method on\n @for RSVP.EventTarget\n @private\n @param {String} eventName name of the event to listen for\n @param {Function} callback function to be called when the event is triggered.\n */\n on: function on(eventName, callback) {\n if (typeof callback !== 'function') {\n throw new TypeError('Callback must be a function');\n }\n\n var allCallbacks = callbacksFor(this),\n callbacks = undefined;\n\n callbacks = allCallbacks[eventName];\n\n if (!callbacks) {\n callbacks = allCallbacks[eventName] = [];\n }\n\n if (indexOf(callbacks, callback) === -1) {\n callbacks.push(callback);\n }\n },\n\n /**\n You can use `off` to stop firing a particular callback for an event:\n ```javascript\n function doStuff() { // do stuff! }\n object.on('stuff', doStuff);\n object.trigger('stuff'); // doStuff will be called\n // Unregister ONLY the doStuff callback\n object.off('stuff', doStuff);\n object.trigger('stuff'); // doStuff will NOT be called\n ```\n If you don't pass a `callback` argument to `off`, ALL callbacks for the\n event will not be executed when the event fires. For example:\n ```javascript\n let callback1 = function(){};\n let callback2 = function(){};\n object.on('stuff', callback1);\n object.on('stuff', callback2);\n object.trigger('stuff'); // callback1 and callback2 will be executed.\n object.off('stuff');\n object.trigger('stuff'); // callback1 and callback2 will not be executed!\n ```\n @method off\n @for RSVP.EventTarget\n @private\n @param {String} eventName event to stop listening to\n @param {Function} callback optional argument. If given, only the function\n given will be removed from the event's callback queue. If no `callback`\n argument is given, all callbacks will be removed from the event's callback\n queue.\n */\n off: function off(eventName, callback) {\n var allCallbacks = callbacksFor(this),\n callbacks = undefined,\n index = undefined;\n\n if (!callback) {\n allCallbacks[eventName] = [];\n return;\n }\n\n callbacks = allCallbacks[eventName];\n\n index = indexOf(callbacks, callback);\n\n if (index !== -1) {\n callbacks.splice(index, 1);\n }\n },\n\n /**\n Use `trigger` to fire custom events. For example:\n ```javascript\n object.on('foo', function(){\n console.log('foo event happened!');\n });\n object.trigger('foo');\n // 'foo event happened!' logged to the console\n ```\n You can also pass a value as a second argument to `trigger` that will be\n passed as an argument to all event listeners for the event:\n ```javascript\n object.on('foo', function(value){\n console.log(value.name);\n });\n object.trigger('foo', { name: 'bar' });\n // 'bar' logged to the console\n ```\n @method trigger\n @for RSVP.EventTarget\n @private\n @param {String} eventName name of the event to be triggered\n @param {*} options optional value to be passed to any event handlers for\n the given `eventName`\n */\n trigger: function trigger(eventName, options, label) {\n var allCallbacks = callbacksFor(this),\n callbacks = undefined,\n callback = undefined;\n\n if (callbacks = allCallbacks[eventName]) {\n // Don't cache the callbacks.length since it may grow\n for (var i = 0; i < callbacks.length; i++) {\n callback = callbacks[i];\n\n callback(options, label);\n }\n }\n }\n};\n\nvar config = {\n instrument: false\n};\n\nEventTarget['mixin'](config);\n\nfunction configure(name, value) {\n if (name === 'onerror') {\n // handle for legacy users that expect the actual\n // error to be passed to their function added via\n // `RSVP.configure('onerror', someFunctionHere);`\n config['on']('error', value);\n return;\n }\n\n if (arguments.length === 2) {\n config[name] = value;\n } else {\n return config[name];\n }\n}\n\nfunction objectOrFunction(x) {\n return typeof x === 'function' || typeof x === 'object' && x !== null;\n}\n\nfunction isFunction(x) {\n return typeof x === 'function';\n}\n\nfunction isMaybeThenable(x) {\n return typeof x === 'object' && x !== null;\n}\n\nvar _isArray = undefined;\nif (!Array.isArray) {\n _isArray = function (x) {\n return Object.prototype.toString.call(x) === '[object Array]';\n };\n} else {\n _isArray = Array.isArray;\n}\n\nvar isArray = _isArray;\n\n// Date.now is not available in browsers < IE9\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility\nvar now = Date.now || function () {\n return new Date().getTime();\n};\n\nfunction F() {}\n\nvar o_create = Object.create || function (o) {\n if (arguments.length > 1) {\n throw new Error('Second argument not supported');\n }\n if (typeof o !== 'object') {\n throw new TypeError('Argument must be an object');\n }\n F.prototype = o;\n return new F();\n};\n\nvar queue = [];\n\nfunction scheduleFlush() {\n setTimeout(function () {\n for (var i = 0; i < queue.length; i++) {\n var entry = queue[i];\n\n var payload = entry.payload;\n\n payload.guid = payload.key + payload.id;\n payload.childGuid = payload.key + payload.childId;\n if (payload.error) {\n payload.stack = payload.error.stack;\n }\n\n config['trigger'](entry.name, entry.payload);\n }\n queue.length = 0;\n }, 50);\n}\nfunction instrument(eventName, promise, child) {\n if (1 === queue.push({\n name: eventName,\n payload: {\n key: promise._guidKey,\n id: promise._id,\n eventName: eventName,\n detail: promise._result,\n childId: child && child._id,\n label: promise._label,\n timeStamp: now(),\n error: config[\"instrument-with-stack\"] ? new Error(promise._label) : null\n } })) {\n scheduleFlush();\n }\n}\n\n/**\n `RSVP.Promise.resolve` returns a promise that will become resolved with the\n passed `value`. It is shorthand for the following:\n\n ```javascript\n let promise = new RSVP.Promise(function(resolve, reject){\n resolve(1);\n });\n\n promise.then(function(value){\n // value === 1\n });\n ```\n\n Instead of writing the above, your code now simply becomes the following:\n\n ```javascript\n let promise = RSVP.Promise.resolve(1);\n\n promise.then(function(value){\n // value === 1\n });\n ```\n\n @method resolve\n @static\n @param {*} object value that the returned promise will be resolved with\n @param {String} label optional string for identifying the returned promise.\n Useful for tooling.\n @return {Promise} a promise that will become fulfilled with the given\n `value`\n*/\nfunction resolve$1(object, label) {\n /*jshint validthis:true */\n var Constructor = this;\n\n if (object && typeof object === 'object' && object.constructor === Constructor) {\n return object;\n }\n\n var promise = new Constructor(noop, label);\n resolve(promise, object);\n return promise;\n}\n\nfunction withOwnPromise() {\n return new TypeError('A promises callback cannot return that same promise.');\n}\n\nfunction noop() {}\n\nvar PENDING = void 0;\nvar FULFILLED = 1;\nvar REJECTED = 2;\n\nvar GET_THEN_ERROR = new ErrorObject();\n\nfunction getThen(promise) {\n try {\n return promise.then;\n } catch (error) {\n GET_THEN_ERROR.error = error;\n return GET_THEN_ERROR;\n }\n}\n\nfunction tryThen(then, value, fulfillmentHandler, rejectionHandler) {\n try {\n then.call(value, fulfillmentHandler, rejectionHandler);\n } catch (e) {\n return e;\n }\n}\n\nfunction handleForeignThenable(promise, thenable, then) {\n config.async(function (promise) {\n var sealed = false;\n var error = tryThen(then, thenable, function (value) {\n if (sealed) {\n return;\n }\n sealed = true;\n if (thenable !== value) {\n resolve(promise, value, undefined);\n } else {\n fulfill(promise, value);\n }\n }, function (reason) {\n if (sealed) {\n return;\n }\n sealed = true;\n\n reject(promise, reason);\n }, 'Settle: ' + (promise._label || ' unknown promise'));\n\n if (!sealed && error) {\n sealed = true;\n reject(promise, error);\n }\n }, promise);\n}\n\nfunction handleOwnThenable(promise, thenable) {\n if (thenable._state === FULFILLED) {\n fulfill(promise, thenable._result);\n } else if (thenable._state === REJECTED) {\n thenable._onError = null;\n reject(promise, thenable._result);\n } else {\n subscribe(thenable, undefined, function (value) {\n if (thenable !== value) {\n resolve(promise, value, undefined);\n } else {\n fulfill(promise, value);\n }\n }, function (reason) {\n return reject(promise, reason);\n });\n }\n}\n\nfunction handleMaybeThenable(promise, maybeThenable, then$$) {\n if (maybeThenable.constructor === promise.constructor && then$$ === then && promise.constructor.resolve === resolve$1) {\n handleOwnThenable(promise, maybeThenable);\n } else {\n if (then$$ === GET_THEN_ERROR) {\n reject(promise, GET_THEN_ERROR.error);\n } else if (then$$ === undefined) {\n fulfill(promise, maybeThenable);\n } else if (isFunction(then$$)) {\n handleForeignThenable(promise, maybeThenable, then$$);\n } else {\n fulfill(promise, maybeThenable);\n }\n }\n}\n\nfunction resolve(promise, value) {\n if (promise === value) {\n fulfill(promise, value);\n } else if (objectOrFunction(value)) {\n handleMaybeThenable(promise, value, getThen(value));\n } else {\n fulfill(promise, value);\n }\n}\n\nfunction publishRejection(promise) {\n if (promise._onError) {\n promise._onError(promise._result);\n }\n\n publish(promise);\n}\n\nfunction fulfill(promise, value) {\n if (promise._state !== PENDING) {\n return;\n }\n\n promise._result = value;\n promise._state = FULFILLED;\n\n if (promise._subscribers.length === 0) {\n if (config.instrument) {\n instrument('fulfilled', promise);\n }\n } else {\n config.async(publish, promise);\n }\n}\n\nfunction reject(promise, reason) {\n if (promise._state !== PENDING) {\n return;\n }\n promise._state = REJECTED;\n promise._result = reason;\n config.async(publishRejection, promise);\n}\n\nfunction subscribe(parent, child, onFulfillment, onRejection) {\n var subscribers = parent._subscribers;\n var length = subscribers.length;\n\n parent._onError = null;\n\n subscribers[length] = child;\n subscribers[length + FULFILLED] = onFulfillment;\n subscribers[length + REJECTED] = onRejection;\n\n if (length === 0 && parent._state) {\n config.async(publish, parent);\n }\n}\n\nfunction publish(promise) {\n var subscribers = promise._subscribers;\n var settled = promise._state;\n\n if (config.instrument) {\n instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise);\n }\n\n if (subscribers.length === 0) {\n return;\n }\n\n var child = undefined,\n callback = undefined,\n detail = promise._result;\n\n for (var i = 0; i < subscribers.length; i += 3) {\n child = subscribers[i];\n callback = subscribers[i + settled];\n\n if (child) {\n invokeCallback(settled, child, callback, detail);\n } else {\n callback(detail);\n }\n }\n\n promise._subscribers.length = 0;\n}\n\nfunction ErrorObject() {\n this.error = null;\n}\n\nvar TRY_CATCH_ERROR = new ErrorObject();\n\nfunction tryCatch(callback, detail) {\n try {\n return callback(detail);\n } catch (e) {\n TRY_CATCH_ERROR.error = e;\n return TRY_CATCH_ERROR;\n }\n}\n\nfunction invokeCallback(settled, promise, callback, detail) {\n var hasCallback = isFunction(callback),\n value = undefined,\n error = undefined,\n succeeded = undefined,\n failed = undefined;\n\n if (hasCallback) {\n value = tryCatch(callback, detail);\n\n if (value === TRY_CATCH_ERROR) {\n failed = true;\n error = value.error;\n value = null;\n } else {\n succeeded = true;\n }\n\n if (promise === value) {\n reject(promise, withOwnPromise());\n return;\n }\n } else {\n value = detail;\n succeeded = true;\n }\n\n if (promise._state !== PENDING) {\n // noop\n } else if (hasCallback && succeeded) {\n resolve(promise, value);\n } else if (failed) {\n reject(promise, error);\n } else if (settled === FULFILLED) {\n fulfill(promise, value);\n } else if (settled === REJECTED) {\n reject(promise, value);\n }\n}\n\nfunction initializePromise(promise, resolver) {\n var resolved = false;\n try {\n resolver(function (value) {\n if (resolved) {\n return;\n }\n resolved = true;\n resolve(promise, value);\n }, function (reason) {\n if (resolved) {\n return;\n }\n resolved = true;\n reject(promise, reason);\n });\n } catch (e) {\n reject(promise, e);\n }\n}\n\nfunction then(onFulfillment, onRejection, label) {\n var _arguments = arguments;\n\n var parent = this;\n var state = parent._state;\n\n if (state === FULFILLED && !onFulfillment || state === REJECTED && !onRejection) {\n config.instrument && instrument('chained', parent, parent);\n return parent;\n }\n\n parent._onError = null;\n\n var child = new parent.constructor(noop, label);\n var result = parent._result;\n\n config.instrument && instrument('chained', parent, child);\n\n if (state) {\n (function () {\n var callback = _arguments[state - 1];\n config.async(function () {\n return invokeCallback(state, child, callback, result);\n });\n })();\n } else {\n subscribe(parent, child, onFulfillment, onRejection);\n }\n\n return child;\n}\n\nfunction makeSettledResult(state, position, value) {\n if (state === FULFILLED) {\n return {\n state: 'fulfilled',\n value: value\n };\n } else {\n return {\n state: 'rejected',\n reason: value\n };\n }\n}\n\nfunction Enumerator(Constructor, input, abortOnReject, label) {\n this._instanceConstructor = Constructor;\n this.promise = new Constructor(noop, label);\n this._abortOnReject = abortOnReject;\n\n if (this._validateInput(input)) {\n this._input = input;\n this.length = input.length;\n this._remaining = input.length;\n\n this._init();\n\n if (this.length === 0) {\n fulfill(this.promise, this._result);\n } else {\n this.length = this.length || 0;\n this._enumerate();\n if (this._remaining === 0) {\n fulfill(this.promise, this._result);\n }\n }\n } else {\n reject(this.promise, this._validationError());\n }\n}\n\nEnumerator.prototype._validateInput = function (input) {\n return isArray(input);\n};\n\nEnumerator.prototype._validationError = function () {\n return new Error('Array Methods must be provided an Array');\n};\n\nEnumerator.prototype._init = function () {\n this._result = new Array(this.length);\n};\n\nEnumerator.prototype._enumerate = function () {\n var length = this.length;\n var promise = this.promise;\n var input = this._input;\n\n for (var i = 0; promise._state === PENDING && i < length; i++) {\n this._eachEntry(input[i], i);\n }\n};\n\nEnumerator.prototype._settleMaybeThenable = function (entry, i) {\n var c = this._instanceConstructor;\n var resolve = c.resolve;\n\n if (resolve === resolve$1) {\n var then$$ = getThen(entry);\n\n if (then$$ === then && entry._state !== PENDING) {\n entry._onError = null;\n this._settledAt(entry._state, i, entry._result);\n } else if (typeof then$$ !== 'function') {\n this._remaining--;\n this._result[i] = this._makeResult(FULFILLED, i, entry);\n } else if (c === Promise) {\n var promise = new c(noop);\n handleMaybeThenable(promise, entry, then$$);\n this._willSettleAt(promise, i);\n } else {\n this._willSettleAt(new c(function (resolve) {\n return resolve(entry);\n }), i);\n }\n } else {\n this._willSettleAt(resolve(entry), i);\n }\n};\n\nEnumerator.prototype._eachEntry = function (entry, i) {\n if (isMaybeThenable(entry)) {\n this._settleMaybeThenable(entry, i);\n } else {\n this._remaining--;\n this._result[i] = this._makeResult(FULFILLED, i, entry);\n }\n};\n\nEnumerator.prototype._settledAt = function (state, i, value) {\n var promise = this.promise;\n\n if (promise._state === PENDING) {\n this._remaining--;\n\n if (this._abortOnReject && state === REJECTED) {\n reject(promise, value);\n } else {\n this._result[i] = this._makeResult(state, i, value);\n }\n }\n\n if (this._remaining === 0) {\n fulfill(promise, this._result);\n }\n};\n\nEnumerator.prototype._makeResult = function (state, i, value) {\n return value;\n};\n\nEnumerator.prototype._willSettleAt = function (promise, i) {\n var enumerator = this;\n\n subscribe(promise, undefined, function (value) {\n return enumerator._settledAt(FULFILLED, i, value);\n }, function (reason) {\n return enumerator._settledAt(REJECTED, i, reason);\n });\n};\n\n/**\n `RSVP.Promise.all` accepts an array of promises, and returns a new promise which\n is fulfilled with an array of fulfillment values for the passed promises, or\n rejected with the reason of the first passed promise to be rejected. It casts all\n elements of the passed iterable to promises as it runs this algorithm.\n\n Example:\n\n ```javascript\n let promise1 = RSVP.resolve(1);\n let promise2 = RSVP.resolve(2);\n let promise3 = RSVP.resolve(3);\n let promises = [ promise1, promise2, promise3 ];\n\n RSVP.Promise.all(promises).then(function(array){\n // The array here would be [ 1, 2, 3 ];\n });\n ```\n\n If any of the `promises` given to `RSVP.all` are rejected, the first promise\n that is rejected will be given as an argument to the returned promises's\n rejection handler. For example:\n\n Example:\n\n ```javascript\n let promise1 = RSVP.resolve(1);\n let promise2 = RSVP.reject(new Error(\"2\"));\n let promise3 = RSVP.reject(new Error(\"3\"));\n let promises = [ promise1, promise2, promise3 ];\n\n RSVP.Promise.all(promises).then(function(array){\n // Code here never runs because there are rejected promises!\n }, function(error) {\n // error.message === \"2\"\n });\n ```\n\n @method all\n @static\n @param {Array} entries array of promises\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @return {Promise} promise that is fulfilled when all `promises` have been\n fulfilled, or rejected if any of them become rejected.\n @static\n*/\nfunction all(entries, label) {\n return new Enumerator(this, entries, true, /* abort on reject */label).promise;\n}\n\n/**\n `RSVP.Promise.race` returns a new promise which is settled in the same way as the\n first passed promise to settle.\n\n Example:\n\n ```javascript\n let promise1 = new RSVP.Promise(function(resolve, reject){\n setTimeout(function(){\n resolve('promise 1');\n }, 200);\n });\n\n let promise2 = new RSVP.Promise(function(resolve, reject){\n setTimeout(function(){\n resolve('promise 2');\n }, 100);\n });\n\n RSVP.Promise.race([promise1, promise2]).then(function(result){\n // result === 'promise 2' because it was resolved before promise1\n // was resolved.\n });\n ```\n\n `RSVP.Promise.race` is deterministic in that only the state of the first\n settled promise matters. For example, even if other promises given to the\n `promises` array argument are resolved, but the first settled promise has\n become rejected before the other promises became fulfilled, the returned\n promise will become rejected:\n\n ```javascript\n let promise1 = new RSVP.Promise(function(resolve, reject){\n setTimeout(function(){\n resolve('promise 1');\n }, 200);\n });\n\n let promise2 = new RSVP.Promise(function(resolve, reject){\n setTimeout(function(){\n reject(new Error('promise 2'));\n }, 100);\n });\n\n RSVP.Promise.race([promise1, promise2]).then(function(result){\n // Code here never runs\n }, function(reason){\n // reason.message === 'promise 2' because promise 2 became rejected before\n // promise 1 became fulfilled\n });\n ```\n\n An example real-world use case is implementing timeouts:\n\n ```javascript\n RSVP.Promise.race([ajax('foo.json'), timeout(5000)])\n ```\n\n @method race\n @static\n @param {Array} entries array of promises to observe\n @param {String} label optional string for describing the promise returned.\n Useful for tooling.\n @return {Promise} a promise which settles in the same way as the first passed\n promise to settle.\n*/\nfunction race(entries, label) {\n /*jshint validthis:true */\n var Constructor = this;\n\n var promise = new Constructor(noop, label);\n\n if (!isArray(entries)) {\n reject(promise, new TypeError('You must pass an array to race.'));\n return promise;\n }\n\n for (var i = 0; promise._state === PENDING && i < entries.length; i++) {\n subscribe(Constructor.resolve(entries[i]), undefined, function (value) {\n return resolve(promise, value);\n }, function (reason) {\n return reject(promise, reason);\n });\n }\n\n return promise;\n}\n\n/**\n `RSVP.Promise.reject` returns a promise rejected with the passed `reason`.\n It is shorthand for the following:\n\n ```javascript\n let promise = new RSVP.Promise(function(resolve, reject){\n reject(new Error('WHOOPS'));\n });\n\n promise.then(function(value){\n // Code here doesn't run because the promise is rejected!\n }, function(reason){\n // reason.message === 'WHOOPS'\n });\n ```\n\n Instead of writing the above, your code now simply becomes the following:\n\n ```javascript\n let promise = RSVP.Promise.reject(new Error('WHOOPS'));\n\n promise.then(function(value){\n // Code here doesn't run because the promise is rejected!\n }, function(reason){\n // reason.message === 'WHOOPS'\n });\n ```\n\n @method reject\n @static\n @param {*} reason value that the returned promise will be rejected with.\n @param {String} label optional string for identifying the returned promise.\n Useful for tooling.\n @return {Promise} a promise rejected with the given `reason`.\n*/\nfunction reject$1(reason, label) {\n /*jshint validthis:true */\n var Constructor = this;\n var promise = new Constructor(noop, label);\n reject(promise, reason);\n return promise;\n}\n\nvar guidKey = 'rsvp_' + now() + '-';\nvar counter = 0;\n\nfunction needsResolver() {\n throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');\n}\n\nfunction needsNew() {\n throw new TypeError(\"Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.\");\n}\n\n/**\n Promise objects represent the eventual result of an asynchronous operation. The\n primary way of interacting with a promise is through its `then` method, which\n registers callbacks to receive either a promise’s eventual value or the reason\n why the promise cannot be fulfilled.\n\n Terminology\n -----------\n\n - `promise` is an object or function with a `then` method whose behavior conforms to this specification.\n - `thenable` is an object or function that defines a `then` method.\n - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).\n - `exception` is a value that is thrown using the throw statement.\n - `reason` is a value that indicates why a promise was rejected.\n - `settled` the final resting state of a promise, fulfilled or rejected.\n\n A promise can be in one of three states: pending, fulfilled, or rejected.\n\n Promises that are fulfilled have a fulfillment value and are in the fulfilled\n state. Promises that are rejected have a rejection reason and are in the\n rejected state. A fulfillment value is never a thenable.\n\n Promises can also be said to *resolve* a value. If this value is also a\n promise, then the original promise's settled state will match the value's\n settled state. So a promise that *resolves* a promise that rejects will\n itself reject, and a promise that *resolves* a promise that fulfills will\n itself fulfill.\n\n\n Basic Usage:\n ------------\n\n ```js\n let promise = new Promise(function(resolve, reject) {\n // on success\n resolve(value);\n\n // on failure\n reject(reason);\n });\n\n promise.then(function(value) {\n // on fulfillment\n }, function(reason) {\n // on rejection\n });\n ```\n\n Advanced Usage:\n ---------------\n\n Promises shine when abstracting away asynchronous interactions such as\n `XMLHttpRequest`s.\n\n ```js\n function getJSON(url) {\n return new Promise(function(resolve, reject){\n let xhr = new XMLHttpRequest();\n\n xhr.open('GET', url);\n xhr.onreadystatechange = handler;\n xhr.responseType = 'json';\n xhr.setRequestHeader('Accept', 'application/json');\n xhr.send();\n\n function handler() {\n if (this.readyState === this.DONE) {\n if (this.status === 200) {\n resolve(this.response);\n } else {\n reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));\n }\n }\n };\n });\n }\n\n getJSON('/posts.json').then(function(json) {\n // on fulfillment\n }, function(reason) {\n // on rejection\n });\n ```\n\n Unlike callbacks, promises are great composable primitives.\n\n ```js\n Promise.all([\n getJSON('/posts'),\n getJSON('/comments')\n ]).then(function(values){\n values[0] // => postsJSON\n values[1] // => commentsJSON\n\n return values;\n });\n ```\n\n @class RSVP.Promise\n @param {function} resolver\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @constructor\n*/\nfunction Promise(resolver, label) {\n this._id = counter++;\n this._label = label;\n this._state = undefined;\n this._result = undefined;\n this._subscribers = [];\n\n config.instrument && instrument('created', this);\n\n if (noop !== resolver) {\n typeof resolver !== 'function' && needsResolver();\n this instanceof Promise ? initializePromise(this, resolver) : needsNew();\n }\n}\n\nPromise.cast = resolve$1; // deprecated\nPromise.all = all;\nPromise.race = race;\nPromise.resolve = resolve$1;\nPromise.reject = reject$1;\n\nPromise.prototype = {\n constructor: Promise,\n\n _guidKey: guidKey,\n\n _onError: function _onError(reason) {\n var promise = this;\n config.after(function () {\n if (promise._onError) {\n config['trigger']('error', reason, promise._label);\n }\n });\n },\n\n /**\n The primary way of interacting with a promise is through its `then` method,\n which registers callbacks to receive either a promise's eventual value or the\n reason why the promise cannot be fulfilled.\n \n ```js\n findUser().then(function(user){\n // user is available\n }, function(reason){\n // user is unavailable, and you are given the reason why\n });\n ```\n \n Chaining\n --------\n \n The return value of `then` is itself a promise. This second, 'downstream'\n promise is resolved with the return value of the first promise's fulfillment\n or rejection handler, or rejected if the handler throws an exception.\n \n ```js\n findUser().then(function (user) {\n return user.name;\n }, function (reason) {\n return 'default name';\n }).then(function (userName) {\n // If `findUser` fulfilled, `userName` will be the user's name, otherwise it\n // will be `'default name'`\n });\n \n findUser().then(function (user) {\n throw new Error('Found user, but still unhappy');\n }, function (reason) {\n throw new Error('`findUser` rejected and we\\'re unhappy');\n }).then(function (value) {\n // never reached\n }, function (reason) {\n // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.\n // If `findUser` rejected, `reason` will be '`findUser` rejected and we\\'re unhappy'.\n });\n ```\n If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.\n \n ```js\n findUser().then(function (user) {\n throw new PedagogicalException('Upstream error');\n }).then(function (value) {\n // never reached\n }).then(function (value) {\n // never reached\n }, function (reason) {\n // The `PedgagocialException` is propagated all the way down to here\n });\n ```\n \n Assimilation\n ------------\n \n Sometimes the value you want to propagate to a downstream promise can only be\n retrieved asynchronously. This can be achieved by returning a promise in the\n fulfillment or rejection handler. The downstream promise will then be pending\n until the returned promise is settled. This is called *assimilation*.\n \n ```js\n findUser().then(function (user) {\n return findCommentsByAuthor(user);\n }).then(function (comments) {\n // The user's comments are now available\n });\n ```\n \n If the assimliated promise rejects, then the downstream promise will also reject.\n \n ```js\n findUser().then(function (user) {\n return findCommentsByAuthor(user);\n }).then(function (comments) {\n // If `findCommentsByAuthor` fulfills, we'll have the value here\n }, function (reason) {\n // If `findCommentsByAuthor` rejects, we'll have the reason here\n });\n ```\n \n Simple Example\n --------------\n \n Synchronous Example\n \n ```javascript\n let result;\n \n try {\n result = findResult();\n // success\n } catch(reason) {\n // failure\n }\n ```\n \n Errback Example\n \n ```js\n findResult(function(result, err){\n if (err) {\n // failure\n } else {\n // success\n }\n });\n ```\n \n Promise Example;\n \n ```javascript\n findResult().then(function(result){\n // success\n }, function(reason){\n // failure\n });\n ```\n \n Advanced Example\n --------------\n \n Synchronous Example\n \n ```javascript\n let author, books;\n \n try {\n author = findAuthor();\n books = findBooksByAuthor(author);\n // success\n } catch(reason) {\n // failure\n }\n ```\n \n Errback Example\n \n ```js\n \n function foundBooks(books) {\n \n }\n \n function failure(reason) {\n \n }\n \n findAuthor(function(author, err){\n if (err) {\n failure(err);\n // failure\n } else {\n try {\n findBoooksByAuthor(author, function(books, err) {\n if (err) {\n failure(err);\n } else {\n try {\n foundBooks(books);\n } catch(reason) {\n failure(reason);\n }\n }\n });\n } catch(error) {\n failure(err);\n }\n // success\n }\n });\n ```\n \n Promise Example;\n \n ```javascript\n findAuthor().\n then(findBooksByAuthor).\n then(function(books){\n // found books\n }).catch(function(reason){\n // something went wrong\n });\n ```\n \n @method then\n @param {Function} onFulfillment\n @param {Function} onRejection\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @return {Promise}\n */\n then: then,\n\n /**\n `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same\n as the catch block of a try/catch statement.\n \n ```js\n function findAuthor(){\n throw new Error('couldn\\'t find that author');\n }\n \n // synchronous\n try {\n findAuthor();\n } catch(reason) {\n // something went wrong\n }\n \n // async with promises\n findAuthor().catch(function(reason){\n // something went wrong\n });\n ```\n \n @method catch\n @param {Function} onRejection\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @return {Promise}\n */\n 'catch': function _catch(onRejection, label) {\n return this.then(undefined, onRejection, label);\n },\n\n /**\n `finally` will be invoked regardless of the promise's fate just as native\n try/catch/finally behaves\n \n Synchronous example:\n \n ```js\n findAuthor() {\n if (Math.random() > 0.5) {\n throw new Error();\n }\n return new Author();\n }\n \n try {\n return findAuthor(); // succeed or fail\n } catch(error) {\n return findOtherAuther();\n } finally {\n // always runs\n // doesn't affect the return value\n }\n ```\n \n Asynchronous example:\n \n ```js\n findAuthor().catch(function(reason){\n return findOtherAuther();\n }).finally(function(){\n // author was either found, or not\n });\n ```\n \n @method finally\n @param {Function} callback\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @return {Promise}\n */\n 'finally': function _finally(callback, label) {\n var promise = this;\n var constructor = promise.constructor;\n\n return promise.then(function (value) {\n return constructor.resolve(callback()).then(function () {\n return value;\n });\n }, function (reason) {\n return constructor.resolve(callback()).then(function () {\n throw reason;\n });\n }, label);\n }\n};\n\nfunction Result() {\n this.value = undefined;\n}\n\nvar ERROR = new Result();\nvar GET_THEN_ERROR$1 = new Result();\n\nfunction getThen$1(obj) {\n try {\n return obj.then;\n } catch (error) {\n ERROR.value = error;\n return ERROR;\n }\n}\n\nfunction tryApply(f, s, a) {\n try {\n f.apply(s, a);\n } catch (error) {\n ERROR.value = error;\n return ERROR;\n }\n}\n\nfunction makeObject(_, argumentNames) {\n var obj = {};\n var length = _.length;\n var args = new Array(length);\n\n for (var x = 0; x < length; x++) {\n args[x] = _[x];\n }\n\n for (var i = 0; i < argumentNames.length; i++) {\n var _name = argumentNames[i];\n obj[_name] = args[i + 1];\n }\n\n return obj;\n}\n\nfunction arrayResult(_) {\n var length = _.length;\n var args = new Array(length - 1);\n\n for (var i = 1; i < length; i++) {\n args[i - 1] = _[i];\n }\n\n return args;\n}\n\nfunction wrapThenable(_then, promise) {\n return {\n then: function then(onFulFillment, onRejection) {\n return _then.call(promise, onFulFillment, onRejection);\n }\n };\n}\n\n/**\n `RSVP.denodeify` takes a 'node-style' function and returns a function that\n will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the\n browser when you'd prefer to use promises over using callbacks. For example,\n `denodeify` transforms the following:\n\n ```javascript\n let fs = require('fs');\n\n fs.readFile('myfile.txt', function(err, data){\n if (err) return handleError(err);\n handleData(data);\n });\n ```\n\n into:\n\n ```javascript\n let fs = require('fs');\n let readFile = RSVP.denodeify(fs.readFile);\n\n readFile('myfile.txt').then(handleData, handleError);\n ```\n\n If the node function has multiple success parameters, then `denodeify`\n just returns the first one:\n\n ```javascript\n let request = RSVP.denodeify(require('request'));\n\n request('http://example.com').then(function(res) {\n // ...\n });\n ```\n\n However, if you need all success parameters, setting `denodeify`'s\n second parameter to `true` causes it to return all success parameters\n as an array:\n\n ```javascript\n let request = RSVP.denodeify(require('request'), true);\n\n request('http://example.com').then(function(result) {\n // result[0] -> res\n // result[1] -> body\n });\n ```\n\n Or if you pass it an array with names it returns the parameters as a hash:\n\n ```javascript\n let request = RSVP.denodeify(require('request'), ['res', 'body']);\n\n request('http://example.com').then(function(result) {\n // result.res\n // result.body\n });\n ```\n\n Sometimes you need to retain the `this`:\n\n ```javascript\n let app = require('express')();\n let render = RSVP.denodeify(app.render.bind(app));\n ```\n\n The denodified function inherits from the original function. It works in all\n environments, except IE 10 and below. Consequently all properties of the original\n function are available to you. However, any properties you change on the\n denodeified function won't be changed on the original function. Example:\n\n ```javascript\n let request = RSVP.denodeify(require('request')),\n cookieJar = request.jar(); // <- Inheritance is used here\n\n request('http://example.com', {jar: cookieJar}).then(function(res) {\n // cookieJar.cookies holds now the cookies returned by example.com\n });\n ```\n\n Using `denodeify` makes it easier to compose asynchronous operations instead\n of using callbacks. For example, instead of:\n\n ```javascript\n let fs = require('fs');\n\n fs.readFile('myfile.txt', function(err, data){\n if (err) { ... } // Handle error\n fs.writeFile('myfile2.txt', data, function(err){\n if (err) { ... } // Handle error\n console.log('done')\n });\n });\n ```\n\n you can chain the operations together using `then` from the returned promise:\n\n ```javascript\n let fs = require('fs');\n let readFile = RSVP.denodeify(fs.readFile);\n let writeFile = RSVP.denodeify(fs.writeFile);\n\n readFile('myfile.txt').then(function(data){\n return writeFile('myfile2.txt', data);\n }).then(function(){\n console.log('done')\n }).catch(function(error){\n // Handle error\n });\n ```\n\n @method denodeify\n @static\n @for RSVP\n @param {Function} nodeFunc a 'node-style' function that takes a callback as\n its last argument. The callback expects an error to be passed as its first\n argument (if an error occurred, otherwise null), and the value from the\n operation as its second argument ('function(err, value){ }').\n @param {Boolean|Array} [options] An optional paramter that if set\n to `true` causes the promise to fulfill with the callback's success arguments\n as an array. This is useful if the node function has multiple success\n paramters. If you set this paramter to an array with names, the promise will\n fulfill with a hash with these names as keys and the success parameters as\n values.\n @return {Function} a function that wraps `nodeFunc` to return an\n `RSVP.Promise`\n @static\n*/\nfunction denodeify(nodeFunc, options) {\n var fn = function fn() {\n var self = this;\n var l = arguments.length;\n var args = new Array(l + 1);\n var promiseInput = false;\n\n for (var i = 0; i < l; ++i) {\n var arg = arguments[i];\n\n if (!promiseInput) {\n // TODO: clean this up\n promiseInput = needsPromiseInput(arg);\n if (promiseInput === GET_THEN_ERROR$1) {\n var p = new Promise(noop);\n reject(p, GET_THEN_ERROR$1.value);\n return p;\n } else if (promiseInput && promiseInput !== true) {\n arg = wrapThenable(promiseInput, arg);\n }\n }\n args[i] = arg;\n }\n\n var promise = new Promise(noop);\n\n args[l] = function (err, val) {\n if (err) reject(promise, err);else if (options === undefined) resolve(promise, val);else if (options === true) resolve(promise, arrayResult(arguments));else if (isArray(options)) resolve(promise, makeObject(arguments, options));else resolve(promise, val);\n };\n\n if (promiseInput) {\n return handlePromiseInput(promise, args, nodeFunc, self);\n } else {\n return handleValueInput(promise, args, nodeFunc, self);\n }\n };\n\n fn.__proto__ = nodeFunc;\n\n return fn;\n}\n\nfunction handleValueInput(promise, args, nodeFunc, self) {\n var result = tryApply(nodeFunc, self, args);\n if (result === ERROR) {\n reject(promise, result.value);\n }\n return promise;\n}\n\nfunction handlePromiseInput(promise, args, nodeFunc, self) {\n return Promise.all(args).then(function (args) {\n var result = tryApply(nodeFunc, self, args);\n if (result === ERROR) {\n reject(promise, result.value);\n }\n return promise;\n });\n}\n\nfunction needsPromiseInput(arg) {\n if (arg && typeof arg === 'object') {\n if (arg.constructor === Promise) {\n return true;\n } else {\n return getThen$1(arg);\n }\n } else {\n return false;\n }\n}\n\n/**\n This is a convenient alias for `RSVP.Promise.all`.\n\n @method all\n @static\n @for RSVP\n @param {Array} array Array of promises.\n @param {String} label An optional label. This is useful\n for tooling.\n*/\nfunction all$1(array, label) {\n return Promise.all(array, label);\n}\n\nfunction AllSettled(Constructor, entries, label) {\n this._superConstructor(Constructor, entries, false, /* don't abort on reject */label);\n}\n\nAllSettled.prototype = o_create(Enumerator.prototype);\nAllSettled.prototype._superConstructor = Enumerator;\nAllSettled.prototype._makeResult = makeSettledResult;\nAllSettled.prototype._validationError = function () {\n return new Error('allSettled must be called with an array');\n};\n\n/**\n `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing\n a fail-fast method, it waits until all the promises have returned and\n shows you all the results. This is useful if you want to handle multiple\n promises' failure states together as a set.\n\n Returns a promise that is fulfilled when all the given promises have been\n settled. The return promise is fulfilled with an array of the states of\n the promises passed into the `promises` array argument.\n\n Each state object will either indicate fulfillment or rejection, and\n provide the corresponding value or reason. The states will take one of\n the following formats:\n\n ```javascript\n { state: 'fulfilled', value: value }\n or\n { state: 'rejected', reason: reason }\n ```\n\n Example:\n\n ```javascript\n let promise1 = RSVP.Promise.resolve(1);\n let promise2 = RSVP.Promise.reject(new Error('2'));\n let promise3 = RSVP.Promise.reject(new Error('3'));\n let promises = [ promise1, promise2, promise3 ];\n\n RSVP.allSettled(promises).then(function(array){\n // array == [\n // { state: 'fulfilled', value: 1 },\n // { state: 'rejected', reason: Error },\n // { state: 'rejected', reason: Error }\n // ]\n // Note that for the second item, reason.message will be '2', and for the\n // third item, reason.message will be '3'.\n }, function(error) {\n // Not run. (This block would only be called if allSettled had failed,\n // for instance if passed an incorrect argument type.)\n });\n ```\n\n @method allSettled\n @static\n @for RSVP\n @param {Array} entries\n @param {String} label - optional string that describes the promise.\n Useful for tooling.\n @return {Promise} promise that is fulfilled with an array of the settled\n states of the constituent promises.\n*/\nfunction allSettled(entries, label) {\n return new AllSettled(Promise, entries, label).promise;\n}\n\n/**\n This is a convenient alias for `RSVP.Promise.race`.\n\n @method race\n @static\n @for RSVP\n @param {Array} array Array of promises.\n @param {String} label An optional label. This is useful\n for tooling.\n */\nfunction race$1(array, label) {\n return Promise.race(array, label);\n}\n\nfunction PromiseHash(Constructor, object, label) {\n this._superConstructor(Constructor, object, true, label);\n}\n\nPromiseHash.prototype = o_create(Enumerator.prototype);\nPromiseHash.prototype._superConstructor = Enumerator;\nPromiseHash.prototype._init = function () {\n this._result = {};\n};\n\nPromiseHash.prototype._validateInput = function (input) {\n return input && typeof input === 'object';\n};\n\nPromiseHash.prototype._validationError = function () {\n return new Error('Promise.hash must be called with an object');\n};\n\nPromiseHash.prototype._enumerate = function () {\n var enumerator = this;\n var promise = enumerator.promise;\n var input = enumerator._input;\n var results = [];\n\n for (var key in input) {\n if (promise._state === PENDING && Object.prototype.hasOwnProperty.call(input, key)) {\n results.push({\n position: key,\n entry: input[key]\n });\n }\n }\n\n var length = results.length;\n enumerator._remaining = length;\n var result = undefined;\n\n for (var i = 0; promise._state === PENDING && i < length; i++) {\n result = results[i];\n enumerator._eachEntry(result.entry, result.position);\n }\n};\n\n/**\n `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array\n for its `promises` argument.\n\n Returns a promise that is fulfilled when all the given promises have been\n fulfilled, or rejected if any of them become rejected. The returned promise\n is fulfilled with a hash that has the same key names as the `promises` object\n argument. If any of the values in the object are not promises, they will\n simply be copied over to the fulfilled object.\n\n Example:\n\n ```javascript\n let promises = {\n myPromise: RSVP.resolve(1),\n yourPromise: RSVP.resolve(2),\n theirPromise: RSVP.resolve(3),\n notAPromise: 4\n };\n\n RSVP.hash(promises).then(function(hash){\n // hash here is an object that looks like:\n // {\n // myPromise: 1,\n // yourPromise: 2,\n // theirPromise: 3,\n // notAPromise: 4\n // }\n });\n ````\n\n If any of the `promises` given to `RSVP.hash` are rejected, the first promise\n that is rejected will be given as the reason to the rejection handler.\n\n Example:\n\n ```javascript\n let promises = {\n myPromise: RSVP.resolve(1),\n rejectedPromise: RSVP.reject(new Error('rejectedPromise')),\n anotherRejectedPromise: RSVP.reject(new Error('anotherRejectedPromise')),\n };\n\n RSVP.hash(promises).then(function(hash){\n // Code here never runs because there are rejected promises!\n }, function(reason) {\n // reason.message === 'rejectedPromise'\n });\n ```\n\n An important note: `RSVP.hash` is intended for plain JavaScript objects that\n are just a set of keys and values. `RSVP.hash` will NOT preserve prototype\n chains.\n\n Example:\n\n ```javascript\n function MyConstructor(){\n this.example = RSVP.resolve('Example');\n }\n\n MyConstructor.prototype = {\n protoProperty: RSVP.resolve('Proto Property')\n };\n\n let myObject = new MyConstructor();\n\n RSVP.hash(myObject).then(function(hash){\n // protoProperty will not be present, instead you will just have an\n // object that looks like:\n // {\n // example: 'Example'\n // }\n //\n // hash.hasOwnProperty('protoProperty'); // false\n // 'undefined' === typeof hash.protoProperty\n });\n ```\n\n @method hash\n @static\n @for RSVP\n @param {Object} object\n @param {String} label optional string that describes the promise.\n Useful for tooling.\n @return {Promise} promise that is fulfilled when all properties of `promises`\n have been fulfilled, or rejected if any of them become rejected.\n*/\nfunction hash(object, label) {\n return new PromiseHash(Promise, object, label).promise;\n}\n\nfunction HashSettled(Constructor, object, label) {\n this._superConstructor(Constructor, object, false, label);\n}\n\nHashSettled.prototype = o_create(PromiseHash.prototype);\nHashSettled.prototype._superConstructor = Enumerator;\nHashSettled.prototype._makeResult = makeSettledResult;\n\nHashSettled.prototype._validationError = function () {\n return new Error('hashSettled must be called with an object');\n};\n\n/**\n `RSVP.hashSettled` is similar to `RSVP.allSettled`, but takes an object\n instead of an array for its `promises` argument.\n\n Unlike `RSVP.all` or `RSVP.hash`, which implement a fail-fast method,\n but like `RSVP.allSettled`, `hashSettled` waits until all the\n constituent promises have returned and then shows you all the results\n with their states and values/reasons. This is useful if you want to\n handle multiple promises' failure states together as a set.\n\n Returns a promise that is fulfilled when all the given promises have been\n settled, or rejected if the passed parameters are invalid.\n\n The returned promise is fulfilled with a hash that has the same key names as\n the `promises` object argument. If any of the values in the object are not\n promises, they will be copied over to the fulfilled object and marked with state\n 'fulfilled'.\n\n Example:\n\n ```javascript\n let promises = {\n myPromise: RSVP.Promise.resolve(1),\n yourPromise: RSVP.Promise.resolve(2),\n theirPromise: RSVP.Promise.resolve(3),\n notAPromise: 4\n };\n\n RSVP.hashSettled(promises).then(function(hash){\n // hash here is an object that looks like:\n // {\n // myPromise: { state: 'fulfilled', value: 1 },\n // yourPromise: { state: 'fulfilled', value: 2 },\n // theirPromise: { state: 'fulfilled', value: 3 },\n // notAPromise: { state: 'fulfilled', value: 4 }\n // }\n });\n ```\n\n If any of the `promises` given to `RSVP.hash` are rejected, the state will\n be set to 'rejected' and the reason for rejection provided.\n\n Example:\n\n ```javascript\n let promises = {\n myPromise: RSVP.Promise.resolve(1),\n rejectedPromise: RSVP.Promise.reject(new Error('rejection')),\n anotherRejectedPromise: RSVP.Promise.reject(new Error('more rejection')),\n };\n\n RSVP.hashSettled(promises).then(function(hash){\n // hash here is an object that looks like:\n // {\n // myPromise: { state: 'fulfilled', value: 1 },\n // rejectedPromise: { state: 'rejected', reason: Error },\n // anotherRejectedPromise: { state: 'rejected', reason: Error },\n // }\n // Note that for rejectedPromise, reason.message == 'rejection',\n // and for anotherRejectedPromise, reason.message == 'more rejection'.\n });\n ```\n\n An important note: `RSVP.hashSettled` is intended for plain JavaScript objects that\n are just a set of keys and values. `RSVP.hashSettled` will NOT preserve prototype\n chains.\n\n Example:\n\n ```javascript\n function MyConstructor(){\n this.example = RSVP.Promise.resolve('Example');\n }\n\n MyConstructor.prototype = {\n protoProperty: RSVP.Promise.resolve('Proto Property')\n };\n\n let myObject = new MyConstructor();\n\n RSVP.hashSettled(myObject).then(function(hash){\n // protoProperty will not be present, instead you will just have an\n // object that looks like:\n // {\n // example: { state: 'fulfilled', value: 'Example' }\n // }\n //\n // hash.hasOwnProperty('protoProperty'); // false\n // 'undefined' === typeof hash.protoProperty\n });\n ```\n\n @method hashSettled\n @for RSVP\n @param {Object} object\n @param {String} label optional string that describes the promise.\n Useful for tooling.\n @return {Promise} promise that is fulfilled when when all properties of `promises`\n have been settled.\n @static\n*/\nfunction hashSettled(object, label) {\n return new HashSettled(Promise, object, label).promise;\n}\n\nfunction rethrow(reason) {\n setTimeout(function () {\n throw reason;\n });\n throw reason;\n}\n\n/**\n `RSVP.defer` returns an object similar to jQuery's `$.Deferred`.\n `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s\n interface. New code should use the `RSVP.Promise` constructor instead.\n\n The object returned from `RSVP.defer` is a plain object with three properties:\n\n * promise - an `RSVP.Promise`.\n * reject - a function that causes the `promise` property on this object to\n become rejected\n * resolve - a function that causes the `promise` property on this object to\n become fulfilled.\n\n Example:\n\n ```javascript\n let deferred = RSVP.defer();\n\n deferred.resolve(\"Success!\");\n\n deferred.promise.then(function(value){\n // value here is \"Success!\"\n });\n ```\n\n @method defer\n @static\n @for RSVP\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @return {Object}\n */\nfunction defer(label) {\n var deferred = { resolve: undefined, reject: undefined };\n\n deferred.promise = new Promise(function (resolve, reject) {\n deferred.resolve = resolve;\n deferred.reject = reject;\n }, label);\n\n return deferred;\n}\n\n/**\n `RSVP.map` is similar to JavaScript's native `map` method, except that it\n waits for all promises to become fulfilled before running the `mapFn` on\n each item in given to `promises`. `RSVP.map` returns a promise that will\n become fulfilled with the result of running `mapFn` on the values the promises\n become fulfilled with.\n\n For example:\n\n ```javascript\n\n let promise1 = RSVP.resolve(1);\n let promise2 = RSVP.resolve(2);\n let promise3 = RSVP.resolve(3);\n let promises = [ promise1, promise2, promise3 ];\n\n let mapFn = function(item){\n return item + 1;\n };\n\n RSVP.map(promises, mapFn).then(function(result){\n // result is [ 2, 3, 4 ]\n });\n ```\n\n If any of the `promises` given to `RSVP.map` are rejected, the first promise\n that is rejected will be given as an argument to the returned promise's\n rejection handler. For example:\n\n ```javascript\n let promise1 = RSVP.resolve(1);\n let promise2 = RSVP.reject(new Error('2'));\n let promise3 = RSVP.reject(new Error('3'));\n let promises = [ promise1, promise2, promise3 ];\n\n let mapFn = function(item){\n return item + 1;\n };\n\n RSVP.map(promises, mapFn).then(function(array){\n // Code here never runs because there are rejected promises!\n }, function(reason) {\n // reason.message === '2'\n });\n ```\n\n `RSVP.map` will also wait if a promise is returned from `mapFn`. For example,\n say you want to get all comments from a set of blog posts, but you need\n the blog posts first because they contain a url to those comments.\n\n ```javscript\n\n let mapFn = function(blogPost){\n // getComments does some ajax and returns an RSVP.Promise that is fulfilled\n // with some comments data\n return getComments(blogPost.comments_url);\n };\n\n // getBlogPosts does some ajax and returns an RSVP.Promise that is fulfilled\n // with some blog post data\n RSVP.map(getBlogPosts(), mapFn).then(function(comments){\n // comments is the result of asking the server for the comments\n // of all blog posts returned from getBlogPosts()\n });\n ```\n\n @method map\n @static\n @for RSVP\n @param {Array} promises\n @param {Function} mapFn function to be called on each fulfilled promise.\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @return {Promise} promise that is fulfilled with the result of calling\n `mapFn` on each fulfilled promise or value when they become fulfilled.\n The promise will be rejected if any of the given `promises` become rejected.\n @static\n*/\nfunction map(promises, mapFn, label) {\n return Promise.all(promises, label).then(function (values) {\n if (!isFunction(mapFn)) {\n throw new TypeError(\"You must pass a function as map's second argument.\");\n }\n\n var length = values.length;\n var results = new Array(length);\n\n for (var i = 0; i < length; i++) {\n results[i] = mapFn(values[i]);\n }\n\n return Promise.all(results, label);\n });\n}\n\n/**\n This is a convenient alias for `RSVP.Promise.resolve`.\n\n @method resolve\n @static\n @for RSVP\n @param {*} value value that the returned promise will be resolved with\n @param {String} label optional string for identifying the returned promise.\n Useful for tooling.\n @return {Promise} a promise that will become fulfilled with the given\n `value`\n*/\nfunction resolve$2(value, label) {\n return Promise.resolve(value, label);\n}\n\n/**\n This is a convenient alias for `RSVP.Promise.reject`.\n\n @method reject\n @static\n @for RSVP\n @param {*} reason value that the returned promise will be rejected with.\n @param {String} label optional string for identifying the returned promise.\n Useful for tooling.\n @return {Promise} a promise rejected with the given `reason`.\n*/\nfunction reject$2(reason, label) {\n return Promise.reject(reason, label);\n}\n\n/**\n `RSVP.filter` is similar to JavaScript's native `filter` method, except that it\n waits for all promises to become fulfilled before running the `filterFn` on\n each item in given to `promises`. `RSVP.filter` returns a promise that will\n become fulfilled with the result of running `filterFn` on the values the\n promises become fulfilled with.\n\n For example:\n\n ```javascript\n\n let promise1 = RSVP.resolve(1);\n let promise2 = RSVP.resolve(2);\n let promise3 = RSVP.resolve(3);\n\n let promises = [promise1, promise2, promise3];\n\n let filterFn = function(item){\n return item > 1;\n };\n\n RSVP.filter(promises, filterFn).then(function(result){\n // result is [ 2, 3 ]\n });\n ```\n\n If any of the `promises` given to `RSVP.filter` are rejected, the first promise\n that is rejected will be given as an argument to the returned promise's\n rejection handler. For example:\n\n ```javascript\n let promise1 = RSVP.resolve(1);\n let promise2 = RSVP.reject(new Error('2'));\n let promise3 = RSVP.reject(new Error('3'));\n let promises = [ promise1, promise2, promise3 ];\n\n let filterFn = function(item){\n return item > 1;\n };\n\n RSVP.filter(promises, filterFn).then(function(array){\n // Code here never runs because there are rejected promises!\n }, function(reason) {\n // reason.message === '2'\n });\n ```\n\n `RSVP.filter` will also wait for any promises returned from `filterFn`.\n For instance, you may want to fetch a list of users then return a subset\n of those users based on some asynchronous operation:\n\n ```javascript\n\n let alice = { name: 'alice' };\n let bob = { name: 'bob' };\n let users = [ alice, bob ];\n\n let promises = users.map(function(user){\n return RSVP.resolve(user);\n });\n\n let filterFn = function(user){\n // Here, Alice has permissions to create a blog post, but Bob does not.\n return getPrivilegesForUser(user).then(function(privs){\n return privs.can_create_blog_post === true;\n });\n };\n RSVP.filter(promises, filterFn).then(function(users){\n // true, because the server told us only Alice can create a blog post.\n users.length === 1;\n // false, because Alice is the only user present in `users`\n users[0] === bob;\n });\n ```\n\n @method filter\n @static\n @for RSVP\n @param {Array} promises\n @param {Function} filterFn - function to be called on each resolved value to\n filter the final results.\n @param {String} label optional string describing the promise. Useful for\n tooling.\n @return {Promise}\n*/\n\nfunction resolveAll(promises, label) {\n return Promise.all(promises, label);\n}\n\nfunction resolveSingle(promise, label) {\n return Promise.resolve(promise, label).then(function (promises) {\n return resolveAll(promises, label);\n });\n}\nfunction filter(promises, filterFn, label) {\n var promise = isArray(promises) ? resolveAll(promises, label) : resolveSingle(promises, label);\n return promise.then(function (values) {\n if (!isFunction(filterFn)) {\n throw new TypeError(\"You must pass a function as filter's second argument.\");\n }\n\n var length = values.length;\n var filtered = new Array(length);\n\n for (var i = 0; i < length; i++) {\n filtered[i] = filterFn(values[i]);\n }\n\n return resolveAll(filtered, label).then(function (filtered) {\n var results = new Array(length);\n var newLength = 0;\n\n for (var i = 0; i < length; i++) {\n if (filtered[i]) {\n results[newLength] = values[i];\n newLength++;\n }\n }\n\n results.length = newLength;\n\n return results;\n });\n });\n}\n\nvar len = 0;\nvar vertxNext = undefined;\nfunction asap(callback, arg) {\n queue$1[len] = callback;\n queue$1[len + 1] = arg;\n len += 2;\n if (len === 2) {\n // If len is 1, that means that we need to schedule an async flush.\n // If additional callbacks are queued before the queue is flushed, they\n // will be processed by this flush that we are scheduling.\n scheduleFlush$1();\n }\n}\n\nvar browserWindow = typeof window !== 'undefined' ? window : undefined;\nvar browserGlobal = browserWindow || {};\nvar BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;\nvar isNode = typeof self === 'undefined' && typeof process !== 'undefined' && ({}).toString.call(process) === '[object process]';\n\n// test for web worker but not in IE10\nvar isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';\n\n// node\nfunction useNextTick() {\n var nextTick = process.nextTick;\n // node version 0.10.x displays a deprecation warning when nextTick is used recursively\n // setImmediate should be used instead instead\n var version = process.versions.node.match(/^(?:(\\d+)\\.)?(?:(\\d+)\\.)?(\\*|\\d+)$/);\n if (Array.isArray(version) && version[1] === '0' && version[2] === '10') {\n nextTick = setImmediate;\n }\n return function () {\n return nextTick(flush);\n };\n}\n\n// vertx\nfunction useVertxTimer() {\n return function () {\n return vertxNext(flush);\n };\n}\n\nfunction useMutationObserver() {\n var iterations = 0;\n var observer = new BrowserMutationObserver(flush);\n var node = document.createTextNode('');\n observer.observe(node, { characterData: true });\n\n return function () {\n return node.data = iterations = ++iterations % 2;\n };\n}\n\n// web worker\nfunction useMessageChannel() {\n var channel = new MessageChannel();\n channel.port1.onmessage = flush;\n return function () {\n return channel.port2.postMessage(0);\n };\n}\n\nfunction useSetTimeout() {\n return function () {\n return setTimeout(flush, 1);\n };\n}\n\nvar queue$1 = new Array(1000);\n\nfunction flush() {\n for (var i = 0; i < len; i += 2) {\n var callback = queue$1[i];\n var arg = queue$1[i + 1];\n\n callback(arg);\n\n queue$1[i] = undefined;\n queue$1[i + 1] = undefined;\n }\n\n len = 0;\n}\n\nfunction attemptVertex() {\n try {\n var r = require;\n var vertx = r('vertx');\n vertxNext = vertx.runOnLoop || vertx.runOnContext;\n return useVertxTimer();\n } catch (e) {\n return useSetTimeout();\n }\n}\n\nvar scheduleFlush$1 = undefined;\n// Decide what async method to use to triggering processing of queued callbacks:\nif (isNode) {\n scheduleFlush$1 = useNextTick();\n} else if (BrowserMutationObserver) {\n scheduleFlush$1 = useMutationObserver();\n} else if (isWorker) {\n scheduleFlush$1 = useMessageChannel();\n} else if (browserWindow === undefined && typeof require === 'function') {\n scheduleFlush$1 = attemptVertex();\n} else {\n scheduleFlush$1 = useSetTimeout();\n}\n\nvar platform = undefined;\n\n/* global self */\nif (typeof self === 'object') {\n platform = self;\n\n /* global global */\n} else if (typeof global === 'object') {\n platform = global;\n } else {\n throw new Error('no global: `self` or `global` found');\n }\n\nvar _async$filter;\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n// defaults\n\n// the default export here is for backwards compat:\n// https://github.com/tildeio/rsvp.js/issues/434\nconfig.async = asap;\nconfig.after = function (cb) {\n return setTimeout(cb, 0);\n};\nvar cast = resolve$2;\n\nvar async = function async(callback, arg) {\n return config.async(callback, arg);\n};\n\nfunction on() {\n config['on'].apply(config, arguments);\n}\n\nfunction off() {\n config['off'].apply(config, arguments);\n}\n\n// Set up instrumentation through `window.__PROMISE_INTRUMENTATION__`\nif (typeof window !== 'undefined' && typeof window['__PROMISE_INSTRUMENTATION__'] === 'object') {\n var callbacks = window['__PROMISE_INSTRUMENTATION__'];\n configure('instrument', true);\n for (var eventName in callbacks) {\n if (callbacks.hasOwnProperty(eventName)) {\n on(eventName, callbacks[eventName]);\n }\n }\n}var rsvp = (_async$filter = {\n cast: cast,\n Promise: Promise,\n EventTarget: EventTarget,\n all: all$1,\n allSettled: allSettled,\n race: race$1,\n hash: hash,\n hashSettled: hashSettled,\n rethrow: rethrow,\n defer: defer,\n denodeify: denodeify,\n configure: configure,\n on: on,\n off: off,\n resolve: resolve$2,\n reject: reject$2,\n map: map\n}, _defineProperty(_async$filter, 'async', async), _defineProperty(_async$filter, 'filter', // babel seems to error if async isn't a computed prop here...\nfilter), _async$filter);\n\nexports['default'] = rsvp;\nexports.cast = cast;\nexports.Promise = Promise;\nexports.EventTarget = EventTarget;\nexports.all = all$1;\nexports.allSettled = allSettled;\nexports.race = race$1;\nexports.hash = hash;\nexports.hashSettled = hashSettled;\nexports.rethrow = rethrow;\nexports.defer = defer;\nexports.denodeify = denodeify;\nexports.configure = configure;\nexports.on = on;\nexports.off = off;\nexports.resolve = resolve$2;\nexports.reject = reject$2;\nexports.map = map;\nexports.async = async;\nexports.filter = filter;\n\nObject.defineProperty(exports, '__esModule', { value: true });\n\n})));\n//# sourceMappingURL=rsvp.map","/*!\n * URI.js - Mutating URLs\n * Second Level Domain (SLD) Support\n *\n * Version: 1.18.1\n *\n * Author: Rodney Rehm\n * Web: http://medialize.github.io/URI.js/\n *\n * Licensed under\n * MIT License http://www.opensource.org/licenses/mit-license\n *\n */\n\n(function (root, factory) {\n 'use strict';\n // https://github.com/umdjs/umd/blob/master/returnExports.js\n if (typeof exports === 'object') {\n // Node\n module.exports = factory();\n } else if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define(factory);\n } else {\n // Browser globals (root is window)\n root.SecondLevelDomains = factory(root);\n }\n}(this, function (root) {\n 'use strict';\n\n // save current SecondLevelDomains variable, if any\n var _SecondLevelDomains = root && root.SecondLevelDomains;\n\n var SLD = {\n // list of known Second Level Domains\n // converted list of SLDs from https://github.com/gavingmiller/second-level-domains\n // ----\n // publicsuffix.org is more current and actually used by a couple of browsers internally.\n // downside is it also contains domains like \"dyndns.org\" - which is fine for the security\n // issues browser have to deal with (SOP for cookies, etc) - but is way overboard for URI.js\n // ----\n list: {\n 'ac':' com gov mil net org ',\n 'ae':' ac co gov mil name net org pro sch ',\n 'af':' com edu gov net org ',\n 'al':' com edu gov mil net org ',\n 'ao':' co ed gv it og pb ',\n 'ar':' com edu gob gov int mil net org tur ',\n 'at':' ac co gv or ',\n 'au':' asn com csiro edu gov id net org ',\n 'ba':' co com edu gov mil net org rs unbi unmo unsa untz unze ',\n 'bb':' biz co com edu gov info net org store tv ',\n 'bh':' biz cc com edu gov info net org ',\n 'bn':' com edu gov net org ',\n 'bo':' com edu gob gov int mil net org tv ',\n 'br':' adm adv agr am arq art ato b bio blog bmd cim cng cnt com coop ecn edu eng esp etc eti far flog fm fnd fot fst g12 ggf gov imb ind inf jor jus lel mat med mil mus net nom not ntr odo org ppg pro psc psi qsl rec slg srv tmp trd tur tv vet vlog wiki zlg ',\n 'bs':' com edu gov net org ',\n 'bz':' du et om ov rg ',\n 'ca':' ab bc mb nb nf nl ns nt nu on pe qc sk yk ',\n 'ck':' biz co edu gen gov info net org ',\n 'cn':' ac ah bj com cq edu fj gd gov gs gx gz ha hb he hi hl hn jl js jx ln mil net nm nx org qh sc sd sh sn sx tj tw xj xz yn zj ',\n 'co':' com edu gov mil net nom org ',\n 'cr':' ac c co ed fi go or sa ',\n 'cy':' ac biz com ekloges gov ltd name net org parliament press pro tm ',\n 'do':' art com edu gob gov mil net org sld web ',\n 'dz':' art asso com edu gov net org pol ',\n 'ec':' com edu fin gov info med mil net org pro ',\n 'eg':' com edu eun gov mil name net org sci ',\n 'er':' com edu gov ind mil net org rochest w ',\n 'es':' com edu gob nom org ',\n 'et':' biz com edu gov info name net org ',\n 'fj':' ac biz com info mil name net org pro ',\n 'fk':' ac co gov net nom org ',\n 'fr':' asso com f gouv nom prd presse tm ',\n 'gg':' co net org ',\n 'gh':' com edu gov mil org ',\n 'gn':' ac com gov net org ',\n 'gr':' com edu gov mil net org ',\n 'gt':' com edu gob ind mil net org ',\n 'gu':' com edu gov net org ',\n 'hk':' com edu gov idv net org ',\n 'hu':' 2000 agrar bolt casino city co erotica erotika film forum games hotel info ingatlan jogasz konyvelo lakas media news org priv reklam sex shop sport suli szex tm tozsde utazas video ',\n 'id':' ac co go mil net or sch web ',\n 'il':' ac co gov idf k12 muni net org ',\n 'in':' ac co edu ernet firm gen gov i ind mil net nic org res ',\n 'iq':' com edu gov i mil net org ',\n 'ir':' ac co dnssec gov i id net org sch ',\n 'it':' edu gov ',\n 'je':' co net org ',\n 'jo':' com edu gov mil name net org sch ',\n 'jp':' ac ad co ed go gr lg ne or ',\n 'ke':' ac co go info me mobi ne or sc ',\n 'kh':' com edu gov mil net org per ',\n 'ki':' biz com de edu gov info mob net org tel ',\n 'km':' asso com coop edu gouv k medecin mil nom notaires pharmaciens presse tm veterinaire ',\n 'kn':' edu gov net org ',\n 'kr':' ac busan chungbuk chungnam co daegu daejeon es gangwon go gwangju gyeongbuk gyeonggi gyeongnam hs incheon jeju jeonbuk jeonnam k kg mil ms ne or pe re sc seoul ulsan ',\n 'kw':' com edu gov net org ',\n 'ky':' com edu gov net org ',\n 'kz':' com edu gov mil net org ',\n 'lb':' com edu gov net org ',\n 'lk':' assn com edu gov grp hotel int ltd net ngo org sch soc web ',\n 'lr':' com edu gov net org ',\n 'lv':' asn com conf edu gov id mil net org ',\n 'ly':' com edu gov id med net org plc sch ',\n 'ma':' ac co gov m net org press ',\n 'mc':' asso tm ',\n 'me':' ac co edu gov its net org priv ',\n 'mg':' com edu gov mil nom org prd tm ',\n 'mk':' com edu gov inf name net org pro ',\n 'ml':' com edu gov net org presse ',\n 'mn':' edu gov org ',\n 'mo':' com edu gov net org ',\n 'mt':' com edu gov net org ',\n 'mv':' aero biz com coop edu gov info int mil museum name net org pro ',\n 'mw':' ac co com coop edu gov int museum net org ',\n 'mx':' com edu gob net org ',\n 'my':' com edu gov mil name net org sch ',\n 'nf':' arts com firm info net other per rec store web ',\n 'ng':' biz com edu gov mil mobi name net org sch ',\n 'ni':' ac co com edu gob mil net nom org ',\n 'np':' com edu gov mil net org ',\n 'nr':' biz com edu gov info net org ',\n 'om':' ac biz co com edu gov med mil museum net org pro sch ',\n 'pe':' com edu gob mil net nom org sld ',\n 'ph':' com edu gov i mil net ngo org ',\n 'pk':' biz com edu fam gob gok gon gop gos gov net org web ',\n 'pl':' art bialystok biz com edu gda gdansk gorzow gov info katowice krakow lodz lublin mil net ngo olsztyn org poznan pwr radom slupsk szczecin torun warszawa waw wroc wroclaw zgora ',\n 'pr':' ac biz com edu est gov info isla name net org pro prof ',\n 'ps':' com edu gov net org plo sec ',\n 'pw':' belau co ed go ne or ',\n 'ro':' arts com firm info nom nt org rec store tm www ',\n 'rs':' ac co edu gov in org ',\n 'sb':' com edu gov net org ',\n 'sc':' com edu gov net org ',\n 'sh':' co com edu gov net nom org ',\n 'sl':' com edu gov net org ',\n 'st':' co com consulado edu embaixada gov mil net org principe saotome store ',\n 'sv':' com edu gob org red ',\n 'sz':' ac co org ',\n 'tr':' av bbs bel biz com dr edu gen gov info k12 name net org pol tel tsk tv web ',\n 'tt':' aero biz cat co com coop edu gov info int jobs mil mobi museum name net org pro tel travel ',\n 'tw':' club com ebiz edu game gov idv mil net org ',\n 'mu':' ac co com gov net or org ',\n 'mz':' ac co edu gov org ',\n 'na':' co com ',\n 'nz':' ac co cri geek gen govt health iwi maori mil net org parliament school ',\n 'pa':' abo ac com edu gob ing med net nom org sld ',\n 'pt':' com edu gov int net nome org publ ',\n 'py':' com edu gov mil net org ',\n 'qa':' com edu gov mil net org ',\n 're':' asso com nom ',\n 'ru':' ac adygeya altai amur arkhangelsk astrakhan bashkiria belgorod bir bryansk buryatia cbg chel chelyabinsk chita chukotka chuvashia com dagestan e-burg edu gov grozny int irkutsk ivanovo izhevsk jar joshkar-ola kalmykia kaluga kamchatka karelia kazan kchr kemerovo khabarovsk khakassia khv kirov koenig komi kostroma kranoyarsk kuban kurgan kursk lipetsk magadan mari mari-el marine mil mordovia mosreg msk murmansk nalchik net nnov nov novosibirsk nsk omsk orenburg org oryol penza perm pp pskov ptz rnd ryazan sakhalin samara saratov simbirsk smolensk spb stavropol stv surgut tambov tatarstan tom tomsk tsaritsyn tsk tula tuva tver tyumen udm udmurtia ulan-ude vladikavkaz vladimir vladivostok volgograd vologda voronezh vrn vyatka yakutia yamal yekaterinburg yuzhno-sakhalinsk ',\n 'rw':' ac co com edu gouv gov int mil net ',\n 'sa':' com edu gov med net org pub sch ',\n 'sd':' com edu gov info med net org tv ',\n 'se':' a ac b bd c d e f g h i k l m n o org p parti pp press r s t tm u w x y z ',\n 'sg':' com edu gov idn net org per ',\n 'sn':' art com edu gouv org perso univ ',\n 'sy':' com edu gov mil net news org ',\n 'th':' ac co go in mi net or ',\n 'tj':' ac biz co com edu go gov info int mil name net nic org test web ',\n 'tn':' agrinet com defense edunet ens fin gov ind info intl mincom nat net org perso rnrt rns rnu tourism ',\n 'tz':' ac co go ne or ',\n 'ua':' biz cherkassy chernigov chernovtsy ck cn co com crimea cv dn dnepropetrovsk donetsk dp edu gov if in ivano-frankivsk kh kharkov kherson khmelnitskiy kiev kirovograd km kr ks kv lg lugansk lutsk lviv me mk net nikolaev od odessa org pl poltava pp rovno rv sebastopol sumy te ternopil uzhgorod vinnica vn zaporizhzhe zhitomir zp zt ',\n 'ug':' ac co go ne or org sc ',\n 'uk':' ac bl british-library co cym gov govt icnet jet lea ltd me mil mod national-library-scotland nel net nhs nic nls org orgn parliament plc police sch scot soc ',\n 'us':' dni fed isa kids nsn ',\n 'uy':' com edu gub mil net org ',\n 've':' co com edu gob info mil net org web ',\n 'vi':' co com k12 net org ',\n 'vn':' ac biz com edu gov health info int name net org pro ',\n 'ye':' co com gov ltd me net org plc ',\n 'yu':' ac co edu gov org ',\n 'za':' ac agric alt bourse city co cybernet db edu gov grondar iaccess imt inca landesign law mil net ngo nis nom olivetti org pix school tm web ',\n 'zm':' ac co com edu gov net org sch '\n },\n // gorhill 2013-10-25: Using indexOf() instead Regexp(). Significant boost\n // in both performance and memory footprint. No initialization required.\n // http://jsperf.com/uri-js-sld-regex-vs-binary-search/4\n // Following methods use lastIndexOf() rather than array.split() in order\n // to avoid any memory allocations.\n has: function(domain) {\n var tldOffset = domain.lastIndexOf('.');\n if (tldOffset <= 0 || tldOffset >= (domain.length-1)) {\n return false;\n }\n var sldOffset = domain.lastIndexOf('.', tldOffset-1);\n if (sldOffset <= 0 || sldOffset >= (tldOffset-1)) {\n return false;\n }\n var sldList = SLD.list[domain.slice(tldOffset+1)];\n if (!sldList) {\n return false;\n }\n return sldList.indexOf(' ' + domain.slice(sldOffset+1, tldOffset) + ' ') >= 0;\n },\n is: function(domain) {\n var tldOffset = domain.lastIndexOf('.');\n if (tldOffset <= 0 || tldOffset >= (domain.length-1)) {\n return false;\n }\n var sldOffset = domain.lastIndexOf('.', tldOffset-1);\n if (sldOffset >= 0) {\n return false;\n }\n var sldList = SLD.list[domain.slice(tldOffset+1)];\n if (!sldList) {\n return false;\n }\n return sldList.indexOf(' ' + domain.slice(0, tldOffset) + ' ') >= 0;\n },\n get: function(domain) {\n var tldOffset = domain.lastIndexOf('.');\n if (tldOffset <= 0 || tldOffset >= (domain.length-1)) {\n return null;\n }\n var sldOffset = domain.lastIndexOf('.', tldOffset-1);\n if (sldOffset <= 0 || sldOffset >= (tldOffset-1)) {\n return null;\n }\n var sldList = SLD.list[domain.slice(tldOffset+1)];\n if (!sldList) {\n return null;\n }\n if (sldList.indexOf(' ' + domain.slice(sldOffset+1, tldOffset) + ' ') < 0) {\n return null;\n }\n return domain.slice(sldOffset+1);\n },\n noConflict: function(){\n if (root.SecondLevelDomains === this) {\n root.SecondLevelDomains = _SecondLevelDomains;\n }\n return this;\n }\n };\n\n return SLD;\n}));\n","/*!\n * URI.js - Mutating URLs\n *\n * Version: 1.18.1\n *\n * Author: Rodney Rehm\n * Web: http://medialize.github.io/URI.js/\n *\n * Licensed under\n * MIT License http://www.opensource.org/licenses/mit-license\n *\n */\n(function (root, factory) {\n 'use strict';\n // https://github.com/umdjs/umd/blob/master/returnExports.js\n if (typeof exports === 'object') {\n // Node\n module.exports = factory(require('./punycode'), require('./IPv6'), require('./SecondLevelDomains'));\n } else if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define(['./punycode', './IPv6', './SecondLevelDomains'], factory);\n } else {\n // Browser globals (root is window)\n root.URI = factory(root.punycode, root.IPv6, root.SecondLevelDomains, root);\n }\n}(this, function (punycode, IPv6, SLD, root) {\n 'use strict';\n /*global location, escape, unescape */\n // FIXME: v2.0.0 renamce non-camelCase properties to uppercase\n /*jshint camelcase: false */\n\n // save current URI variable, if any\n var _URI = root && root.URI;\n\n function URI(url, base) {\n var _urlSupplied = arguments.length >= 1;\n var _baseSupplied = arguments.length >= 2;\n\n // Allow instantiation without the 'new' keyword\n if (!(this instanceof URI)) {\n if (_urlSupplied) {\n if (_baseSupplied) {\n return new URI(url, base);\n }\n\n return new URI(url);\n }\n\n return new URI();\n }\n\n if (url === undefined) {\n if (_urlSupplied) {\n throw new TypeError('undefined is not a valid argument for URI');\n }\n\n if (typeof location !== 'undefined') {\n url = location.href + '';\n } else {\n url = '';\n }\n }\n\n this.href(url);\n\n // resolve to base according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#constructor\n if (base !== undefined) {\n return this.absoluteTo(base);\n }\n\n return this;\n }\n\n URI.version = '1.18.1';\n\n var p = URI.prototype;\n var hasOwn = Object.prototype.hasOwnProperty;\n\n function escapeRegEx(string) {\n // https://github.com/medialize/URI.js/commit/85ac21783c11f8ccab06106dba9735a31a86924d#commitcomment-821963\n return string.replace(/([.*+?^=!:${}()|[\\]\\/\\\\])/g, '\\\\$1');\n }\n\n function getType(value) {\n // IE8 doesn't return [Object Undefined] but [Object Object] for undefined value\n if (value === undefined) {\n return 'Undefined';\n }\n\n return String(Object.prototype.toString.call(value)).slice(8, -1);\n }\n\n function isArray(obj) {\n return getType(obj) === 'Array';\n }\n\n function filterArrayValues(data, value) {\n var lookup = {};\n var i, length;\n\n if (getType(value) === 'RegExp') {\n lookup = null;\n } else if (isArray(value)) {\n for (i = 0, length = value.length; i < length; i++) {\n lookup[value[i]] = true;\n }\n } else {\n lookup[value] = true;\n }\n\n for (i = 0, length = data.length; i < length; i++) {\n /*jshint laxbreak: true */\n var _match = lookup && lookup[data[i]] !== undefined\n || !lookup && value.test(data[i]);\n /*jshint laxbreak: false */\n if (_match) {\n data.splice(i, 1);\n length--;\n i--;\n }\n }\n\n return data;\n }\n\n function arrayContains(list, value) {\n var i, length;\n\n // value may be string, number, array, regexp\n if (isArray(value)) {\n // Note: this can be optimized to O(n) (instead of current O(m * n))\n for (i = 0, length = value.length; i < length; i++) {\n if (!arrayContains(list, value[i])) {\n return false;\n }\n }\n\n return true;\n }\n\n var _type = getType(value);\n for (i = 0, length = list.length; i < length; i++) {\n if (_type === 'RegExp') {\n if (typeof list[i] === 'string' && list[i].match(value)) {\n return true;\n }\n } else if (list[i] === value) {\n return true;\n }\n }\n\n return false;\n }\n\n function arraysEqual(one, two) {\n if (!isArray(one) || !isArray(two)) {\n return false;\n }\n\n // arrays can't be equal if they have different amount of content\n if (one.length !== two.length) {\n return false;\n }\n\n one.sort();\n two.sort();\n\n for (var i = 0, l = one.length; i < l; i++) {\n if (one[i] !== two[i]) {\n return false;\n }\n }\n\n return true;\n }\n\n function trimSlashes(text) {\n var trim_expression = /^\\/+|\\/+$/g;\n return text.replace(trim_expression, '');\n }\n\n URI._parts = function() {\n return {\n protocol: null,\n username: null,\n password: null,\n hostname: null,\n urn: null,\n port: null,\n path: null,\n query: null,\n fragment: null,\n // state\n duplicateQueryParameters: URI.duplicateQueryParameters,\n escapeQuerySpace: URI.escapeQuerySpace\n };\n };\n // state: allow duplicate query parameters (a=1&a=1)\n URI.duplicateQueryParameters = false;\n // state: replaces + with %20 (space in query strings)\n URI.escapeQuerySpace = true;\n // static properties\n URI.protocol_expression = /^[a-z][a-z0-9.+-]*$/i;\n URI.idn_expression = /[^a-z0-9\\.-]/i;\n URI.punycode_expression = /(xn--)/i;\n // well, 333.444.555.666 matches, but it sure ain't no IPv4 - do we care?\n URI.ip4_expression = /^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/;\n // credits to Rich Brown\n // source: http://forums.intermapper.com/viewtopic.php?p=1096#1096\n // specification: http://www.ietf.org/rfc/rfc4291.txt\n URI.ip6_expression = /^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$/;\n // expression used is \"gruber revised\" (@gruber v2) determined to be the\n // best solution in a regex-golf we did a couple of ages ago at\n // * http://mathiasbynens.be/demo/url-regex\n // * http://rodneyrehm.de/t/url-regex.html\n URI.find_uri_expression = /\\b((?:[a-z][\\w-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'\".,<>?«»“”‘’]))/ig;\n URI.findUri = {\n // valid \"scheme://\" or \"www.\"\n start: /\\b(?:([a-z][a-z0-9.+-]*:\\/\\/)|www\\.)/gi,\n // everything up to the next whitespace\n end: /[\\s\\r\\n]|$/,\n // trim trailing punctuation captured by end RegExp\n trim: /[`!()\\[\\]{};:'\".,<>?«»“”„‘’]+$/\n };\n // http://www.iana.org/assignments/uri-schemes.html\n // http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers#Well-known_ports\n URI.defaultPorts = {\n http: '80',\n https: '443',\n ftp: '21',\n gopher: '70',\n ws: '80',\n wss: '443'\n };\n // allowed hostname characters according to RFC 3986\n // ALPHA DIGIT \"-\" \".\" \"_\" \"~\" \"!\" \"$\" \"&\" \"'\" \"(\" \")\" \"*\" \"+\" \",\" \";\" \"=\" %encoded\n // I've never seen a (non-IDN) hostname other than: ALPHA DIGIT . -\n URI.invalid_hostname_characters = /[^a-zA-Z0-9\\.-]/;\n // map DOM Elements to their URI attribute\n URI.domAttributes = {\n 'a': 'href',\n 'blockquote': 'cite',\n 'link': 'href',\n 'base': 'href',\n 'script': 'src',\n 'form': 'action',\n 'img': 'src',\n 'area': 'href',\n 'iframe': 'src',\n 'embed': 'src',\n 'source': 'src',\n 'track': 'src',\n 'input': 'src', // but only if type=\"image\"\n 'audio': 'src',\n 'video': 'src'\n };\n URI.getDomAttribute = function(node) {\n if (!node || !node.nodeName) {\n return undefined;\n }\n\n var nodeName = node.nodeName.toLowerCase();\n // should only expose src for type=\"image\"\n if (nodeName === 'input' && node.type !== 'image') {\n return undefined;\n }\n\n return URI.domAttributes[nodeName];\n };\n\n function escapeForDumbFirefox36(value) {\n // https://github.com/medialize/URI.js/issues/91\n return escape(value);\n }\n\n // encoding / decoding according to RFC3986\n function strictEncodeURIComponent(string) {\n // see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/encodeURIComponent\n return encodeURIComponent(string)\n .replace(/[!'()*]/g, escapeForDumbFirefox36)\n .replace(/\\*/g, '%2A');\n }\n URI.encode = strictEncodeURIComponent;\n URI.decode = decodeURIComponent;\n URI.iso8859 = function() {\n URI.encode = escape;\n URI.decode = unescape;\n };\n URI.unicode = function() {\n URI.encode = strictEncodeURIComponent;\n URI.decode = decodeURIComponent;\n };\n URI.characters = {\n pathname: {\n encode: {\n // RFC3986 2.1: For consistency, URI producers and normalizers should\n // use uppercase hexadecimal digits for all percent-encodings.\n expression: /%(24|26|2B|2C|3B|3D|3A|40)/ig,\n map: {\n // -._~!'()*\n '%24': '$',\n '%26': '&',\n '%2B': '+',\n '%2C': ',',\n '%3B': ';',\n '%3D': '=',\n '%3A': ':',\n '%40': '@'\n }\n },\n decode: {\n expression: /[\\/\\?#]/g,\n map: {\n '/': '%2F',\n '?': '%3F',\n '#': '%23'\n }\n }\n },\n reserved: {\n encode: {\n // RFC3986 2.1: For consistency, URI producers and normalizers should\n // use uppercase hexadecimal digits for all percent-encodings.\n expression: /%(21|23|24|26|27|28|29|2A|2B|2C|2F|3A|3B|3D|3F|40|5B|5D)/ig,\n map: {\n // gen-delims\n '%3A': ':',\n '%2F': '/',\n '%3F': '?',\n '%23': '#',\n '%5B': '[',\n '%5D': ']',\n '%40': '@',\n // sub-delims\n '%21': '!',\n '%24': '$',\n '%26': '&',\n '%27': '\\'',\n '%28': '(',\n '%29': ')',\n '%2A': '*',\n '%2B': '+',\n '%2C': ',',\n '%3B': ';',\n '%3D': '='\n }\n }\n },\n urnpath: {\n // The characters under `encode` are the characters called out by RFC 2141 as being acceptable\n // for usage in a URN. RFC2141 also calls out \"-\", \".\", and \"_\" as acceptable characters, but\n // these aren't encoded by encodeURIComponent, so we don't have to call them out here. Also\n // note that the colon character is not featured in the encoding map; this is because URI.js\n // gives the colons in URNs semantic meaning as the delimiters of path segements, and so it\n // should not appear unencoded in a segment itself.\n // See also the note above about RFC3986 and capitalalized hex digits.\n encode: {\n expression: /%(21|24|27|28|29|2A|2B|2C|3B|3D|40)/ig,\n map: {\n '%21': '!',\n '%24': '$',\n '%27': '\\'',\n '%28': '(',\n '%29': ')',\n '%2A': '*',\n '%2B': '+',\n '%2C': ',',\n '%3B': ';',\n '%3D': '=',\n '%40': '@'\n }\n },\n // These characters are the characters called out by RFC2141 as \"reserved\" characters that\n // should never appear in a URN, plus the colon character (see note above).\n decode: {\n expression: /[\\/\\?#:]/g,\n map: {\n '/': '%2F',\n '?': '%3F',\n '#': '%23',\n ':': '%3A'\n }\n }\n }\n };\n URI.encodeQuery = function(string, escapeQuerySpace) {\n var escaped = URI.encode(string + '');\n if (escapeQuerySpace === undefined) {\n escapeQuerySpace = URI.escapeQuerySpace;\n }\n\n return escapeQuerySpace ? escaped.replace(/%20/g, '+') : escaped;\n };\n URI.decodeQuery = function(string, escapeQuerySpace) {\n string += '';\n if (escapeQuerySpace === undefined) {\n escapeQuerySpace = URI.escapeQuerySpace;\n }\n\n try {\n return URI.decode(escapeQuerySpace ? string.replace(/\\+/g, '%20') : string);\n } catch(e) {\n // we're not going to mess with weird encodings,\n // give up and return the undecoded original string\n // see https://github.com/medialize/URI.js/issues/87\n // see https://github.com/medialize/URI.js/issues/92\n return string;\n }\n };\n // generate encode/decode path functions\n var _parts = {'encode':'encode', 'decode':'decode'};\n var _part;\n var generateAccessor = function(_group, _part) {\n return function(string) {\n try {\n return URI[_part](string + '').replace(URI.characters[_group][_part].expression, function(c) {\n return URI.characters[_group][_part].map[c];\n });\n } catch (e) {\n // we're not going to mess with weird encodings,\n // give up and return the undecoded original string\n // see https://github.com/medialize/URI.js/issues/87\n // see https://github.com/medialize/URI.js/issues/92\n return string;\n }\n };\n };\n\n for (_part in _parts) {\n URI[_part + 'PathSegment'] = generateAccessor('pathname', _parts[_part]);\n URI[_part + 'UrnPathSegment'] = generateAccessor('urnpath', _parts[_part]);\n }\n\n var generateSegmentedPathFunction = function(_sep, _codingFuncName, _innerCodingFuncName) {\n return function(string) {\n // Why pass in names of functions, rather than the function objects themselves? The\n // definitions of some functions (but in particular, URI.decode) will occasionally change due\n // to URI.js having ISO8859 and Unicode modes. Passing in the name and getting it will ensure\n // that the functions we use here are \"fresh\".\n var actualCodingFunc;\n if (!_innerCodingFuncName) {\n actualCodingFunc = URI[_codingFuncName];\n } else {\n actualCodingFunc = function(string) {\n return URI[_codingFuncName](URI[_innerCodingFuncName](string));\n };\n }\n\n var segments = (string + '').split(_sep);\n\n for (var i = 0, length = segments.length; i < length; i++) {\n segments[i] = actualCodingFunc(segments[i]);\n }\n\n return segments.join(_sep);\n };\n };\n\n // This takes place outside the above loop because we don't want, e.g., encodeUrnPath functions.\n URI.decodePath = generateSegmentedPathFunction('/', 'decodePathSegment');\n URI.decodeUrnPath = generateSegmentedPathFunction(':', 'decodeUrnPathSegment');\n URI.recodePath = generateSegmentedPathFunction('/', 'encodePathSegment', 'decode');\n URI.recodeUrnPath = generateSegmentedPathFunction(':', 'encodeUrnPathSegment', 'decode');\n\n URI.encodeReserved = generateAccessor('reserved', 'encode');\n\n URI.parse = function(string, parts) {\n var pos;\n if (!parts) {\n parts = {};\n }\n // [protocol\"://\"[username[\":\"password]\"@\"]hostname[\":\"port]\"/\"?][path][\"?\"querystring][\"#\"fragment]\n\n // extract fragment\n pos = string.indexOf('#');\n if (pos > -1) {\n // escaping?\n parts.fragment = string.substring(pos + 1) || null;\n string = string.substring(0, pos);\n }\n\n // extract query\n pos = string.indexOf('?');\n if (pos > -1) {\n // escaping?\n parts.query = string.substring(pos + 1) || null;\n string = string.substring(0, pos);\n }\n\n // extract protocol\n if (string.substring(0, 2) === '//') {\n // relative-scheme\n parts.protocol = null;\n string = string.substring(2);\n // extract \"user:pass@host:port\"\n string = URI.parseAuthority(string, parts);\n } else {\n pos = string.indexOf(':');\n if (pos > -1) {\n parts.protocol = string.substring(0, pos) || null;\n if (parts.protocol && !parts.protocol.match(URI.protocol_expression)) {\n // : may be within the path\n parts.protocol = undefined;\n } else if (string.substring(pos + 1, pos + 3) === '//') {\n string = string.substring(pos + 3);\n\n // extract \"user:pass@host:port\"\n string = URI.parseAuthority(string, parts);\n } else {\n string = string.substring(pos + 1);\n parts.urn = true;\n }\n }\n }\n\n // what's left must be the path\n parts.path = string;\n\n // and we're done\n return parts;\n };\n URI.parseHost = function(string, parts) {\n // Copy chrome, IE, opera backslash-handling behavior.\n // Back slashes before the query string get converted to forward slashes\n // See: https://github.com/joyent/node/blob/386fd24f49b0e9d1a8a076592a404168faeecc34/lib/url.js#L115-L124\n // See: https://code.google.com/p/chromium/issues/detail?id=25916\n // https://github.com/medialize/URI.js/pull/233\n string = string.replace(/\\\\/g, '/');\n\n // extract host:port\n var pos = string.indexOf('/');\n var bracketPos;\n var t;\n\n if (pos === -1) {\n pos = string.length;\n }\n\n if (string.charAt(0) === '[') {\n // IPv6 host - http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-04#section-6\n // I claim most client software breaks on IPv6 anyways. To simplify things, URI only accepts\n // IPv6+port in the format [2001:db8::1]:80 (for the time being)\n bracketPos = string.indexOf(']');\n parts.hostname = string.substring(1, bracketPos) || null;\n parts.port = string.substring(bracketPos + 2, pos) || null;\n if (parts.port === '/') {\n parts.port = null;\n }\n } else {\n var firstColon = string.indexOf(':');\n var firstSlash = string.indexOf('/');\n var nextColon = string.indexOf(':', firstColon + 1);\n if (nextColon !== -1 && (firstSlash === -1 || nextColon < firstSlash)) {\n // IPv6 host contains multiple colons - but no port\n // this notation is actually not allowed by RFC 3986, but we're a liberal parser\n parts.hostname = string.substring(0, pos) || null;\n parts.port = null;\n } else {\n t = string.substring(0, pos).split(':');\n parts.hostname = t[0] || null;\n parts.port = t[1] || null;\n }\n }\n\n if (parts.hostname && string.substring(pos).charAt(0) !== '/') {\n pos++;\n string = '/' + string;\n }\n\n return string.substring(pos) || '/';\n };\n URI.parseAuthority = function(string, parts) {\n string = URI.parseUserinfo(string, parts);\n return URI.parseHost(string, parts);\n };\n URI.parseUserinfo = function(string, parts) {\n // extract username:password\n var firstSlash = string.indexOf('/');\n var pos = string.lastIndexOf('@', firstSlash > -1 ? firstSlash : string.length - 1);\n var t;\n\n // authority@ must come before /path\n if (pos > -1 && (firstSlash === -1 || pos < firstSlash)) {\n t = string.substring(0, pos).split(':');\n parts.username = t[0] ? URI.decode(t[0]) : null;\n t.shift();\n parts.password = t[0] ? URI.decode(t.join(':')) : null;\n string = string.substring(pos + 1);\n } else {\n parts.username = null;\n parts.password = null;\n }\n\n return string;\n };\n URI.parseQuery = function(string, escapeQuerySpace) {\n if (!string) {\n return {};\n }\n\n // throw out the funky business - \"?\"[name\"=\"value\"&\"]+\n string = string.replace(/&+/g, '&').replace(/^\\?*&*|&+$/g, '');\n\n if (!string) {\n return {};\n }\n\n var items = {};\n var splits = string.split('&');\n var length = splits.length;\n var v, name, value;\n\n for (var i = 0; i < length; i++) {\n v = splits[i].split('=');\n name = URI.decodeQuery(v.shift(), escapeQuerySpace);\n // no \"=\" is null according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#collect-url-parameters\n value = v.length ? URI.decodeQuery(v.join('='), escapeQuerySpace) : null;\n\n if (hasOwn.call(items, name)) {\n if (typeof items[name] === 'string' || items[name] === null) {\n items[name] = [items[name]];\n }\n\n items[name].push(value);\n } else {\n items[name] = value;\n }\n }\n\n return items;\n };\n\n URI.build = function(parts) {\n var t = '';\n\n if (parts.protocol) {\n t += parts.protocol + ':';\n }\n\n if (!parts.urn && (t || parts.hostname)) {\n t += '//';\n }\n\n t += (URI.buildAuthority(parts) || '');\n\n if (typeof parts.path === 'string') {\n if (parts.path.charAt(0) !== '/' && typeof parts.hostname === 'string') {\n t += '/';\n }\n\n t += parts.path;\n }\n\n if (typeof parts.query === 'string' && parts.query) {\n t += '?' + parts.query;\n }\n\n if (typeof parts.fragment === 'string' && parts.fragment) {\n t += '#' + parts.fragment;\n }\n return t;\n };\n URI.buildHost = function(parts) {\n var t = '';\n\n if (!parts.hostname) {\n return '';\n } else if (URI.ip6_expression.test(parts.hostname)) {\n t += '[' + parts.hostname + ']';\n } else {\n t += parts.hostname;\n }\n\n if (parts.port) {\n t += ':' + parts.port;\n }\n\n return t;\n };\n URI.buildAuthority = function(parts) {\n return URI.buildUserinfo(parts) + URI.buildHost(parts);\n };\n URI.buildUserinfo = function(parts) {\n var t = '';\n\n if (parts.username) {\n t += URI.encode(parts.username);\n }\n\n if (parts.password) {\n t += ':' + URI.encode(parts.password);\n }\n\n if (t) {\n t += '@';\n }\n\n return t;\n };\n URI.buildQuery = function(data, duplicateQueryParameters, escapeQuerySpace) {\n // according to http://tools.ietf.org/html/rfc3986 or http://labs.apache.org/webarch/uri/rfc/rfc3986.html\n // being »-._~!$&'()*+,;=:@/?« %HEX and alnum are allowed\n // the RFC explicitly states ?/foo being a valid use case, no mention of parameter syntax!\n // URI.js treats the query string as being application/x-www-form-urlencoded\n // see http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type\n\n var t = '';\n var unique, key, i, length;\n for (key in data) {\n if (hasOwn.call(data, key) && key) {\n if (isArray(data[key])) {\n unique = {};\n for (i = 0, length = data[key].length; i < length; i++) {\n if (data[key][i] !== undefined && unique[data[key][i] + ''] === undefined) {\n t += '&' + URI.buildQueryParameter(key, data[key][i], escapeQuerySpace);\n if (duplicateQueryParameters !== true) {\n unique[data[key][i] + ''] = true;\n }\n }\n }\n } else if (data[key] !== undefined) {\n t += '&' + URI.buildQueryParameter(key, data[key], escapeQuerySpace);\n }\n }\n }\n\n return t.substring(1);\n };\n URI.buildQueryParameter = function(name, value, escapeQuerySpace) {\n // http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type -- application/x-www-form-urlencoded\n // don't append \"=\" for null values, according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#url-parameter-serialization\n return URI.encodeQuery(name, escapeQuerySpace) + (value !== null ? '=' + URI.encodeQuery(value, escapeQuerySpace) : '');\n };\n\n URI.addQuery = function(data, name, value) {\n if (typeof name === 'object') {\n for (var key in name) {\n if (hasOwn.call(name, key)) {\n URI.addQuery(data, key, name[key]);\n }\n }\n } else if (typeof name === 'string') {\n if (data[name] === undefined) {\n data[name] = value;\n return;\n } else if (typeof data[name] === 'string') {\n data[name] = [data[name]];\n }\n\n if (!isArray(value)) {\n value = [value];\n }\n\n data[name] = (data[name] || []).concat(value);\n } else {\n throw new TypeError('URI.addQuery() accepts an object, string as the name parameter');\n }\n };\n URI.removeQuery = function(data, name, value) {\n var i, length, key;\n\n if (isArray(name)) {\n for (i = 0, length = name.length; i < length; i++) {\n data[name[i]] = undefined;\n }\n } else if (getType(name) === 'RegExp') {\n for (key in data) {\n if (name.test(key)) {\n data[key] = undefined;\n }\n }\n } else if (typeof name === 'object') {\n for (key in name) {\n if (hasOwn.call(name, key)) {\n URI.removeQuery(data, key, name[key]);\n }\n }\n } else if (typeof name === 'string') {\n if (value !== undefined) {\n if (getType(value) === 'RegExp') {\n if (!isArray(data[name]) && value.test(data[name])) {\n data[name] = undefined;\n } else {\n data[name] = filterArrayValues(data[name], value);\n }\n } else if (data[name] === String(value) && (!isArray(value) || value.length === 1)) {\n data[name] = undefined;\n } else if (isArray(data[name])) {\n data[name] = filterArrayValues(data[name], value);\n }\n } else {\n data[name] = undefined;\n }\n } else {\n throw new TypeError('URI.removeQuery() accepts an object, string, RegExp as the first parameter');\n }\n };\n URI.hasQuery = function(data, name, value, withinArray) {\n switch (getType(name)) {\n case 'String':\n // Nothing to do here\n break;\n\n case 'RegExp':\n for (var key in data) {\n if (hasOwn.call(data, key)) {\n if (name.test(key) && (value === undefined || URI.hasQuery(data, key, value))) {\n return true;\n }\n }\n }\n\n return false;\n\n case 'Object':\n for (var _key in name) {\n if (hasOwn.call(name, _key)) {\n if (!URI.hasQuery(data, _key, name[_key])) {\n return false;\n }\n }\n }\n\n return true;\n\n default:\n throw new TypeError('URI.hasQuery() accepts a string, regular expression or object as the name parameter');\n }\n\n switch (getType(value)) {\n case 'Undefined':\n // true if exists (but may be empty)\n return name in data; // data[name] !== undefined;\n\n case 'Boolean':\n // true if exists and non-empty\n var _booly = Boolean(isArray(data[name]) ? data[name].length : data[name]);\n return value === _booly;\n\n case 'Function':\n // allow complex comparison\n return !!value(data[name], name, data);\n\n case 'Array':\n if (!isArray(data[name])) {\n return false;\n }\n\n var op = withinArray ? arrayContains : arraysEqual;\n return op(data[name], value);\n\n case 'RegExp':\n if (!isArray(data[name])) {\n return Boolean(data[name] && data[name].match(value));\n }\n\n if (!withinArray) {\n return false;\n }\n\n return arrayContains(data[name], value);\n\n case 'Number':\n value = String(value);\n /* falls through */\n case 'String':\n if (!isArray(data[name])) {\n return data[name] === value;\n }\n\n if (!withinArray) {\n return false;\n }\n\n return arrayContains(data[name], value);\n\n default:\n throw new TypeError('URI.hasQuery() accepts undefined, boolean, string, number, RegExp, Function as the value parameter');\n }\n };\n\n\n URI.joinPaths = function() {\n var input = [];\n var segments = [];\n var nonEmptySegments = 0;\n\n for (var i = 0; i < arguments.length; i++) {\n var url = new URI(arguments[i]);\n input.push(url);\n var _segments = url.segment();\n for (var s = 0; s < _segments.length; s++) {\n if (typeof _segments[s] === 'string') {\n segments.push(_segments[s]);\n }\n\n if (_segments[s]) {\n nonEmptySegments++;\n }\n }\n }\n\n if (!segments.length || !nonEmptySegments) {\n return new URI('');\n }\n\n var uri = new URI('').segment(segments);\n\n if (input[0].path() === '' || input[0].path().slice(0, 1) === '/') {\n uri.path('/' + uri.path());\n }\n\n return uri.normalize();\n };\n\n URI.commonPath = function(one, two) {\n var length = Math.min(one.length, two.length);\n var pos;\n\n // find first non-matching character\n for (pos = 0; pos < length; pos++) {\n if (one.charAt(pos) !== two.charAt(pos)) {\n pos--;\n break;\n }\n }\n\n if (pos < 1) {\n return one.charAt(0) === two.charAt(0) && one.charAt(0) === '/' ? '/' : '';\n }\n\n // revert to last /\n if (one.charAt(pos) !== '/' || two.charAt(pos) !== '/') {\n pos = one.substring(0, pos).lastIndexOf('/');\n }\n\n return one.substring(0, pos + 1);\n };\n\n URI.withinString = function(string, callback, options) {\n options || (options = {});\n var _start = options.start || URI.findUri.start;\n var _end = options.end || URI.findUri.end;\n var _trim = options.trim || URI.findUri.trim;\n var _attributeOpen = /[a-z0-9-]=[\"']?$/i;\n\n _start.lastIndex = 0;\n while (true) {\n var match = _start.exec(string);\n if (!match) {\n break;\n }\n\n var start = match.index;\n if (options.ignoreHtml) {\n // attribut(e=[\"']?$)\n var attributeOpen = string.slice(Math.max(start - 3, 0), start);\n if (attributeOpen && _attributeOpen.test(attributeOpen)) {\n continue;\n }\n }\n\n var end = start + string.slice(start).search(_end);\n var slice = string.slice(start, end).replace(_trim, '');\n if (options.ignore && options.ignore.test(slice)) {\n continue;\n }\n\n end = start + slice.length;\n var result = callback(slice, start, end, string);\n string = string.slice(0, start) + result + string.slice(end);\n _start.lastIndex = start + result.length;\n }\n\n _start.lastIndex = 0;\n return string;\n };\n\n URI.ensureValidHostname = function(v) {\n // Theoretically URIs allow percent-encoding in Hostnames (according to RFC 3986)\n // they are not part of DNS and therefore ignored by URI.js\n\n if (v.match(URI.invalid_hostname_characters)) {\n // test punycode\n if (!punycode) {\n throw new TypeError('Hostname \"' + v + '\" contains characters other than [A-Z0-9.-] and Punycode.js is not available');\n }\n\n if (punycode.toASCII(v).match(URI.invalid_hostname_characters)) {\n throw new TypeError('Hostname \"' + v + '\" contains characters other than [A-Z0-9.-]');\n }\n }\n };\n\n // noConflict\n URI.noConflict = function(removeAll) {\n if (removeAll) {\n var unconflicted = {\n URI: this.noConflict()\n };\n\n if (root.URITemplate && typeof root.URITemplate.noConflict === 'function') {\n unconflicted.URITemplate = root.URITemplate.noConflict();\n }\n\n if (root.IPv6 && typeof root.IPv6.noConflict === 'function') {\n unconflicted.IPv6 = root.IPv6.noConflict();\n }\n\n if (root.SecondLevelDomains && typeof root.SecondLevelDomains.noConflict === 'function') {\n unconflicted.SecondLevelDomains = root.SecondLevelDomains.noConflict();\n }\n\n return unconflicted;\n } else if (root.URI === this) {\n root.URI = _URI;\n }\n\n return this;\n };\n\n p.build = function(deferBuild) {\n if (deferBuild === true) {\n this._deferred_build = true;\n } else if (deferBuild === undefined || this._deferred_build) {\n this._string = URI.build(this._parts);\n this._deferred_build = false;\n }\n\n return this;\n };\n\n p.clone = function() {\n return new URI(this);\n };\n\n p.valueOf = p.toString = function() {\n return this.build(false)._string;\n };\n\n\n function generateSimpleAccessor(_part){\n return function(v, build) {\n if (v === undefined) {\n return this._parts[_part] || '';\n } else {\n this._parts[_part] = v || null;\n this.build(!build);\n return this;\n }\n };\n }\n\n function generatePrefixAccessor(_part, _key){\n return function(v, build) {\n if (v === undefined) {\n return this._parts[_part] || '';\n } else {\n if (v !== null) {\n v = v + '';\n if (v.charAt(0) === _key) {\n v = v.substring(1);\n }\n }\n\n this._parts[_part] = v;\n this.build(!build);\n return this;\n }\n };\n }\n\n p.protocol = generateSimpleAccessor('protocol');\n p.username = generateSimpleAccessor('username');\n p.password = generateSimpleAccessor('password');\n p.hostname = generateSimpleAccessor('hostname');\n p.port = generateSimpleAccessor('port');\n p.query = generatePrefixAccessor('query', '?');\n p.fragment = generatePrefixAccessor('fragment', '#');\n\n p.search = function(v, build) {\n var t = this.query(v, build);\n return typeof t === 'string' && t.length ? ('?' + t) : t;\n };\n p.hash = function(v, build) {\n var t = this.fragment(v, build);\n return typeof t === 'string' && t.length ? ('#' + t) : t;\n };\n\n p.pathname = function(v, build) {\n if (v === undefined || v === true) {\n var res = this._parts.path || (this._parts.hostname ? '/' : '');\n return v ? (this._parts.urn ? URI.decodeUrnPath : URI.decodePath)(res) : res;\n } else {\n if (this._parts.urn) {\n this._parts.path = v ? URI.recodeUrnPath(v) : '';\n } else {\n this._parts.path = v ? URI.recodePath(v) : '/';\n }\n this.build(!build);\n return this;\n }\n };\n p.path = p.pathname;\n p.href = function(href, build) {\n var key;\n\n if (href === undefined) {\n return this.toString();\n }\n\n this._string = '';\n this._parts = URI._parts();\n\n var _URI = href instanceof URI;\n var _object = typeof href === 'object' && (href.hostname || href.path || href.pathname);\n if (href.nodeName) {\n var attribute = URI.getDomAttribute(href);\n href = href[attribute] || '';\n _object = false;\n }\n\n // window.location is reported to be an object, but it's not the sort\n // of object we're looking for:\n // * location.protocol ends with a colon\n // * location.query != object.search\n // * location.hash != object.fragment\n // simply serializing the unknown object should do the trick\n // (for location, not for everything...)\n if (!_URI && _object && href.pathname !== undefined) {\n href = href.toString();\n }\n\n if (typeof href === 'string' || href instanceof String) {\n this._parts = URI.parse(String(href), this._parts);\n } else if (_URI || _object) {\n var src = _URI ? href._parts : href;\n for (key in src) {\n if (hasOwn.call(this._parts, key)) {\n this._parts[key] = src[key];\n }\n }\n } else {\n throw new TypeError('invalid input');\n }\n\n this.build(!build);\n return this;\n };\n\n // identification accessors\n p.is = function(what) {\n var ip = false;\n var ip4 = false;\n var ip6 = false;\n var name = false;\n var sld = false;\n var idn = false;\n var punycode = false;\n var relative = !this._parts.urn;\n\n if (this._parts.hostname) {\n relative = false;\n ip4 = URI.ip4_expression.test(this._parts.hostname);\n ip6 = URI.ip6_expression.test(this._parts.hostname);\n ip = ip4 || ip6;\n name = !ip;\n sld = name && SLD && SLD.has(this._parts.hostname);\n idn = name && URI.idn_expression.test(this._parts.hostname);\n punycode = name && URI.punycode_expression.test(this._parts.hostname);\n }\n\n switch (what.toLowerCase()) {\n case 'relative':\n return relative;\n\n case 'absolute':\n return !relative;\n\n // hostname identification\n case 'domain':\n case 'name':\n return name;\n\n case 'sld':\n return sld;\n\n case 'ip':\n return ip;\n\n case 'ip4':\n case 'ipv4':\n case 'inet4':\n return ip4;\n\n case 'ip6':\n case 'ipv6':\n case 'inet6':\n return ip6;\n\n case 'idn':\n return idn;\n\n case 'url':\n return !this._parts.urn;\n\n case 'urn':\n return !!this._parts.urn;\n\n case 'punycode':\n return punycode;\n }\n\n return null;\n };\n\n // component specific input validation\n var _protocol = p.protocol;\n var _port = p.port;\n var _hostname = p.hostname;\n\n p.protocol = function(v, build) {\n if (v !== undefined) {\n if (v) {\n // accept trailing ://\n v = v.replace(/:(\\/\\/)?$/, '');\n\n if (!v.match(URI.protocol_expression)) {\n throw new TypeError('Protocol \"' + v + '\" contains characters other than [A-Z0-9.+-] or doesn\\'t start with [A-Z]');\n }\n }\n }\n return _protocol.call(this, v, build);\n };\n p.scheme = p.protocol;\n p.port = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v !== undefined) {\n if (v === 0) {\n v = null;\n }\n\n if (v) {\n v += '';\n if (v.charAt(0) === ':') {\n v = v.substring(1);\n }\n\n if (v.match(/[^0-9]/)) {\n throw new TypeError('Port \"' + v + '\" contains characters other than [0-9]');\n }\n }\n }\n return _port.call(this, v, build);\n };\n p.hostname = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v !== undefined) {\n var x = {};\n var res = URI.parseHost(v, x);\n if (res !== '/') {\n throw new TypeError('Hostname \"' + v + '\" contains characters other than [A-Z0-9.-]');\n }\n\n v = x.hostname;\n }\n return _hostname.call(this, v, build);\n };\n\n // compound accessors\n p.origin = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v === undefined) {\n var protocol = this.protocol();\n var authority = this.authority();\n if (!authority) {\n return '';\n }\n\n return (protocol ? protocol + '://' : '') + this.authority();\n } else {\n var origin = URI(v);\n this\n .protocol(origin.protocol())\n .authority(origin.authority())\n .build(!build);\n return this;\n }\n };\n p.host = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v === undefined) {\n return this._parts.hostname ? URI.buildHost(this._parts) : '';\n } else {\n var res = URI.parseHost(v, this._parts);\n if (res !== '/') {\n throw new TypeError('Hostname \"' + v + '\" contains characters other than [A-Z0-9.-]');\n }\n\n this.build(!build);\n return this;\n }\n };\n p.authority = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v === undefined) {\n return this._parts.hostname ? URI.buildAuthority(this._parts) : '';\n } else {\n var res = URI.parseAuthority(v, this._parts);\n if (res !== '/') {\n throw new TypeError('Hostname \"' + v + '\" contains characters other than [A-Z0-9.-]');\n }\n\n this.build(!build);\n return this;\n }\n };\n p.userinfo = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v === undefined) {\n var t = URI.buildUserinfo(this._parts);\n return t ? t.substring(0, t.length -1) : t;\n } else {\n if (v[v.length-1] !== '@') {\n v += '@';\n }\n\n URI.parseUserinfo(v, this._parts);\n this.build(!build);\n return this;\n }\n };\n p.resource = function(v, build) {\n var parts;\n\n if (v === undefined) {\n return this.path() + this.search() + this.hash();\n }\n\n parts = URI.parse(v);\n this._parts.path = parts.path;\n this._parts.query = parts.query;\n this._parts.fragment = parts.fragment;\n this.build(!build);\n return this;\n };\n\n // fraction accessors\n p.subdomain = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n // convenience, return \"www\" from \"www.example.org\"\n if (v === undefined) {\n if (!this._parts.hostname || this.is('IP')) {\n return '';\n }\n\n // grab domain and add another segment\n var end = this._parts.hostname.length - this.domain().length - 1;\n return this._parts.hostname.substring(0, end) || '';\n } else {\n var e = this._parts.hostname.length - this.domain().length;\n var sub = this._parts.hostname.substring(0, e);\n var replace = new RegExp('^' + escapeRegEx(sub));\n\n if (v && v.charAt(v.length - 1) !== '.') {\n v += '.';\n }\n\n if (v) {\n URI.ensureValidHostname(v);\n }\n\n this._parts.hostname = this._parts.hostname.replace(replace, v);\n this.build(!build);\n return this;\n }\n };\n p.domain = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (typeof v === 'boolean') {\n build = v;\n v = undefined;\n }\n\n // convenience, return \"example.org\" from \"www.example.org\"\n if (v === undefined) {\n if (!this._parts.hostname || this.is('IP')) {\n return '';\n }\n\n // if hostname consists of 1 or 2 segments, it must be the domain\n var t = this._parts.hostname.match(/\\./g);\n if (t && t.length < 2) {\n return this._parts.hostname;\n }\n\n // grab tld and add another segment\n var end = this._parts.hostname.length - this.tld(build).length - 1;\n end = this._parts.hostname.lastIndexOf('.', end -1) + 1;\n return this._parts.hostname.substring(end) || '';\n } else {\n if (!v) {\n throw new TypeError('cannot set domain empty');\n }\n\n URI.ensureValidHostname(v);\n\n if (!this._parts.hostname || this.is('IP')) {\n this._parts.hostname = v;\n } else {\n var replace = new RegExp(escapeRegEx(this.domain()) + '$');\n this._parts.hostname = this._parts.hostname.replace(replace, v);\n }\n\n this.build(!build);\n return this;\n }\n };\n p.tld = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (typeof v === 'boolean') {\n build = v;\n v = undefined;\n }\n\n // return \"org\" from \"www.example.org\"\n if (v === undefined) {\n if (!this._parts.hostname || this.is('IP')) {\n return '';\n }\n\n var pos = this._parts.hostname.lastIndexOf('.');\n var tld = this._parts.hostname.substring(pos + 1);\n\n if (build !== true && SLD && SLD.list[tld.toLowerCase()]) {\n return SLD.get(this._parts.hostname) || tld;\n }\n\n return tld;\n } else {\n var replace;\n\n if (!v) {\n throw new TypeError('cannot set TLD empty');\n } else if (v.match(/[^a-zA-Z0-9-]/)) {\n if (SLD && SLD.is(v)) {\n replace = new RegExp(escapeRegEx(this.tld()) + '$');\n this._parts.hostname = this._parts.hostname.replace(replace, v);\n } else {\n throw new TypeError('TLD \"' + v + '\" contains characters other than [A-Z0-9]');\n }\n } else if (!this._parts.hostname || this.is('IP')) {\n throw new ReferenceError('cannot set TLD on non-domain host');\n } else {\n replace = new RegExp(escapeRegEx(this.tld()) + '$');\n this._parts.hostname = this._parts.hostname.replace(replace, v);\n }\n\n this.build(!build);\n return this;\n }\n };\n p.directory = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v === undefined || v === true) {\n if (!this._parts.path && !this._parts.hostname) {\n return '';\n }\n\n if (this._parts.path === '/') {\n return '/';\n }\n\n var end = this._parts.path.length - this.filename().length - 1;\n var res = this._parts.path.substring(0, end) || (this._parts.hostname ? '/' : '');\n\n return v ? URI.decodePath(res) : res;\n\n } else {\n var e = this._parts.path.length - this.filename().length;\n var directory = this._parts.path.substring(0, e);\n var replace = new RegExp('^' + escapeRegEx(directory));\n\n // fully qualifier directories begin with a slash\n if (!this.is('relative')) {\n if (!v) {\n v = '/';\n }\n\n if (v.charAt(0) !== '/') {\n v = '/' + v;\n }\n }\n\n // directories always end with a slash\n if (v && v.charAt(v.length - 1) !== '/') {\n v += '/';\n }\n\n v = URI.recodePath(v);\n this._parts.path = this._parts.path.replace(replace, v);\n this.build(!build);\n return this;\n }\n };\n p.filename = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v === undefined || v === true) {\n if (!this._parts.path || this._parts.path === '/') {\n return '';\n }\n\n var pos = this._parts.path.lastIndexOf('/');\n var res = this._parts.path.substring(pos+1);\n\n return v ? URI.decodePathSegment(res) : res;\n } else {\n var mutatedDirectory = false;\n\n if (v.charAt(0) === '/') {\n v = v.substring(1);\n }\n\n if (v.match(/\\.?\\//)) {\n mutatedDirectory = true;\n }\n\n var replace = new RegExp(escapeRegEx(this.filename()) + '$');\n v = URI.recodePath(v);\n this._parts.path = this._parts.path.replace(replace, v);\n\n if (mutatedDirectory) {\n this.normalizePath(build);\n } else {\n this.build(!build);\n }\n\n return this;\n }\n };\n p.suffix = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v === undefined || v === true) {\n if (!this._parts.path || this._parts.path === '/') {\n return '';\n }\n\n var filename = this.filename();\n var pos = filename.lastIndexOf('.');\n var s, res;\n\n if (pos === -1) {\n return '';\n }\n\n // suffix may only contain alnum characters (yup, I made this up.)\n s = filename.substring(pos+1);\n res = (/^[a-z0-9%]+$/i).test(s) ? s : '';\n return v ? URI.decodePathSegment(res) : res;\n } else {\n if (v.charAt(0) === '.') {\n v = v.substring(1);\n }\n\n var suffix = this.suffix();\n var replace;\n\n if (!suffix) {\n if (!v) {\n return this;\n }\n\n this._parts.path += '.' + URI.recodePath(v);\n } else if (!v) {\n replace = new RegExp(escapeRegEx('.' + suffix) + '$');\n } else {\n replace = new RegExp(escapeRegEx(suffix) + '$');\n }\n\n if (replace) {\n v = URI.recodePath(v);\n this._parts.path = this._parts.path.replace(replace, v);\n }\n\n this.build(!build);\n return this;\n }\n };\n p.segment = function(segment, v, build) {\n var separator = this._parts.urn ? ':' : '/';\n var path = this.path();\n var absolute = path.substring(0, 1) === '/';\n var segments = path.split(separator);\n\n if (segment !== undefined && typeof segment !== 'number') {\n build = v;\n v = segment;\n segment = undefined;\n }\n\n if (segment !== undefined && typeof segment !== 'number') {\n throw new Error('Bad segment \"' + segment + '\", must be 0-based integer');\n }\n\n if (absolute) {\n segments.shift();\n }\n\n if (segment < 0) {\n // allow negative indexes to address from the end\n segment = Math.max(segments.length + segment, 0);\n }\n\n if (v === undefined) {\n /*jshint laxbreak: true */\n return segment === undefined\n ? segments\n : segments[segment];\n /*jshint laxbreak: false */\n } else if (segment === null || segments[segment] === undefined) {\n if (isArray(v)) {\n segments = [];\n // collapse empty elements within array\n for (var i=0, l=v.length; i < l; i++) {\n if (!v[i].length && (!segments.length || !segments[segments.length -1].length)) {\n continue;\n }\n\n if (segments.length && !segments[segments.length -1].length) {\n segments.pop();\n }\n\n segments.push(trimSlashes(v[i]));\n }\n } else if (v || typeof v === 'string') {\n v = trimSlashes(v);\n if (segments[segments.length -1] === '') {\n // empty trailing elements have to be overwritten\n // to prevent results such as /foo//bar\n segments[segments.length -1] = v;\n } else {\n segments.push(v);\n }\n }\n } else {\n if (v) {\n segments[segment] = trimSlashes(v);\n } else {\n segments.splice(segment, 1);\n }\n }\n\n if (absolute) {\n segments.unshift('');\n }\n\n return this.path(segments.join(separator), build);\n };\n p.segmentCoded = function(segment, v, build) {\n var segments, i, l;\n\n if (typeof segment !== 'number') {\n build = v;\n v = segment;\n segment = undefined;\n }\n\n if (v === undefined) {\n segments = this.segment(segment, v, build);\n if (!isArray(segments)) {\n segments = segments !== undefined ? URI.decode(segments) : undefined;\n } else {\n for (i = 0, l = segments.length; i < l; i++) {\n segments[i] = URI.decode(segments[i]);\n }\n }\n\n return segments;\n }\n\n if (!isArray(v)) {\n v = (typeof v === 'string' || v instanceof String) ? URI.encode(v) : v;\n } else {\n for (i = 0, l = v.length; i < l; i++) {\n v[i] = URI.encode(v[i]);\n }\n }\n\n return this.segment(segment, v, build);\n };\n\n // mutating query string\n var q = p.query;\n p.query = function(v, build) {\n if (v === true) {\n return URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);\n } else if (typeof v === 'function') {\n var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);\n var result = v.call(this, data);\n this._parts.query = URI.buildQuery(result || data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);\n this.build(!build);\n return this;\n } else if (v !== undefined && typeof v !== 'string') {\n this._parts.query = URI.buildQuery(v, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);\n this.build(!build);\n return this;\n } else {\n return q.call(this, v, build);\n }\n };\n p.setQuery = function(name, value, build) {\n var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);\n\n if (typeof name === 'string' || name instanceof String) {\n data[name] = value !== undefined ? value : null;\n } else if (typeof name === 'object') {\n for (var key in name) {\n if (hasOwn.call(name, key)) {\n data[key] = name[key];\n }\n }\n } else {\n throw new TypeError('URI.addQuery() accepts an object, string as the name parameter');\n }\n\n this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);\n if (typeof name !== 'string') {\n build = value;\n }\n\n this.build(!build);\n return this;\n };\n p.addQuery = function(name, value, build) {\n var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);\n URI.addQuery(data, name, value === undefined ? null : value);\n this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);\n if (typeof name !== 'string') {\n build = value;\n }\n\n this.build(!build);\n return this;\n };\n p.removeQuery = function(name, value, build) {\n var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);\n URI.removeQuery(data, name, value);\n this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);\n if (typeof name !== 'string') {\n build = value;\n }\n\n this.build(!build);\n return this;\n };\n p.hasQuery = function(name, value, withinArray) {\n var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);\n return URI.hasQuery(data, name, value, withinArray);\n };\n p.setSearch = p.setQuery;\n p.addSearch = p.addQuery;\n p.removeSearch = p.removeQuery;\n p.hasSearch = p.hasQuery;\n\n // sanitizing URLs\n p.normalize = function() {\n if (this._parts.urn) {\n return this\n .normalizeProtocol(false)\n .normalizePath(false)\n .normalizeQuery(false)\n .normalizeFragment(false)\n .build();\n }\n\n return this\n .normalizeProtocol(false)\n .normalizeHostname(false)\n .normalizePort(false)\n .normalizePath(false)\n .normalizeQuery(false)\n .normalizeFragment(false)\n .build();\n };\n p.normalizeProtocol = function(build) {\n if (typeof this._parts.protocol === 'string') {\n this._parts.protocol = this._parts.protocol.toLowerCase();\n this.build(!build);\n }\n\n return this;\n };\n p.normalizeHostname = function(build) {\n if (this._parts.hostname) {\n if (this.is('IDN') && punycode) {\n this._parts.hostname = punycode.toASCII(this._parts.hostname);\n } else if (this.is('IPv6') && IPv6) {\n this._parts.hostname = IPv6.best(this._parts.hostname);\n }\n\n this._parts.hostname = this._parts.hostname.toLowerCase();\n this.build(!build);\n }\n\n return this;\n };\n p.normalizePort = function(build) {\n // remove port of it's the protocol's default\n if (typeof this._parts.protocol === 'string' && this._parts.port === URI.defaultPorts[this._parts.protocol]) {\n this._parts.port = null;\n this.build(!build);\n }\n\n return this;\n };\n p.normalizePath = function(build) {\n var _path = this._parts.path;\n if (!_path) {\n return this;\n }\n\n if (this._parts.urn) {\n this._parts.path = URI.recodeUrnPath(this._parts.path);\n this.build(!build);\n return this;\n }\n\n if (this._parts.path === '/') {\n return this;\n }\n\n _path = URI.recodePath(_path);\n\n var _was_relative;\n var _leadingParents = '';\n var _parent, _pos;\n\n // handle relative paths\n if (_path.charAt(0) !== '/') {\n _was_relative = true;\n _path = '/' + _path;\n }\n\n // handle relative files (as opposed to directories)\n if (_path.slice(-3) === '/..' || _path.slice(-2) === '/.') {\n _path += '/';\n }\n\n // resolve simples\n _path = _path\n .replace(/(\\/(\\.\\/)+)|(\\/\\.$)/g, '/')\n .replace(/\\/{2,}/g, '/');\n\n // remember leading parents\n if (_was_relative) {\n _leadingParents = _path.substring(1).match(/^(\\.\\.\\/)+/) || '';\n if (_leadingParents) {\n _leadingParents = _leadingParents[0];\n }\n }\n\n // resolve parents\n while (true) {\n _parent = _path.search(/\\/\\.\\.(\\/|$)/);\n if (_parent === -1) {\n // no more ../ to resolve\n break;\n } else if (_parent === 0) {\n // top level cannot be relative, skip it\n _path = _path.substring(3);\n continue;\n }\n\n _pos = _path.substring(0, _parent).lastIndexOf('/');\n if (_pos === -1) {\n _pos = _parent;\n }\n _path = _path.substring(0, _pos) + _path.substring(_parent + 3);\n }\n\n // revert to relative\n if (_was_relative && this.is('relative')) {\n _path = _leadingParents + _path.substring(1);\n }\n\n this._parts.path = _path;\n this.build(!build);\n return this;\n };\n p.normalizePathname = p.normalizePath;\n p.normalizeQuery = function(build) {\n if (typeof this._parts.query === 'string') {\n if (!this._parts.query.length) {\n this._parts.query = null;\n } else {\n this.query(URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace));\n }\n\n this.build(!build);\n }\n\n return this;\n };\n p.normalizeFragment = function(build) {\n if (!this._parts.fragment) {\n this._parts.fragment = null;\n this.build(!build);\n }\n\n return this;\n };\n p.normalizeSearch = p.normalizeQuery;\n p.normalizeHash = p.normalizeFragment;\n\n p.iso8859 = function() {\n // expect unicode input, iso8859 output\n var e = URI.encode;\n var d = URI.decode;\n\n URI.encode = escape;\n URI.decode = decodeURIComponent;\n try {\n this.normalize();\n } finally {\n URI.encode = e;\n URI.decode = d;\n }\n return this;\n };\n\n p.unicode = function() {\n // expect iso8859 input, unicode output\n var e = URI.encode;\n var d = URI.decode;\n\n URI.encode = strictEncodeURIComponent;\n URI.decode = unescape;\n try {\n this.normalize();\n } finally {\n URI.encode = e;\n URI.decode = d;\n }\n return this;\n };\n\n p.readable = function() {\n var uri = this.clone();\n // removing username, password, because they shouldn't be displayed according to RFC 3986\n uri.username('').password('').normalize();\n var t = '';\n if (uri._parts.protocol) {\n t += uri._parts.protocol + '://';\n }\n\n if (uri._parts.hostname) {\n if (uri.is('punycode') && punycode) {\n t += punycode.toUnicode(uri._parts.hostname);\n if (uri._parts.port) {\n t += ':' + uri._parts.port;\n }\n } else {\n t += uri.host();\n }\n }\n\n if (uri._parts.hostname && uri._parts.path && uri._parts.path.charAt(0) !== '/') {\n t += '/';\n }\n\n t += uri.path(true);\n if (uri._parts.query) {\n var q = '';\n for (var i = 0, qp = uri._parts.query.split('&'), l = qp.length; i < l; i++) {\n var kv = (qp[i] || '').split('=');\n q += '&' + URI.decodeQuery(kv[0], this._parts.escapeQuerySpace)\n .replace(/&/g, '%26');\n\n if (kv[1] !== undefined) {\n q += '=' + URI.decodeQuery(kv[1], this._parts.escapeQuerySpace)\n .replace(/&/g, '%26');\n }\n }\n t += '?' + q.substring(1);\n }\n\n t += URI.decodeQuery(uri.hash(), true);\n return t;\n };\n\n // resolving relative and absolute URLs\n p.absoluteTo = function(base) {\n var resolved = this.clone();\n var properties = ['protocol', 'username', 'password', 'hostname', 'port'];\n var basedir, i, p;\n\n if (this._parts.urn) {\n throw new Error('URNs do not have any generally defined hierarchical components');\n }\n\n if (!(base instanceof URI)) {\n base = new URI(base);\n }\n\n if (!resolved._parts.protocol) {\n resolved._parts.protocol = base._parts.protocol;\n }\n\n if (this._parts.hostname) {\n return resolved;\n }\n\n for (i = 0; (p = properties[i]); i++) {\n resolved._parts[p] = base._parts[p];\n }\n\n if (!resolved._parts.path) {\n resolved._parts.path = base._parts.path;\n if (!resolved._parts.query) {\n resolved._parts.query = base._parts.query;\n }\n } else if (resolved._parts.path.substring(-2) === '..') {\n resolved._parts.path += '/';\n }\n\n if (resolved.path().charAt(0) !== '/') {\n basedir = base.directory();\n basedir = basedir ? basedir : base.path().indexOf('/') === 0 ? '/' : '';\n resolved._parts.path = (basedir ? (basedir + '/') : '') + resolved._parts.path;\n resolved.normalizePath();\n }\n\n resolved.build();\n return resolved;\n };\n p.relativeTo = function(base) {\n var relative = this.clone().normalize();\n var relativeParts, baseParts, common, relativePath, basePath;\n\n if (relative._parts.urn) {\n throw new Error('URNs do not have any generally defined hierarchical components');\n }\n\n base = new URI(base).normalize();\n relativeParts = relative._parts;\n baseParts = base._parts;\n relativePath = relative.path();\n basePath = base.path();\n\n if (relativePath.charAt(0) !== '/') {\n throw new Error('URI is already relative');\n }\n\n if (basePath.charAt(0) !== '/') {\n throw new Error('Cannot calculate a URI relative to another relative URI');\n }\n\n if (relativeParts.protocol === baseParts.protocol) {\n relativeParts.protocol = null;\n }\n\n if (relativeParts.username !== baseParts.username || relativeParts.password !== baseParts.password) {\n return relative.build();\n }\n\n if (relativeParts.protocol !== null || relativeParts.username !== null || relativeParts.password !== null) {\n return relative.build();\n }\n\n if (relativeParts.hostname === baseParts.hostname && relativeParts.port === baseParts.port) {\n relativeParts.hostname = null;\n relativeParts.port = null;\n } else {\n return relative.build();\n }\n\n if (relativePath === basePath) {\n relativeParts.path = '';\n return relative.build();\n }\n\n // determine common sub path\n common = URI.commonPath(relativePath, basePath);\n\n // If the paths have nothing in common, return a relative URL with the absolute path.\n if (!common) {\n return relative.build();\n }\n\n var parents = baseParts.path\n .substring(common.length)\n .replace(/[^\\/]*$/, '')\n .replace(/.*?\\//g, '../');\n\n relativeParts.path = (parents + relativeParts.path.substring(common.length)) || './';\n\n return relative.build();\n };\n\n // comparing URIs\n p.equals = function(uri) {\n var one = this.clone();\n var two = new URI(uri);\n var one_map = {};\n var two_map = {};\n var checked = {};\n var one_query, two_query, key;\n\n one.normalize();\n two.normalize();\n\n // exact match\n if (one.toString() === two.toString()) {\n return true;\n }\n\n // extract query string\n one_query = one.query();\n two_query = two.query();\n one.query('');\n two.query('');\n\n // definitely not equal if not even non-query parts match\n if (one.toString() !== two.toString()) {\n return false;\n }\n\n // query parameters have the same length, even if they're permuted\n if (one_query.length !== two_query.length) {\n return false;\n }\n\n one_map = URI.parseQuery(one_query, this._parts.escapeQuerySpace);\n two_map = URI.parseQuery(two_query, this._parts.escapeQuerySpace);\n\n for (key in one_map) {\n if (hasOwn.call(one_map, key)) {\n if (!isArray(one_map[key])) {\n if (one_map[key] !== two_map[key]) {\n return false;\n }\n } else if (!arraysEqual(one_map[key], two_map[key])) {\n return false;\n }\n\n checked[key] = true;\n }\n }\n\n for (key in two_map) {\n if (hasOwn.call(two_map, key)) {\n if (!checked[key]) {\n // two contains a parameter not present in one\n return false;\n }\n }\n }\n\n return true;\n };\n\n // state\n p.duplicateQueryParameters = function(v) {\n this._parts.duplicateQueryParameters = !!v;\n return this;\n };\n\n p.escapeQuerySpace = function(v) {\n this._parts.escapeQuerySpace = !!v;\n return this;\n };\n\n return URI;\n}));\n","var RSVP = require('rsvp');\nvar URI = require('urijs');\nvar core = require('./core');\nvar Spine = require('./spine');\nvar Locations = require('./locations');\nvar Parser = require('./parser');\nvar Navigation = require('./navigation');\nvar Rendition = require('./rendition');\nvar Unarchive = require('./unarchive');\nvar request = require('./request');\nvar EpubCFI = require('./epubcfi');\n\nfunction Book(_url, options){\n\n this.settings = core.extend(this.settings || {}, {\n\t\trequestMethod: this.requestMethod\n\t});\n\n core.extend(this.settings, options);\n\n\n // Promises\n this.opening = new RSVP.defer();\n this.opened = this.opening.promise;\n this.isOpen = false;\n\n this.url = undefined;\n\n this.loading = {\n manifest: new RSVP.defer(),\n spine: new RSVP.defer(),\n metadata: new RSVP.defer(),\n cover: new RSVP.defer(),\n navigation: new RSVP.defer(),\n pageList: new RSVP.defer()\n };\n\n this.loaded = {\n manifest: this.loading.manifest.promise,\n spine: this.loading.spine.promise,\n metadata: this.loading.metadata.promise,\n cover: this.loading.cover.promise,\n navigation: this.loading.navigation.promise,\n pageList: this.loading.pageList.promise\n };\n\n this.ready = RSVP.hash(this.loaded);\n\n // Queue for methods used before opening\n this.isRendered = false;\n // this._q = core.queue(this);\n\n this.request = this.settings.requestMethod.bind(this);\n\n this.spine = new Spine(this.request);\n this.locations = new Locations(this.spine, this.request);\n\n if(_url) {\n this.open(_url).catch(function (error) {\n var err = new Error(\"Cannot load book at \"+ _url );\n console.error(err);\n\n this.trigger(\"loadFailed\", error);\n }.bind(this));\n }\n};\n\nBook.prototype.open = function(_url, options){\n var uri;\n var parse = new Parser();\n var epubPackage;\n var epubContainer;\n var book = this;\n var containerPath = \"META-INF/container.xml\";\n var location;\n var absoluteUri;\n var isArrayBuffer = false;\n var isBase64 = options && options.base64;\n\n if(!_url) {\n this.opening.resolve(this);\n return this.opened;\n }\n\n // Reuse parsed url or create a new uri object\n // if(typeof(_url) === \"object\") {\n // uri = _url;\n // } else {\n // uri = core.uri(_url);\n // }\n if (_url instanceof ArrayBuffer || isBase64) {\n\t\tisArrayBuffer = true;\n this.url = '/';\n\t} else {\n uri = URI(_url);\n\t}\n\n if (window && window.location && uri) {\n absoluteUri = uri.absoluteTo(window.location.href);\n this.url = absoluteUri.toString();\n } if (window && window.location) {\n this.url = window.location.href;\n } else {\n this.url = _url;\n }\n\n // Find path to the Container\n if(uri && uri.suffix() === \"opf\") {\n // Direct link to package, no container\n this.packageUrl = _url;\n this.containerUrl = '';\n\n if(uri.origin()) {\n this.baseUrl = uri.origin() + \"/\" + uri.directory() + \"/\";\n } else if(absoluteUri){\n this.baseUrl = absoluteUri.origin();\n this.baseUrl += absoluteUri.directory() + \"/\";\n } else {\n this.baseUrl = uri.directory() + \"/\";\n }\n\n epubPackage = this.request(this.packageUrl)\n .catch(function(error) {\n book.opening.reject(error);\n });\n\n } else if(isArrayBuffer || isBase64 || this.isArchivedUrl(uri)) {\n // Book is archived\n this.url = '/';\n this.containerUrl = URI(containerPath).absoluteTo(this.url).toString();\n\n epubContainer = this.unarchive(_url, isBase64).\n then(function() {\n return this.request(this.containerUrl);\n }.bind(this))\n .catch(function(error) {\n book.opening.reject(error);\n });\n }\n // Find the path to the Package from the container\n else if (!uri.suffix()) {\n\n this.containerUrl = this.url + containerPath;\n\n epubContainer = this.request(this.containerUrl)\n .catch(function(error) {\n // handle errors in loading container\n book.opening.reject(error);\n });\n }\n\n if (epubContainer) {\n epubPackage = epubContainer.\n then(function(containerXml){\n return parse.container(containerXml); // Container has path to content\n }).\n then(function(paths){\n var packageUri = URI(paths.packagePath);\n var absPackageUri = packageUri.absoluteTo(book.url);\n var absWindowUri;\n\n book.packageUrl = absPackageUri.toString();\n book.encoding = paths.encoding;\n\n // Set Url relative to the content\n if(absPackageUri.origin()) {\n book.baseUrl = absPackageUri.origin() + absPackageUri.directory() + \"/\";\n } else {\n if(packageUri.directory()) {\n book.baseUrl = \"/\" + packageUri.directory() + \"/\";\n } else {\n book.baseUrl = \"/\"\n }\n }\n\n return book.request(book.packageUrl);\n }).catch(function(error) {\n // handle errors in either of the two requests\n book.opening.reject(error);\n });\n }\n\n epubPackage.then(function(packageXml) {\n\n if (!packageXml) {\n return;\n }\n\n // Get package information from epub opf\n book.unpack(packageXml);\n\n // Resolve promises\n book.loading.manifest.resolve(book.package.manifest);\n book.loading.metadata.resolve(book.package.metadata);\n book.loading.spine.resolve(book.spine);\n book.loading.cover.resolve(book.cover);\n\n book.isOpen = true;\n\n // Clear queue of any waiting book request\n\n // Resolve book opened promise\n book.opening.resolve(book);\n\n }).catch(function(error) {\n // handle errors in parsing the book\n // console.error(error.message, error.stack);\n book.opening.reject(error);\n });\n\n return this.opened;\n};\n\nBook.prototype.unpack = function(packageXml){\n var book = this,\n parse = new Parser();\n\n book.package = parse.packageContents(packageXml); // Extract info from contents\n if(!book.package) {\n return;\n }\n\n book.package.baseUrl = book.baseUrl; // Provides a url base for resolving paths\n\n this.spine.load(book.package);\n\n book.navigation = new Navigation(book.package, this.request);\n book.navigation.load().then(function(toc){\n book.toc = toc;\n book.loading.navigation.resolve(book.toc);\n });\n\n // //-- Set Global Layout setting based on metadata\n // MOVE TO RENDER\n // book.globalLayoutProperties = book.parseLayoutProperties(book.package.metadata);\n\n book.cover = URI(book.package.coverPath).absoluteTo(book.baseUrl).toString();\n};\n\n// Alias for book.spine.get\nBook.prototype.section = function(target) {\n return this.spine.get(target);\n};\n\n// Sugar to render a book\nBook.prototype.renderTo = function(element, options) {\n // var renderMethod = (options && options.method) ?\n // options.method :\n // \"single\";\n\n this.rendition = new Rendition(this, options);\n this.rendition.attachTo(element);\n\n return this.rendition;\n};\n\nBook.prototype.requestMethod = function(_url) {\n // Switch request methods\n if(this.unarchived) {\n return this.unarchived.request(_url);\n } else {\n return request(_url, null, this.requestCredentials, this.requestHeaders);\n }\n\n};\n\nBook.prototype.setRequestCredentials = function(_credentials) {\n this.requestCredentials = _credentials;\n};\n\nBook.prototype.setRequestHeaders = function(_headers) {\n this.requestHeaders = _headers;\n};\n\nBook.prototype.unarchive = function(bookUrl, isBase64){\n\tthis.unarchived = new Unarchive();\n\treturn this.unarchived.open(bookUrl, isBase64);\n};\n\n//-- Checks if url has a .epub or .zip extension, or is ArrayBuffer (of zip/epub)\nBook.prototype.isArchivedUrl = function(bookUrl){\n var uri;\n var extension;\n\n if (bookUrl instanceof ArrayBuffer) {\n\t\treturn true;\n\t}\n\n // Reuse parsed url or create a new uri object\n // if(typeof(bookUrl) === \"object\") {\n // uri = bookUrl;\n // } else {\n // uri = core.uri(bookUrl);\n // }\n uri = URI(bookUrl);\n extension = uri.suffix();\n\n\tif(extension && (extension == \"epub\" || extension == \"zip\")){\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\n//-- Returns the cover\nBook.prototype.coverUrl = function(){\n\tvar retrieved = this.loaded.cover.\n\t\tthen(function(url) {\n\t\t\tif(this.unarchived) {\n\t\t\t\treturn this.unarchived.createUrl(this.cover);\n\t\t\t}else{\n\t\t\t\treturn this.cover;\n\t\t\t}\n\t\t}.bind(this));\n\n\n\n\treturn retrieved;\n};\n\nBook.prototype.range = function(cfiRange) {\n var cfi = new EpubCFI(cfiRange);\n var item = this.spine.get(cfi.spinePos);\n\n return item.load().then(function (contents) {\n var range = cfi.toRange(item.document);\n return range;\n })\n};\n\nmodule.exports = Book;\n\n//-- Enable binding events to book\nRSVP.EventTarget.mixin(Book.prototype);\n\n//-- Handle RSVP Errors\nRSVP.on('error', function(event) {\n console.error(event);\n});\n\nRSVP.configure('instrument', false); //-- true | will logging out all RSVP rejections\n// RSVP.on('created', listener);\n// RSVP.on('chained', listener);\n// RSVP.on('fulfilled', listener);\nRSVP.on('rejected', function(event){\n console.error(event.detail.message, event.detail.stack);\n});\n","var RSVP = require('rsvp');\nvar core = require('./core');\nvar EpubCFI = require('./epubcfi');\nvar Mapping = require('./mapping');\n\n\nfunction Contents(doc, content, cfiBase) {\n // Blank Cfi for Parsing\n this.epubcfi = new EpubCFI();\n\n this.document = doc;\n this.documentElement = this.document.documentElement;\n this.content = content || this.document.body;\n this.window = this.document.defaultView;\n // Dom events to listen for\n this.listenedEvents = [\"keydown\", \"keyup\", \"keypressed\", \"mouseup\", \"mousedown\", \"click\", \"touchend\", \"touchstart\"];\n\n this._size = {\n width: 0,\n height: 0\n }\n\n this.cfiBase = cfiBase || \"\";\n\n this.listeners();\n};\n\nContents.prototype.width = function(w) {\n // var frame = this.documentElement;\n var frame = this.content;\n\n if (w && core.isNumber(w)) {\n w = w + \"px\";\n }\n\n if (w) {\n frame.style.width = w;\n // this.content.style.width = w;\n }\n\n return this.window.getComputedStyle(frame)['width'];\n\n\n};\n\nContents.prototype.height = function(h) {\n // var frame = this.documentElement;\n var frame = this.content;\n\n if (h && core.isNumber(h)) {\n h = h + \"px\";\n }\n\n if (h) {\n frame.style.height = h;\n // this.content.style.height = h;\n }\n\n return this.window.getComputedStyle(frame)['height'];\n\n};\n\nContents.prototype.contentWidth = function(w) {\n\n var content = this.content || this.document.body;\n\n if (w && core.isNumber(w)) {\n w = w + \"px\";\n }\n\n if (w) {\n content.style.width = w;\n }\n\n return this.window.getComputedStyle(content)['width'];\n\n\n};\n\nContents.prototype.contentHeight = function(h) {\n\n var content = this.content || this.document.body;\n\n if (h && core.isNumber(h)) {\n h = h + \"px\";\n }\n\n if (h) {\n content.style.height = h;\n }\n\n return this.window.getComputedStyle(content)['height'];\n\n};\n\nContents.prototype.textWidth = function() {\n var width;\n var range = this.document.createRange();\n var content = this.content || this.document.body;\n\n // Select the contents of frame\n range.selectNodeContents(content);\n\n // get the width of the text content\n width = range.getBoundingClientRect().width;\n\n return width;\n\n};\n\nContents.prototype.textHeight = function() {\n var height;\n var range = this.document.createRange();\n var content = this.content || this.document.body;\n\n range.selectNodeContents(content);\n\n height = range.getBoundingClientRect().height;\n\n return height;\n};\n\nContents.prototype.scrollWidth = function() {\n var width = this.documentElement.scrollWidth;\n\n return width;\n};\n\nContents.prototype.scrollHeight = function() {\n var height = this.documentElement.scrollHeight;\n\n return height;\n};\n\nContents.prototype.overflow = function(overflow) {\n\n if (overflow) {\n this.documentElement.style.overflow = overflow;\n }\n\n return this.window.getComputedStyle(this.documentElement)['overflow'];\n};\n\nContents.prototype.overflowX = function(overflow) {\n\n if (overflow) {\n this.documentElement.style.overflowX = overflow;\n }\n\n return this.window.getComputedStyle(this.documentElement)['overflowX'];\n};\n\nContents.prototype.overflowY = function(overflow) {\n\n if (overflow) {\n this.documentElement.style.overflowY = overflow;\n }\n\n return this.window.getComputedStyle(this.documentElement)['overflowY'];\n};\n\nContents.prototype.css = function(property, value) {\n var content = this.content || this.document.body;\n\n if (value) {\n content.style[property] = value;\n }\n\n return this.window.getComputedStyle(content)[property];\n};\n\nContents.prototype.viewport = function(options) {\n var width, height, scale, scalable;\n var $viewport = this.document.querySelector(\"meta[name='viewport']\");\n var newContent = '';\n\n /**\n * check for the viewport size\n * \n */\n if($viewport && $viewport.hasAttribute(\"content\")) {\n content = $viewport.getAttribute(\"content\");\n contents = content.split(/\\s*,\\s*/);\n if(contents[0]){\n width = contents[0].replace(\"width=\", '').trim();\n }\n if(contents[1]){\n height = contents[1].replace(\"height=\", '').trim();\n }\n if(contents[2]){\n scale = contents[2].replace(\"initial-scale=\", '').trim();\n }\n if(contents[3]){\n scalable = contents[3].replace(\"user-scalable=\", '').trim();\n }\n }\n\n if (options) {\n\n newContent += \"width=\" + (options.width || width);\n newContent += \", height=\" + (options.height || height);\n if (options.scale || scale) {\n newContent += \", initial-scale=\" + (options.scale || scale);\n }\n if (options.scalable || scalable) {\n newContent += \", user-scalable=\" + (options.scalable || scalable);\n }\n\n if (!$viewport) {\n $viewport = this.document.createElement(\"meta\");\n $viewport.setAttribute(\"name\", \"viewport\");\n this.document.querySelector('head').appendChild($viewport);\n }\n\n $viewport.setAttribute(\"content\", newContent);\n }\n\n\n return {\n width: parseInt(width),\n height: parseInt(height)\n };\n};\n\n\n// Contents.prototype.layout = function(layoutFunc) {\n//\n// this.iframe.style.display = \"inline-block\";\n//\n// // Reset Body Styles\n// this.content.style.margin = \"0\";\n// //this.document.body.style.display = \"inline-block\";\n// //this.document.documentElement.style.width = \"auto\";\n//\n// if(layoutFunc){\n// layoutFunc(this);\n// }\n//\n// this.onLayout(this);\n//\n// };\n//\n// Contents.prototype.onLayout = function(view) {\n// // stub\n// };\n\nContents.prototype.expand = function() {\n this.trigger(\"expand\");\n};\n\nContents.prototype.listeners = function() {\n\n this.imageLoadListeners();\n\n this.mediaQueryListeners();\n\n // this.fontLoadListeners();\n\n this.addEventListeners();\n\n this.addSelectionListeners();\n\n this.resizeListeners();\n\n};\n\nContents.prototype.removeListeners = function() {\n\n this.removeEventListeners();\n\n this.removeSelectionListeners();\n};\n\nContents.prototype.resizeListeners = function() {\n var width, height;\n // Test size again\n clearTimeout(this.expanding);\n\n width = this.scrollWidth();\n height = this.scrollHeight();\n\n if (width != this._size.width || height != this._size.height) {\n\n this._size = {\n width: width,\n height: height\n }\n\n this.trigger(\"resize\", this._size);\n }\n\n this.expanding = setTimeout(this.resizeListeners.bind(this), 350);\n};\n\n//https://github.com/tylergaw/media-query-events/blob/master/js/mq-events.js\nContents.prototype.mediaQueryListeners = function() {\n var sheets = this.document.styleSheets;\n var mediaChangeHandler = function(m){\n if(m.matches && !this._expanding) {\n setTimeout(this.expand.bind(this), 1);\n // this.expand();\n }\n }.bind(this);\n\n for (var i = 0; i < sheets.length; i += 1) {\n var rules = sheets[i].cssRules;\n if(!rules) return; // Stylesheets changed\n for (var j = 0; j < rules.length; j += 1) {\n //if (rules[j].constructor === CSSMediaRule) {\n if(rules[j].media){\n var mql = this.window.matchMedia(rules[j].media.mediaText);\n mql.addListener(mediaChangeHandler);\n //mql.onchange = mediaChangeHandler;\n }\n }\n }\n};\n\nContents.prototype.observe = function(target) {\n var renderer = this;\n\n // create an observer instance\n var observer = new MutationObserver(function(mutations) {\n if(renderer._expanding) {\n renderer.expand();\n }\n // mutations.forEach(function(mutation) {\n // console.log(mutation);\n // });\n });\n\n // configuration of the observer:\n var config = { attributes: true, childList: true, characterData: true, subtree: true };\n\n // pass in the target node, as well as the observer options\n observer.observe(target, config);\n\n return observer;\n};\n\nContents.prototype.imageLoadListeners = function(target) {\n var images = this.document.querySelectorAll(\"img\");\n var img;\n for (var i = 0; i < images.length; i++) {\n img = images[i];\n\n if (typeof img.naturalWidth !== \"undefined\" &&\n img.naturalWidth === 0) {\n img.onload = this.expand.bind(this);\n }\n }\n};\n\nContents.prototype.fontLoadListeners = function(target) {\n if (!this.document || !this.document.fonts) {\n return;\n }\n\n this.document.fonts.ready.then(function () {\n this.expand();\n }.bind(this));\n\n};\n\nContents.prototype.root = function() {\n if(!this.document) return null;\n return this.document.documentElement;\n};\n\nContents.prototype.locationOf = function(target, ignoreClass) {\n var position;\n var targetPos = {\"left\": 0, \"top\": 0};\n\n if(!this.document) return;\n\n if(this.epubcfi.isCfiString(target)) {\n range = new EpubCFI(target).toRange(this.document, ignoreClass);\n\n if(range) {\n if (range.startContainer.nodeType === Node.ELEMENT_NODE) {\n position = range.startContainer.getBoundingClientRect();\n targetPos.left = position.left;\n targetPos.top = position.top;\n } else {\n position = range.getBoundingClientRect();\n targetPos.left = position.left;\n targetPos.top = position.top;\n }\n }\n\n } else if(typeof target === \"string\" &&\n target.indexOf(\"#\") > -1) {\n\n id = target.substring(target.indexOf(\"#\")+1);\n el = this.document.getElementById(id);\n\n if(el) {\n position = el.getBoundingClientRect();\n targetPos.left = position.left;\n targetPos.top = position.top;\n }\n }\n\n return targetPos;\n};\n\nContents.prototype.addStylesheet = function(src) {\n return new RSVP.Promise(function(resolve, reject){\n var $stylesheet;\n var ready = false;\n\n if(!this.document) {\n resolve(false);\n return;\n }\n\n $stylesheet = this.document.createElement('link');\n $stylesheet.type = 'text/css';\n $stylesheet.rel = \"stylesheet\";\n $stylesheet.href = src;\n $stylesheet.onload = $stylesheet.onreadystatechange = function() {\n if ( !ready && (!this.readyState || this.readyState == 'complete') ) {\n ready = true;\n // Let apply\n setTimeout(function(){\n resolve(true);\n }, 1);\n }\n };\n\n this.document.head.appendChild($stylesheet);\n\n }.bind(this));\n};\n\n// https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule\nContents.prototype.addStylesheetRules = function(rules) {\n var styleEl;\n var styleSheet;\n\n if(!this.document) return;\n\n styleEl = this.document.createElement('style');\n\n // Append style element to head\n this.document.head.appendChild(styleEl);\n\n // Grab style sheet\n styleSheet = styleEl.sheet;\n\n for (var i = 0, rl = rules.length; i < rl; i++) {\n var j = 1, rule = rules[i], selector = rules[i][0], propStr = '';\n // If the second argument of a rule is an array of arrays, correct our variables.\n if (Object.prototype.toString.call(rule[1][0]) === '[object Array]') {\n rule = rule[1];\n j = 0;\n }\n\n for (var pl = rule.length; j < pl; j++) {\n var prop = rule[j];\n propStr += prop[0] + ':' + prop[1] + (prop[2] ? ' !important' : '') + ';\\n';\n }\n\n // Insert CSS Rule\n styleSheet.insertRule(selector + '{' + propStr + '}', styleSheet.cssRules.length);\n }\n};\n\nContents.prototype.addScript = function(src) {\n\n return new RSVP.Promise(function(resolve, reject){\n var $script;\n var ready = false;\n\n if(!this.document) {\n resolve(false);\n return;\n }\n\n $script = this.document.createElement('script');\n $script.type = 'text/javascript';\n $script.async = true;\n $script.src = src;\n $script.onload = $script.onreadystatechange = function() {\n if ( !ready && (!this.readyState || this.readyState == 'complete') ) {\n ready = true;\n setTimeout(function(){\n resolve(true);\n }, 1);\n }\n };\n\n this.document.head.appendChild($script);\n\n }.bind(this));\n};\n\nContents.prototype.addEventListeners = function(){\n if(!this.document) {\n return;\n }\n this.listenedEvents.forEach(function(eventName){\n this.document.addEventListener(eventName, this.triggerEvent.bind(this), false);\n }, this);\n\n};\n\nContents.prototype.removeEventListeners = function(){\n if(!this.document) {\n return;\n }\n this.listenedEvents.forEach(function(eventName){\n this.document.removeEventListener(eventName, this.triggerEvent, false);\n }, this);\n\n};\n\n// Pass browser events\nContents.prototype.triggerEvent = function(e){\n this.trigger(e.type, e);\n};\n\nContents.prototype.addSelectionListeners = function(){\n if(!this.document) {\n return;\n }\n this.document.addEventListener(\"selectionchange\", this.onSelectionChange.bind(this), false);\n};\n\nContents.prototype.removeSelectionListeners = function(){\n if(!this.document) {\n return;\n }\n this.document.removeEventListener(\"selectionchange\", this.onSelectionChange, false);\n};\n\nContents.prototype.onSelectionChange = function(e){\n if (this.selectionEndTimeout) {\n clearTimeout(this.selectionEndTimeout);\n }\n this.selectionEndTimeout = setTimeout(function() {\n var selection = this.window.getSelection();\n this.triggerSelectedEvent(selection);\n }.bind(this), 500);\n};\n\nContents.prototype.triggerSelectedEvent = function(selection){\n\tvar range, cfirange;\n\n if (selection && selection.rangeCount > 0) {\n range = selection.getRangeAt(0);\n if(!range.collapsed) {\n // cfirange = this.section.cfiFromRange(range);\n cfirange = new EpubCFI(range, this.cfiBase).toString();\n this.trigger(\"selected\", cfirange);\n this.trigger(\"selectedRange\", range);\n }\n }\n};\n\nContents.prototype.range = function(_cfi, ignoreClass){\n var cfi = new EpubCFI(_cfi);\n return cfi.toRange(this.document, ignoreClass);\n};\n\nContents.prototype.map = function(layout){\n var map = new Mapping(layout);\n return map.section();\n};\n\nContents.prototype.size = function(width, height){\n\n if (width >= 0) {\n this.width(width);\n }\n\n if (height >= 0) {\n this.height(height);\n }\n\n this.css(\"margin\", \"0\");\n this.css(\"boxSizing\", \"border-box\");\n\n};\n\nContents.prototype.columns = function(width, height, columnWidth, gap){\n var COLUMN_AXIS = core.prefixed('columnAxis');\n var COLUMN_GAP = core.prefixed('columnGap');\n var COLUMN_WIDTH = core.prefixed('columnWidth');\n var COLUMN_FILL = core.prefixed('columnFill');\n var textWidth;\n\n this.width(width);\n this.height(height);\n\n // Deal with Mobile trying to scale to viewport\n this.viewport({ width: width, height: height, scale: 1.0 });\n\n // this.overflowY(\"hidden\");\n this.css(\"overflowY\", \"hidden\");\n this.css(\"margin\", \"0\");\n this.css(\"boxSizing\", \"border-box\");\n\n this.css(COLUMN_AXIS, \"horizontal\");\n this.css(COLUMN_FILL, \"auto\");\n\n this.css(COLUMN_GAP, gap+\"px\");\n this.css(COLUMN_WIDTH, columnWidth+\"px\");\n};\n\nContents.prototype.scale = function(scale, offsetX, offsetY){\n var scale = \"scale(\" + scale + \")\";\n var translate = '';\n // this.css(\"position\", \"absolute\"));\n this.css(\"transformOrigin\", \"top left\");\n\n if (offsetX >= 0 || offsetY >= 0) {\n translate = \" translate(\" + (offsetX || 0 )+ \"px, \" + (offsetY || 0 )+ \"px )\";\n }\n\n this.css(\"transform\", scale + translate);\n};\n\nContents.prototype.fit = function(width, height){\n var viewport = this.viewport();\n var widthScale = width / viewport.width;\n var heightScale = height / viewport.height;\n var scale = widthScale < heightScale ? widthScale : heightScale;\n\n var offsetY = (height - (viewport.height * scale)) / 2;\n\n this.width(width);\n this.height(height);\n this.overflow(\"hidden\");\n\n // Deal with Mobile trying to scale to viewport\n this.viewport({ scale: 1.0 });\n\n // Scale to the correct size\n this.scale(scale, 0, offsetY);\n\n this.css(\"backgroundColor\", \"transparent\");\n};\n\nContents.prototype.mapPage = function(cfiBase, start, end) {\n var mapping = new Mapping();\n\n return mapping.page(this, cfiBase, start, end);\n};\n\nContents.prototype.destroy = function() {\n // Stop observing\n if(this.observer) {\n this.observer.disconnect();\n }\n\n this.removeListeners();\n\n};\n\nRSVP.EventTarget.mixin(Contents.prototype);\n\nmodule.exports = Contents;\n","var RSVP = require('rsvp');\nvar base64 = require('base64-js');\n\nvar requestAnimationFrame = (typeof window != 'undefined') ? (window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame) : false;\n/*\n//-- Parse the different parts of a url, returning a object\nfunction uri(url){\n var uri = {\n protocol : '',\n host : '',\n path : '',\n origin : '',\n directory : '',\n base : '',\n filename : '',\n extension : '',\n fragment : '',\n href : url\n },\n doubleSlash = url.indexOf('://'),\n search = url.indexOf('?'),\n fragment = url.indexOf(\"#\"),\n withoutProtocol,\n dot,\n firstSlash;\n\n if(fragment != -1) {\n uri.fragment = url.slice(fragment + 1);\n url = url.slice(0, fragment);\n }\n\n if(search != -1) {\n uri.search = url.slice(search + 1);\n url = url.slice(0, search);\n href = url;\n }\n\n if(doubleSlash != -1) {\n uri.protocol = url.slice(0, doubleSlash);\n withoutProtocol = url.slice(doubleSlash+3);\n firstSlash = withoutProtocol.indexOf('/');\n\n if(firstSlash === -1) {\n uri.host = uri.path;\n uri.path = \"\";\n } else {\n uri.host = withoutProtocol.slice(0, firstSlash);\n uri.path = withoutProtocol.slice(firstSlash);\n }\n\n\n uri.origin = uri.protocol + \"://\" + uri.host;\n\n uri.directory = folder(uri.path);\n\n uri.base = uri.origin + uri.directory;\n // return origin;\n } else {\n uri.path = url;\n uri.directory = folder(url);\n uri.base = uri.directory;\n }\n\n //-- Filename\n uri.filename = url.replace(uri.base, '');\n dot = uri.filename.lastIndexOf('.');\n if(dot != -1) {\n uri.extension = uri.filename.slice(dot+1);\n }\n return uri;\n};\n\n//-- Parse out the folder, will return everything before the last slash\nfunction folder(url){\n\n var lastSlash = url.lastIndexOf('/');\n\n if(lastSlash == -1) var folder = '';\n\n folder = url.slice(0, lastSlash + 1);\n\n return folder;\n\n};\n*/\nfunction isElement(obj) {\n return !!(obj && obj.nodeType == 1);\n};\n\n// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript\nfunction uuid() {\n var d = new Date().getTime();\n var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {\n var r = (d + Math.random()*16)%16 | 0;\n d = Math.floor(d/16);\n return (c=='x' ? r : (r&0x7|0x8)).toString(16);\n });\n return uuid;\n};\n\n// From Lodash\nfunction values(object) {\n var index = -1,\n props = Object.keys(object),\n length = props.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = object[props[index]];\n }\n return result;\n};\n\nfunction resolveUrl(base, path) {\n var url = [],\n segments = [],\n baseUri = uri(base),\n pathUri = uri(path),\n baseDirectory = baseUri.directory,\n pathDirectory = pathUri.directory,\n directories = [],\n // folders = base.split(\"/\"),\n paths;\n\n // if(uri.host) {\n // return path;\n // }\n\n if(baseDirectory[0] === \"/\") {\n baseDirectory = baseDirectory.substring(1);\n }\n\n if(pathDirectory[pathDirectory.length-1] === \"/\") {\n baseDirectory = baseDirectory.substring(0, baseDirectory.length-1);\n }\n\n if(pathDirectory[0] === \"/\") {\n pathDirectory = pathDirectory.substring(1);\n }\n\n if(pathDirectory[pathDirectory.length-1] === \"/\") {\n pathDirectory = pathDirectory.substring(0, pathDirectory.length-1);\n }\n\n if(baseDirectory) {\n directories = baseDirectory.split(\"/\");\n }\n\n paths = pathDirectory.split(\"/\");\n\n paths.reverse().forEach(function(part, index){\n if(part === \"..\"){\n directories.pop();\n } else if(part === directories[directories.length-1]) {\n directories.pop();\n segments.unshift(part);\n } else {\n segments.unshift(part);\n }\n });\n\n url = [baseUri.origin];\n\n if(directories.length) {\n url = url.concat(directories);\n }\n\n if(segments) {\n url = url.concat(segments);\n }\n\n url = url.concat(pathUri.filename);\n\n return url.join(\"/\");\n};\n\nfunction documentHeight() {\n return Math.max(\n document.documentElement.clientHeight,\n document.body.scrollHeight,\n document.documentElement.scrollHeight,\n document.body.offsetHeight,\n document.documentElement.offsetHeight\n );\n};\n\nfunction isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n};\n\nfunction prefixed(unprefixed) {\n var vendors = [\"Webkit\", \"Moz\", \"O\", \"ms\" ],\n prefixes = ['-Webkit-', '-moz-', '-o-', '-ms-'],\n upper = unprefixed[0].toUpperCase() + unprefixed.slice(1),\n length = vendors.length;\n\n if (typeof(document) === 'undefined' || typeof(document.body.style[unprefixed]) != 'undefined') {\n return unprefixed;\n }\n\n for ( var i=0; i < length; i++ ) {\n if (typeof(document.body.style[vendors[i] + upper]) != 'undefined') {\n return vendors[i] + upper;\n }\n }\n\n return unprefixed;\n};\n\nfunction defaults(obj) {\n for (var i = 1, length = arguments.length; i < length; i++) {\n var source = arguments[i];\n for (var prop in source) {\n if (obj[prop] === void 0) obj[prop] = source[prop];\n }\n }\n return obj;\n};\n\nfunction extend(target) {\n var sources = [].slice.call(arguments, 1);\n sources.forEach(function (source) {\n if(!source) return;\n Object.getOwnPropertyNames(source).forEach(function(propName) {\n Object.defineProperty(target, propName, Object.getOwnPropertyDescriptor(source, propName));\n });\n });\n return target;\n};\n\n// Fast quicksort insert for sorted array -- based on:\n// http://stackoverflow.com/questions/1344500/efficient-way-to-insert-a-number-into-a-sorted-array-of-numbers\nfunction insert(item, array, compareFunction) {\n var location = locationOf(item, array, compareFunction);\n array.splice(location, 0, item);\n\n return location;\n};\n// Returns where something would fit in\nfunction locationOf(item, array, compareFunction, _start, _end) {\n var start = _start || 0;\n var end = _end || array.length;\n var pivot = parseInt(start + (end - start) / 2);\n var compared;\n if(!compareFunction){\n compareFunction = function(a, b) {\n if(a > b) return 1;\n if(a < b) return -1;\n if(a = b) return 0;\n };\n }\n if(end-start <= 0) {\n return pivot;\n }\n\n compared = compareFunction(array[pivot], item);\n if(end-start === 1) {\n return compared > 0 ? pivot : pivot + 1;\n }\n\n if(compared === 0) {\n return pivot;\n }\n if(compared === -1) {\n return locationOf(item, array, compareFunction, pivot, end);\n } else{\n return locationOf(item, array, compareFunction, start, pivot);\n }\n};\n// Returns -1 of mpt found\nfunction indexOfSorted(item, array, compareFunction, _start, _end) {\n var start = _start || 0;\n var end = _end || array.length;\n var pivot = parseInt(start + (end - start) / 2);\n var compared;\n if(!compareFunction){\n compareFunction = function(a, b) {\n if(a > b) return 1;\n if(a < b) return -1;\n if(a = b) return 0;\n };\n }\n if(end-start <= 0) {\n return -1; // Not found\n }\n\n compared = compareFunction(array[pivot], item);\n if(end-start === 1) {\n return compared === 0 ? pivot : -1;\n }\n if(compared === 0) {\n return pivot; // Found\n }\n if(compared === -1) {\n return indexOfSorted(item, array, compareFunction, pivot, end);\n } else{\n return indexOfSorted(item, array, compareFunction, start, pivot);\n }\n};\n\nfunction bounds(el) {\n\n var style = window.getComputedStyle(el);\n var widthProps = [\"width\", \"paddingRight\", \"paddingLeft\", \"marginRight\", \"marginLeft\", \"borderRightWidth\", \"borderLeftWidth\"];\n var heightProps = [\"height\", \"paddingTop\", \"paddingBottom\", \"marginTop\", \"marginBottom\", \"borderTopWidth\", \"borderBottomWidth\"];\n\n var width = 0;\n var height = 0;\n\n widthProps.forEach(function(prop){\n width += parseFloat(style[prop]) || 0;\n });\n\n heightProps.forEach(function(prop){\n height += parseFloat(style[prop]) || 0;\n });\n\n return {\n height: height,\n width: width\n };\n\n};\n\nfunction borders(el) {\n\n var style = window.getComputedStyle(el);\n var widthProps = [\"paddingRight\", \"paddingLeft\", \"marginRight\", \"marginLeft\", \"borderRightWidth\", \"borderLeftWidth\"];\n var heightProps = [\"paddingTop\", \"paddingBottom\", \"marginTop\", \"marginBottom\", \"borderTopWidth\", \"borderBottomWidth\"];\n\n var width = 0;\n var height = 0;\n\n widthProps.forEach(function(prop){\n width += parseFloat(style[prop]) || 0;\n });\n\n heightProps.forEach(function(prop){\n height += parseFloat(style[prop]) || 0;\n });\n\n return {\n height: height,\n width: width\n };\n\n};\n\nfunction windowBounds() {\n\n var width = window.innerWidth;\n var height = window.innerHeight;\n\n return {\n top: 0,\n left: 0,\n right: width,\n bottom: height,\n width: width,\n height: height\n };\n\n};\n\n//https://stackoverflow.com/questions/13482352/xquery-looking-for-text-with-single-quote/13483496#13483496\nfunction cleanStringForXpath(str) {\n var parts = str.match(/[^'\"]+|['\"]/g);\n parts = parts.map(function(part){\n if (part === \"'\") {\n return '\\\"\\'\\\"'; // output \"'\"\n }\n\n if (part === '\"') {\n return \"\\'\\\"\\'\"; // output '\"'\n }\n return \"\\'\" + part + \"\\'\";\n });\n return \"concat(\\'\\',\" + parts.join(\",\") + \")\";\n};\n\nfunction indexOfTextNode(textNode){\n var parent = textNode.parentNode;\n var children = parent.childNodes;\n var sib;\n var index = -1;\n for (var i = 0; i < children.length; i++) {\n sib = children[i];\n if(sib.nodeType === Node.TEXT_NODE){\n index++;\n }\n if(sib == textNode) break;\n }\n\n return index;\n};\n\nfunction isXml(ext) {\n return ['xml', 'opf', 'ncx'].indexOf(ext) > -1;\n}\n\nfunction createBlob(content, mime){\n\tvar blob = new Blob([content], {type : mime });\n\n return blob;\n};\n\nfunction createBlobUrl(content, mime){\n var _URL = window.URL || window.webkitURL || window.mozURL;\n\tvar tempUrl;\n\tvar blob = this.createBlob(content, mime);\n\n tempUrl = _URL.createObjectURL(blob);\n\n return tempUrl;\n};\n\nfunction createBase64Url(content, mime){\n var string;\n var data;\n var datauri;\n\n if (typeof(content) !== \"string\") {\n // Only handles strings\n return;\n }\n\n data = btoa(content);\n\n datauri = \"data:\" + mime + \";base64,\" + data;\n\n return datauri;\n};\n\nfunction type(obj){\n return Object.prototype.toString.call(obj).slice(8, -1);\n}\n\nfunction parse(markup, mime) {\n var doc;\n // console.log(\"parse\", markup);\n\n if (typeof DOMParser === \"undefined\") {\n DOMParser = require('xmldom').DOMParser;\n }\n\n\n doc = new DOMParser().parseFromString(markup, mime);\n\n return doc;\n}\n\nfunction qs(el, sel) {\n var elements;\n\n if (typeof el.querySelector != \"undefined\") {\n return el.querySelector(sel);\n } else {\n elements = el.getElementsByTagName(sel);\n if (elements.length) {\n return elements[0];\n }\n }\n}\n\nfunction qsa(el, sel) {\n\n if (typeof el.querySelector != \"undefined\") {\n return el.querySelectorAll(sel);\n } else {\n return el.getElementsByTagName(sel);\n }\n}\n\nfunction qsp(el, sel, props) {\n var q, filtered;\n if (typeof el.querySelector != \"undefined\") {\n sel += '[';\n for (var prop in props) {\n sel += prop + \"='\" + props[prop] + \"'\";\n }\n sel += ']';\n return el.querySelector(sel);\n } else {\n q = el.getElementsByTagName(sel);\n filtered = Array.prototype.slice.call(q, 0).filter(function(el) {\n for (var prop in props) {\n if(el.getAttribute(prop) === props[prop]){\n return true;\n }\n }\n return false;\n });\n\n if (filtered) {\n return filtered[0];\n }\n }\n}\n\nfunction blob2base64(blob, cb) {\n var reader = new FileReader();\n reader.readAsDataURL(blob);\n reader.onloadend = function() {\n cb(reader.result);\n }\n}\n\nmodule.exports = {\n // 'uri': uri,\n // 'folder': folder,\n 'isElement': isElement,\n 'uuid': uuid,\n 'values': values,\n 'resolveUrl': resolveUrl,\n 'indexOfSorted': indexOfSorted,\n 'documentHeight': documentHeight,\n 'isNumber': isNumber,\n 'prefixed': prefixed,\n 'defaults': defaults,\n 'extend': extend,\n 'insert': insert,\n 'locationOf': locationOf,\n 'indexOfSorted': indexOfSorted,\n 'requestAnimationFrame': requestAnimationFrame,\n 'bounds': bounds,\n 'borders': borders,\n 'windowBounds': windowBounds,\n 'cleanStringForXpath': cleanStringForXpath,\n 'indexOfTextNode': indexOfTextNode,\n 'isXml': isXml,\n 'createBlob': createBlob,\n 'createBlobUrl': createBlobUrl,\n 'type': type,\n 'parse' : parse,\n 'qs' : qs,\n 'qsa' : qsa,\n 'qsp' : qsp,\n 'blob2base64' : blob2base64,\n 'createBase64Url': createBase64Url\n};\n","var URI = require('urijs');\nvar core = require('./core');\n\n/**\n EPUB CFI spec: http://www.idpf.org/epub/linking/cfi/epub-cfi.html\n\n Implements:\n - Character Offset: epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)\n - Simple Ranges : epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)\n\n Does Not Implement:\n - Temporal Offset (~)\n - Spatial Offset (@)\n - Temporal-Spatial Offset (~ + @)\n - Text Location Assertion ([)\n*/\n\nfunction EpubCFI(cfiFrom, base, ignoreClass){\n var type;\n\n this.str = '';\n\n this.base = {};\n this.spinePos = 0; // For compatibility\n\n this.range = false; // true || false;\n\n this.path = {};\n this.start = null;\n this.end = null;\n\n // Allow instantiation without the 'new' keyword\n if (!(this instanceof EpubCFI)) {\n return new EpubCFI(cfiFrom, base, ignoreClass);\n }\n\n if(typeof base === 'string') {\n this.base = this.parseComponent(base);\n } else if(typeof base === 'object' && base.steps) {\n this.base = base;\n }\n\n type = this.checkType(cfiFrom);\n\n\n if(type === 'string') {\n this.str = cfiFrom;\n return core.extend(this, this.parse(cfiFrom));\n } else if (type === 'range') {\n return core.extend(this, this.fromRange(cfiFrom, this.base, ignoreClass));\n } else if (type === 'node') {\n return core.extend(this, this.fromNode(cfiFrom, this.base, ignoreClass));\n } else if (type === 'EpubCFI' && cfiFrom.path) {\n return cfiFrom;\n } else if (!cfiFrom) {\n return this;\n } else {\n throw new TypeError('not a valid argument for EpubCFI');\n }\n\n};\n\nEpubCFI.prototype.checkType = function(cfi) {\n\n if (this.isCfiString(cfi)) {\n return 'string';\n // Is a range object\n } else if (typeof cfi === 'object' && core.type(cfi) === \"Range\"){\n return 'range';\n } else if (typeof cfi === 'object' && typeof(cfi.nodeType) != \"undefined\" ){ // || typeof cfi === 'function'\n return 'node';\n } else if (typeof cfi === 'object' && cfi instanceof EpubCFI){\n return 'EpubCFI';\n } else {\n return false;\n }\n};\n\nEpubCFI.prototype.parse = function(cfiStr) {\n var cfi = {\n spinePos: -1,\n range: false,\n base: {},\n path: {},\n start: null,\n end: null\n };\n var baseComponent, pathComponent, range;\n\n if(typeof cfiStr !== \"string\") {\n return {spinePos: -1};\n }\n\n if(cfiStr.indexOf(\"epubcfi(\") === 0 && cfiStr[cfiStr.length-1] === \")\") {\n // Remove intial epubcfi( and ending )\n cfiStr = cfiStr.slice(8, cfiStr.length-1);\n }\n\n baseComponent = this.getChapterComponent(cfiStr);\n\n // Make sure this is a valid cfi or return\n if(!baseComponent) {\n return {spinePos: -1};\n }\n\n cfi.base = this.parseComponent(baseComponent);\n\n pathComponent = this.getPathComponent(cfiStr);\n cfi.path = this.parseComponent(pathComponent);\n\n range = this.getRange(cfiStr);\n\n if(range) {\n cfi.range = true;\n cfi.start = this.parseComponent(range[0]);\n cfi.end = this.parseComponent(range[1]);\n }\n\n // Get spine node position\n // cfi.spineSegment = cfi.base.steps[1];\n\n // Chapter segment is always the second step\n cfi.spinePos = cfi.base.steps[1].index;\n\n return cfi;\n};\n\nEpubCFI.prototype.parseComponent = function(componentStr){\n var component = {\n steps: [],\n terminal: {\n offset: null,\n assertion: null\n }\n };\n var parts = componentStr.split(':');\n var steps = parts[0].split('/');\n var terminal;\n\n if(parts.length > 1) {\n terminal = parts[1];\n component.terminal = this.parseTerminal(terminal);\n }\n\n if (steps[0] === '') {\n steps.shift(); // Ignore the first slash\n }\n\n component.steps = steps.map(function(step){\n return this.parseStep(step);\n }.bind(this));\n\n return component;\n};\n\nEpubCFI.prototype.parseStep = function(stepStr){\n var type, num, index, has_brackets, id;\n\n has_brackets = stepStr.match(/\\[(.*)\\]/);\n if(has_brackets && has_brackets[1]){\n id = has_brackets[1];\n }\n\n //-- Check if step is a text node or element\n num = parseInt(stepStr);\n\n if(isNaN(num)) {\n return;\n }\n\n if(num % 2 === 0) { // Even = is an element\n type = \"element\";\n index = num / 2 - 1;\n } else {\n type = \"text\";\n index = (num - 1 ) / 2;\n }\n\n return {\n \"type\" : type,\n 'index' : index,\n 'id' : id || null\n };\n};\n\nEpubCFI.prototype.parseTerminal = function(termialStr){\n var characterOffset, textLocationAssertion;\n var assertion = termialStr.match(/\\[(.*)\\]/);\n\n if(assertion && assertion[1]){\n characterOffset = parseInt(termialStr.split('[')[0]) || null;\n textLocationAssertion = assertion[1];\n } else {\n characterOffset = parseInt(termialStr) || null;\n }\n\n return {\n 'offset': characterOffset,\n 'assertion': textLocationAssertion\n };\n\n};\n\nEpubCFI.prototype.getChapterComponent = function(cfiStr) {\n\n var indirection = cfiStr.split(\"!\");\n\n return indirection[0];\n};\n\nEpubCFI.prototype.getPathComponent = function(cfiStr) {\n\n var indirection = cfiStr.split(\"!\");\n\n if(indirection[1]) {\n ranges = indirection[1].split(',');\n return ranges[0];\n }\n\n};\n\nEpubCFI.prototype.getRange = function(cfiStr) {\n\n var ranges = cfiStr.split(\",\");\n\n if(ranges.length === 3){\n return [\n ranges[1],\n ranges[2]\n ];\n }\n\n return false;\n};\n\nEpubCFI.prototype.getCharecterOffsetComponent = function(cfiStr) {\n var splitStr = cfiStr.split(\":\");\n return splitStr[1] || '';\n};\n\nEpubCFI.prototype.joinSteps = function(steps) {\n if(!steps) {\n return \"\";\n }\n \n return steps.map(function(part){\n var segment = '';\n\n if(part.type === 'element') {\n segment += (part.index + 1) * 2;\n }\n\n if(part.type === 'text') {\n segment += 1 + (2 * part.index); // TODO: double check that this is odd\n }\n\n if(part.id) {\n segment += \"[\" + part.id + \"]\";\n }\n\n return segment;\n\n }).join('/');\n\n};\n\nEpubCFI.prototype.segmentString = function(segment) {\n var segmentString = '/';\n\n segmentString += this.joinSteps(segment.steps);\n\n if(segment.terminal && segment.terminal.offset != null){\n segmentString += ':' + segment.terminal.offset;\n }\n\n if(segment.terminal && segment.terminal.assertion != null){\n segmentString += '[' + segment.terminal.assertion + ']';\n }\n\n return segmentString;\n};\n\nEpubCFI.prototype.toString = function() {\n var cfiString = 'epubcfi(';\n\n cfiString += this.segmentString(this.base);\n\n cfiString += '!';\n cfiString += this.segmentString(this.path);\n\n // Add Range, if present\n if(this.start) {\n cfiString += ',';\n cfiString += this.segmentString(this.start);\n }\n\n if(this.end) {\n cfiString += ',';\n cfiString += this.segmentString(this.end);\n }\n\n cfiString += \")\";\n\n return cfiString;\n};\n\nEpubCFI.prototype.compare = function(cfiOne, cfiTwo) {\n if(typeof cfiOne === 'string') {\n cfiOne = new EpubCFI(cfiOne);\n }\n if(typeof cfiTwo === 'string') {\n cfiTwo = new EpubCFI(cfiTwo);\n }\n // Compare Spine Positions\n if(cfiOne.spinePos > cfiTwo.spinePos) {\n return 1;\n }\n if(cfiOne.spinePos < cfiTwo.spinePos) {\n return -1;\n }\n\n\n // Compare Each Step in the First item\n for (var i = 0; i < cfiOne.path.steps.length; i++) {\n if(!cfiTwo.path.steps[i]) {\n return 1;\n }\n if(cfiOne.path.steps[i].index > cfiTwo.path.steps[i].index) {\n return 1;\n }\n if(cfiOne.path.steps[i].index < cfiTwo.path.steps[i].index) {\n return -1;\n }\n // Otherwise continue checking\n }\n\n // All steps in First equal to Second and First is Less Specific\n if(cfiOne.path.steps.length < cfiTwo.path.steps.length) {\n return 1;\n }\n\n // Compare the charecter offset of the text node\n if(cfiOne.path.terminal.offset > cfiTwo.path.terminal.offset) {\n return 1;\n }\n if(cfiOne.path.terminal.offset < cfiTwo.path.terminal.offset) {\n return -1;\n }\n\n // TODO: compare ranges\n\n // CFI's are equal\n return 0;\n};\n\nEpubCFI.prototype.step = function(node) {\n var nodeType = (node.nodeType === Node.TEXT_NODE) ? 'text' : 'element';\n\n return {\n 'id' : node.id,\n 'tagName' : node.tagName,\n 'type' : nodeType,\n 'index' : this.position(node)\n };\n};\n\nEpubCFI.prototype.filteredStep = function(node, ignoreClass) {\n var filteredNode = this.filter(node, ignoreClass);\n var nodeType;\n\n // Node filtered, so ignore\n if (!filteredNode) {\n return;\n }\n\n // Otherwise add the filter node in\n nodeType = (filteredNode.nodeType === Node.TEXT_NODE) ? 'text' : 'element';\n\n return {\n 'id' : filteredNode.id,\n 'tagName' : filteredNode.tagName,\n 'type' : nodeType,\n 'index' : this.filteredPosition(filteredNode, ignoreClass)\n };\n};\n\nEpubCFI.prototype.pathTo = function(node, offset, ignoreClass) {\n var segment = {\n steps: [],\n terminal: {\n offset: null,\n assertion: null\n }\n };\n var currentNode = node;\n var step;\n\n while(currentNode && currentNode.parentNode &&\n currentNode.parentNode.nodeType != Node.DOCUMENT_NODE) {\n\n if (ignoreClass) {\n step = this.filteredStep(currentNode, ignoreClass);\n } else {\n step = this.step(currentNode);\n }\n\n if (step) {\n segment.steps.unshift(step);\n }\n\n currentNode = currentNode.parentNode;\n\n }\n\n if (offset != null && offset >= 0) {\n\n segment.terminal.offset = offset;\n\n // Make sure we are getting to a textNode if there is an offset\n if(segment.steps[segment.steps.length-1].type != \"text\") {\n segment.steps.push({\n 'type' : \"text\",\n 'index' : 0\n });\n }\n\n }\n\n\n return segment;\n}\n\nEpubCFI.prototype.equalStep = function(stepA, stepB) {\n if (!stepA || !stepB) {\n return false;\n }\n\n if(stepA.index === stepB.index &&\n stepA.id === stepB.id &&\n stepA.type === stepB.type) {\n return true;\n }\n\n return false;\n};\nEpubCFI.prototype.fromRange = function(range, base, ignoreClass) {\n var cfi = {\n range: false,\n base: {},\n path: {},\n start: null,\n end: null\n };\n\n var start = range.startContainer;\n var end = range.endContainer;\n\n var startOffset = range.startOffset;\n var endOffset = range.endOffset;\n\n var needsIgnoring = false;\n\n if (ignoreClass) {\n // Tell pathTo if / what to ignore\n needsIgnoring = (start.ownerDocument.querySelector('.' + ignoreClass) != null);\n }\n\n\n if (typeof base === 'string') {\n cfi.base = this.parseComponent(base);\n cfi.spinePos = cfi.base.steps[1].index;\n } else if (typeof base === 'object') {\n cfi.base = base;\n }\n\n if (range.collapsed) {\n if (needsIgnoring) {\n startOffset = this.patchOffset(start, startOffset, ignoreClass);\n }\n cfi.path = this.pathTo(start, startOffset, ignoreClass);\n } else {\n cfi.range = true;\n\n if (needsIgnoring) {\n startOffset = this.patchOffset(start, startOffset, ignoreClass);\n }\n\n cfi.start = this.pathTo(start, startOffset, ignoreClass);\n\n if (needsIgnoring) {\n endOffset = this.patchOffset(end, endOffset, ignoreClass);\n }\n\n cfi.end = this.pathTo(end, endOffset, ignoreClass);\n\n // Create a new empty path\n cfi.path = {\n steps: [],\n terminal: null\n };\n\n // Push steps that are shared between start and end to the common path\n var len = cfi.start.steps.length;\n var i;\n\n for (i = 0; i < len; i++) {\n if (this.equalStep(cfi.start.steps[i], cfi.end.steps[i])) {\n if(i == len-1) {\n // Last step is equal, check terminals\n if(cfi.start.terminal === cfi.end.terminal) {\n // CFI's are equal\n cfi.path.steps.push(cfi.start.steps[i]);\n // Not a range\n cfi.range = false;\n }\n } else {\n cfi.path.steps.push(cfi.start.steps[i]);\n }\n\n } else {\n break;\n }\n };\n\n cfi.start.steps = cfi.start.steps.slice(cfi.path.steps.length);\n cfi.end.steps = cfi.end.steps.slice(cfi.path.steps.length);\n\n // TODO: Add Sanity check to make sure that the end if greater than the start\n }\n\n return cfi;\n}\n\nEpubCFI.prototype.fromNode = function(anchor, base, ignoreClass) {\n var cfi = {\n range: false,\n base: {},\n path: {},\n start: null,\n end: null\n };\n\n var needsIgnoring = false;\n\n if (ignoreClass) {\n // Tell pathTo if / what to ignore\n needsIgnoring = (anchor.ownerDocument.querySelector('.' + ignoreClass) != null);\n }\n\n if (typeof base === 'string') {\n cfi.base = this.parseComponent(base);\n cfi.spinePos = cfi.base.steps[1].index;\n } else if (typeof base === 'object') {\n cfi.base = base;\n }\n\n cfi.path = this.pathTo(anchor, null, ignoreClass);\n\n return cfi;\n};\n\n\nEpubCFI.prototype.filter = function(anchor, ignoreClass) {\n var needsIgnoring;\n var sibling; // to join with\n var parent, prevSibling, nextSibling;\n var isText = false;\n\n if (anchor.nodeType === Node.TEXT_NODE) {\n isText = true;\n parent = anchor.parentNode;\n needsIgnoring = anchor.parentNode.classList.contains(ignoreClass);\n } else {\n isText = false;\n needsIgnoring = anchor.classList.contains(ignoreClass);\n }\n\n if (needsIgnoring && isText) {\n previousSibling = parent.previousSibling;\n nextSibling = parent.nextSibling;\n\n // If the sibling is a text node, join the nodes\n if (previousSibling && previousSibling.nodeType === Node.TEXT_NODE) {\n sibling = previousSibling;\n } else if (nextSibling && nextSibling.nodeType === Node.TEXT_NODE) {\n sibling = nextSibling;\n }\n\n if (sibling) {\n return sibling;\n } else {\n // Parent will be ignored on next step\n return anchor;\n }\n\n } else if (needsIgnoring && !isText) {\n // Otherwise just skip the element node\n return false;\n } else {\n // No need to filter\n return anchor;\n }\n\n};\n\nEpubCFI.prototype.patchOffset = function(anchor, offset, ignoreClass) {\n var needsIgnoring;\n var sibling;\n\n if (anchor.nodeType != Node.TEXT_NODE) {\n console.error(\"Anchor must be a text node\");\n return;\n }\n\n var curr = anchor;\n var totalOffset = offset;\n\n // If the parent is a ignored node, get offset from it's start\n if (anchor.parentNode.classList.contains(ignoreClass)) {\n curr = anchor.parentNode;\n }\n\n while (curr.previousSibling) {\n if(curr.previousSibling.nodeType === Node.ELEMENT_NODE) {\n // Originally a text node, so join\n if(curr.previousSibling.classList.contains(ignoreClass)){\n totalOffset += curr.previousSibling.textContent.length;\n } else {\n break; // Normal node, dont join\n }\n } else {\n // If the previous sibling is a text node, join the nodes\n totalOffset += curr.previousSibling.textContent.length;\n }\n\n curr = curr.previousSibling;\n }\n\n return totalOffset;\n\n};\n\nEpubCFI.prototype.normalizedMap = function(children, nodeType, ignoreClass) {\n var output = {};\n var prevIndex = -1;\n var i, len = children.length;\n var currNodeType;\n var prevNodeType;\n\n for (i = 0; i < len; i++) {\n\n currNodeType = children[i].nodeType;\n\n // Check if needs ignoring\n if (currNodeType === Node.ELEMENT_NODE &&\n children[i].classList.contains(ignoreClass)) {\n currNodeType = Node.TEXT_NODE;\n }\n\n if (i > 0 &&\n currNodeType === Node.TEXT_NODE &&\n prevNodeType === Node.TEXT_NODE) {\n // join text nodes\n output[i] = prevIndex;\n } else if (nodeType === currNodeType){\n prevIndex = prevIndex + 1;\n output[i] = prevIndex;\n }\n\n prevNodeType = currNodeType;\n\n }\n\n return output;\n};\n\nEpubCFI.prototype.position = function(anchor) {\n var children, index, map;\n\n if (anchor.nodeType === Node.ELEMENT_NODE) {\n children = anchor.parentNode.children;\n index = Array.prototype.indexOf.call(children, anchor);\n } else {\n children = this.textNodes(anchor.parentNode);\n index = children.indexOf(anchor);\n }\n\n return index;\n};\n\nEpubCFI.prototype.filteredPosition = function(anchor, ignoreClass) {\n var children, index, map;\n\n if (anchor.nodeType === Node.ELEMENT_NODE) {\n children = anchor.parentNode.children;\n map = this.normalizedMap(children, Node.ELEMENT_NODE, ignoreClass);\n } else {\n children = anchor.parentNode.childNodes;\n // Inside an ignored node\n if(anchor.parentNode.classList.contains(ignoreClass)) {\n anchor = anchor.parentNode;\n children = anchor.parentNode.childNodes;\n }\n map = this.normalizedMap(children, Node.TEXT_NODE, ignoreClass);\n }\n\n\n index = Array.prototype.indexOf.call(children, anchor);\n\n return map[index];\n};\n\nEpubCFI.prototype.stepsToXpath = function(steps) {\n var xpath = [\".\", \"*\"];\n\n steps.forEach(function(step){\n var position = step.index + 1;\n\n if(step.id){\n xpath.push(\"*[position()=\" + position + \" and @id='\" + step.id + \"']\");\n } else if(step.type === \"text\") {\n xpath.push(\"text()[\" + position + \"]\");\n } else {\n xpath.push(\"*[\" + position + \"]\");\n }\n });\n\n return xpath.join(\"/\");\n};\n\n\n/*\n\nTo get the last step if needed:\n\n// Get the terminal step\nlastStep = steps[steps.length-1];\n// Get the query string\nquery = this.stepsToQuery(steps);\n// Find the containing element\nstartContainerParent = doc.querySelector(query);\n// Find the text node within that element\nif(startContainerParent && lastStep.type == \"text\") {\n container = startContainerParent.childNodes[lastStep.index];\n}\n*/\nEpubCFI.prototype.stepsToQuerySelector = function(steps) {\n var query = [\"html\"];\n\n steps.forEach(function(step){\n var position = step.index + 1;\n\n if(step.id){\n query.push(\"#\" + step.id);\n } else if(step.type === \"text\") {\n // unsupported in querySelector\n // query.push(\"text()[\" + position + \"]\");\n } else {\n query.push(\"*:nth-child(\" + position + \")\");\n }\n });\n\n return query.join(\">\");\n\n};\n\nEpubCFI.prototype.textNodes = function(container, ignoreClass) {\n return Array.prototype.slice.call(container.childNodes).\n filter(function (node) {\n if (node.nodeType === Node.TEXT_NODE) {\n return true;\n } else if (ignoreClass && node.classList.contains(ignoreClass)) {\n return true;\n }\n return false;\n });\n};\n\nEpubCFI.prototype.walkToNode = function(steps, _doc, ignoreClass) {\n var doc = _doc || document;\n var container = doc.documentElement;\n var step;\n var len = steps.length;\n var i;\n\n for (i = 0; i < len; i++) {\n step = steps[i];\n\n if(step.type === \"element\") {\n container = container.children[step.index];\n } else if(step.type === \"text\"){\n container = this.textNodes(container, ignoreClass)[step.index];\n }\n\n };\n\n return container;\n};\n\nEpubCFI.prototype.findNode = function(steps, _doc, ignoreClass) {\n var doc = _doc || document;\n var container;\n var xpath;\n\n if(!ignoreClass && typeof doc.evaluate != 'undefined') {\n xpath = this.stepsToXpath(steps);\n container = doc.evaluate(xpath, doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;\n } else if(ignoreClass) {\n container = this.walkToNode(steps, doc, ignoreClass);\n } else {\n container = this.walkToNode(steps, doc);\n }\n\n return container;\n};\n\nEpubCFI.prototype.fixMiss = function(steps, offset, _doc, ignoreClass) {\n var container = this.findNode(steps.slice(0,-1), _doc, ignoreClass);\n var children = container.childNodes;\n var map = this.normalizedMap(children, Node.TEXT_NODE, ignoreClass);\n var i;\n var child;\n var len;\n var childIndex;\n var lastStepIndex = steps[steps.length-1].index;\n\n for (var childIndex in map) {\n if (!map.hasOwnProperty(childIndex)) return;\n\n if(map[childIndex] === lastStepIndex) {\n child = children[childIndex];\n len = child.textContent.length;\n if(offset > len) {\n offset = offset - len;\n } else {\n if (child.nodeType === Node.ELEMENT_NODE) {\n container = child.childNodes[0];\n } else {\n container = child;\n }\n break;\n }\n }\n }\n\n return {\n container: container,\n offset: offset\n };\n\n};\n\nEpubCFI.prototype.toRange = function(_doc, ignoreClass) {\n var doc = _doc || document;\n var range = doc.createRange();\n var start, end, startContainer, endContainer;\n var cfi = this;\n var startSteps, endSteps;\n var needsIgnoring = ignoreClass ? (doc.querySelector('.' + ignoreClass) != null) : false;\n var missed;\n\n if (cfi.range) {\n start = cfi.start;\n startSteps = cfi.path.steps.concat(start.steps);\n startContainer = this.findNode(startSteps, doc, needsIgnoring ? ignoreClass : null);\n end = cfi.end;\n endSteps = cfi.path.steps.concat(end.steps);\n endContainer = this.findNode(endSteps, doc, needsIgnoring ? ignoreClass : null);\n } else {\n start = cfi.path;\n startSteps = cfi.path.steps;\n startContainer = this.findNode(cfi.path.steps, doc, needsIgnoring ? ignoreClass : null);\n }\n\n if(startContainer) {\n try {\n\n if(start.terminal.offset != null) {\n range.setStart(startContainer, start.terminal.offset);\n } else {\n range.setStart(startContainer, 0);\n }\n\n } catch (e) {\n missed = this.fixMiss(startSteps, start.terminal.offset, doc, needsIgnoring ? ignoreClass : null);\n range.setStart(missed.container, missed.offset);\n }\n } else {\n // No start found\n return null;\n }\n\n if (endContainer) {\n try {\n\n if(end.terminal.offset != null) {\n range.setEnd(endContainer, end.terminal.offset);\n } else {\n range.setEnd(endContainer, 0);\n }\n\n } catch (e) {\n missed = this.fixMiss(endSteps, cfi.end.terminal.offset, doc, needsIgnoring ? ignoreClass : null);\n range.setEnd(missed.container, missed.offset);\n }\n }\n\n\n // doc.defaultView.getSelection().addRange(range);\n return range;\n};\n\n// is a cfi string, should be wrapped with \"epubcfi()\"\nEpubCFI.prototype.isCfiString = function(str) {\n if(typeof str === 'string' &&\n str.indexOf(\"epubcfi(\") === 0 &&\n str[str.length-1] === \")\") {\n return true;\n }\n\n return false;\n};\n\nEpubCFI.prototype.generateChapterComponent = function(_spineNodeIndex, _pos, id) {\n var pos = parseInt(_pos),\n spineNodeIndex = _spineNodeIndex + 1,\n cfi = '/'+spineNodeIndex+'/';\n\n cfi += (pos + 1) * 2;\n\n if(id) {\n cfi += \"[\" + id + \"]\";\n }\n\n return cfi;\n};\n\nmodule.exports = EpubCFI;\n","var RSVP = require('rsvp');\n\n//-- Hooks allow for injecting functions that must all complete in order before finishing\n// They will execute in parallel but all must finish before continuing\n// Functions may return a promise if they are asycn.\n\n// this.content = new EPUBJS.Hook();\n// this.content.register(function(){});\n// this.content.trigger(args).then(function(){});\n\nfunction Hook(context){\n this.context = context || this;\n this.hooks = [];\n};\n\n// Adds a function to be run before a hook completes\nHook.prototype.register = function(){\n for(var i = 0; i < arguments.length; ++i) {\n if (typeof arguments[i] === \"function\") {\n this.hooks.push(arguments[i]);\n } else {\n // unpack array\n for(var j = 0; j < arguments[i].length; ++j) {\n this.hooks.push(arguments[i][j]);\n }\n }\n }\n};\n\n// Triggers a hook to run all functions\nHook.prototype.trigger = function(){\n var args = arguments;\n var context = this.context;\n var promises = [];\n\n this.hooks.forEach(function(task, i) {\n var executing = task.apply(context, args);\n\n if(executing && typeof executing[\"then\"] === \"function\") {\n // Task is a function that returns a promise\n promises.push(executing);\n }\n // Otherwise Task resolves immediately, continue\n });\n\n\n return RSVP.all(promises);\n};\n\n// Adds a function to be run before a hook completes\nHook.prototype.list = function(){\n return this.hooks;\n};\n\nHook.prototype.clear = function(){\n return this.hooks = [];\n};\n\nmodule.exports = Hook;\n","var core = require('./core');\nvar RSVP = require('rsvp');\n\nfunction Layout(settings){\n this.name = settings.layout || \"reflowable\";\n this._spread = (settings.spread === \"none\") ? false : true;\n this._minSpreadWidth = settings.spread || 800;\n this._evenSpreads = settings.evenSpreads || false;\n\n if (settings.flow === \"scrolled-continuous\" ||\n settings.flow === \"scrolled-doc\") {\n this._flow = \"scrolled\";\n } else {\n this._flow = \"paginated\";\n }\n\n\n this.width = 0;\n this.height = 0;\n this.spreadWidth = 0;\n this.delta = 0;\n\n this.columnWidth = 0;\n this.gap = 0;\n this.divisor = 1;\n};\n\n// paginated | scrolled\nLayout.prototype.flow = function(flow) {\n this._flow = (flow === \"paginated\") ? \"paginated\" : \"scrolled\";\n}\n\n// true | false\nLayout.prototype.spread = function(spread, min) {\n\n this._spread = (spread === \"none\") ? false : true;\n\n if (min >= 0) {\n this._minSpreadWidth = min;\n }\n}\n\nLayout.prototype.calculate = function(_width, _height, _gap){\n\n var divisor = 1;\n var gap = _gap || 0;\n\n //-- Check the width and create even width columns\n var fullWidth = Math.floor(_width);\n var width = _width;\n\n var section = Math.floor(width / 8);\n\n var colWidth;\n var spreadWidth;\n var delta;\n\n if (this._spread && width >= this._minSpreadWidth) {\n divisor = 2;\n } else {\n divisor = 1;\n }\n\n if (this.name === \"reflowable\" && this._flow === \"paginated\" && !(_gap >= 0)) {\n gap = ((section % 2 === 0) ? section : section - 1);\n }\n\n if (this.name === \"pre-paginated\" ) {\n gap = 0;\n }\n\n //-- Double Page\n if(divisor > 1) {\n colWidth = Math.floor((width - gap) / divisor);\n } else {\n colWidth = width;\n }\n\n if (this.name === \"pre-paginated\" && divisor > 1) {\n width = colWidth;\n }\n\n spreadWidth = colWidth * divisor;\n\n delta = (colWidth + gap) * divisor;\n\n this.width = width;\n this.height = _height;\n this.spreadWidth = spreadWidth;\n this.delta = delta;\n\n this.columnWidth = colWidth;\n this.gap = gap;\n this.divisor = divisor;\n};\n\nLayout.prototype.format = function(contents){\n var formating;\n\n if (this.name === \"pre-paginated\") {\n formating = contents.fit(this.columnWidth, this.height);\n } else if (this._flow === \"paginated\") {\n formating = contents.columns(this.width, this.height, this.columnWidth, this.gap);\n } else { // scrolled\n formating = contents.size(this.width, null);\n }\n\n return formating; // might be a promise in some View Managers\n};\n\nLayout.prototype.count = function(totalWidth) {\n // var totalWidth = contents.scrollWidth();\n var spreads = Math.ceil( totalWidth / this.spreadWidth);\n\n return {\n spreads : spreads,\n pages : spreads * this.divisor\n };\n};\n\nmodule.exports = Layout;\n","var core = require('./core');\nvar Queue = require('./queue');\nvar EpubCFI = require('./epubcfi');\nvar RSVP = require('rsvp');\n\nfunction Locations(spine, request) {\n this.spine = spine;\n this.request = request;\n\n this.q = new Queue(this);\n this.epubcfi = new EpubCFI();\n\n this._locations = [];\n this.total = 0;\n\n this.break = 150;\n\n this._current = 0;\n\n};\n\n// Load all of sections in the book\nLocations.prototype.generate = function(chars) {\n\n if (chars) {\n this.break = chars;\n }\n\n this.q.pause();\n\n this.spine.each(function(section) {\n\n this.q.enqueue(this.process, section);\n\n }.bind(this));\n\n return this.q.run().then(function() {\n this.total = this._locations.length-1;\n\n if (this._currentCfi) {\n this.currentLocation = this._currentCfi;\n }\n\n return this._locations;\n // console.log(this.precentage(this.book.rendition.location.start), this.precentage(this.book.rendition.location.end));\n }.bind(this));\n\n};\n\nLocations.prototype.process = function(section) {\n\n return section.load(this.request)\n .then(function(contents) {\n\n var range;\n var doc = contents.ownerDocument;\n var counter = 0;\n\n this.sprint(contents, function(node) {\n var len = node.length;\n var dist;\n var pos = 0;\n\n // Start range\n if (counter == 0) {\n range = doc.createRange();\n range.setStart(node, 0);\n }\n\n dist = this.break - counter;\n\n // Node is smaller than a break\n if(dist > len){\n counter += len;\n pos = len;\n }\n\n while (pos < len) {\n counter = this.break;\n pos += this.break;\n\n // Gone over\n if(pos >= len){\n // Continue counter for next node\n counter = len - (pos - this.break);\n\n // At End\n } else {\n // End the previous range\n range.setEnd(node, pos);\n cfi = section.cfiFromRange(range);\n this._locations.push(cfi);\n counter = 0;\n\n // Start new range\n pos += 1;\n range = doc.createRange();\n range.setStart(node, pos);\n }\n }\n\n\n\n }.bind(this));\n\n // Close remaining\n if (range) {\n range.setEnd(prev, prev.length);\n cfi = section.cfiFromRange(range);\n this._locations.push(cfi)\n counter = 0;\n }\n\n }.bind(this));\n\n};\n\nLocations.prototype.sprint = function(root, func) {\n\tvar treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);\n\n\twhile ((node = treeWalker.nextNode())) {\n\t\tfunc(node);\n\t}\n\n};\n\nLocations.prototype.locationFromCfi = function(cfi){\n // Check if the location has not been set yet\n\tif(this._locations.length === 0) {\n\t\treturn -1;\n\t}\n\n return core.locationOf(cfi, this._locations, this.epubcfi.compare);\n};\n\nLocations.prototype.precentageFromCfi = function(cfi) {\n // Find closest cfi\n var loc = this.locationFromCfi(cfi);\n // Get percentage in total\n return this.precentageFromLocation(loc);\n};\n\nLocations.prototype.percentageFromLocation = function(loc) {\n if (!loc || !this.total) {\n return 0;\n }\n return (loc / this.total);\n};\n\nLocations.prototype.cfiFromLocation = function(loc){\n\tvar cfi = -1;\n\t// check that pg is an int\n\tif(typeof loc != \"number\"){\n\t\tloc = parseInt(pg);\n\t}\n\n\tif(loc >= 0 && loc < this._locations.length) {\n\t\tcfi = this._locations[loc];\n\t}\n\n\treturn cfi;\n};\n\nLocations.prototype.cfiFromPercentage = function(value){\n var percentage = (value > 1) ? value / 100 : value; // Normalize value to 0-1\n\tvar loc = Math.ceil(this.total * percentage);\n\n\treturn this.cfiFromLocation(loc);\n};\n\nLocations.prototype.load = function(locations){\n\tthis._locations = JSON.parse(locations);\n this.total = this._locations.length-1;\n return this._locations;\n};\n\nLocations.prototype.save = function(json){\n\treturn JSON.stringify(this._locations);\n};\n\nLocations.prototype.getCurrent = function(json){\n\treturn this._current;\n};\n\nLocations.prototype.setCurrent = function(curr){\n var loc;\n\n if(typeof curr == \"string\"){\n this._currentCfi = curr;\n } else if (typeof curr == \"number\") {\n this._current = curr;\n } else {\n return;\n }\n\n if(this._locations.length === 0) {\n return;\n\t}\n\n if(typeof curr == \"string\"){\n loc = this.locationFromCfi(curr);\n this._current = loc;\n } else {\n loc = curr;\n }\n\n this.trigger(\"changed\", {\n percentage: this.precentageFromLocation(loc)\n });\n};\n\nObject.defineProperty(Locations.prototype, 'currentLocation', {\n get: function () {\n return this._current;\n },\n set: function (curr) {\n this.setCurrent(curr);\n }\n});\n\nRSVP.EventTarget.mixin(Locations.prototype);\n\nmodule.exports = Locations;\n","var RSVP = require('rsvp');\nvar core = require('../core');\nvar SingleViewManager = require('./single');\n\nfunction ContinuousViewManager(options) {\n\n\tSingleViewManager.apply(this, arguments); // call super constructor.\n\n\tthis.name = \"continuous\";\n\n\tthis.settings = core.extend(this.settings || {}, {\n\t\tinfinite: true,\n\t\toverflow: \"auto\",\n\t\taxis: \"vertical\",\n\t\toffset: 500,\n\t\toffsetDelta: 250,\n\t\twidth: undefined,\n\t\theight: undefined\n\t});\n\n\tcore.extend(this.settings, options.settings || {});\n\n\t// Gap can be 0, byt defaults doesn't handle that\n if (options.settings.gap != \"undefined\" && options.settings.gap === 0) {\n this.settings.gap = options.settings.gap;\n }\n\n\t// this.viewSettings.axis = this.settings.axis;\n\tthis.viewSettings = {\n\t\tignoreClass: this.settings.ignoreClass,\n\t\taxis: this.settings.axis,\n\t\tlayout: this.layout,\n\t\twidth: 0,\n\t\theight: 0\n\t};\n\n\tthis.scrollTop = 0;\n\tthis.scrollLeft = 0;\n};\n\n// subclass extends superclass\nContinuousViewManager.prototype = Object.create(SingleViewManager.prototype);\nContinuousViewManager.prototype.constructor = ContinuousViewManager;\n\nContinuousViewManager.prototype.display = function(section, target){\n return SingleViewManager.prototype.display.call(this, section, target)\n\t\t.then(function () {\n\t\t\treturn this.fill();\n\t\t}.bind(this));\n};\n\nContinuousViewManager.prototype.fill = function(_full){\n\tvar full = _full || new RSVP.defer();\n\n\tthis.check().then(function(result) {\n\t\tif (result) {\n\t\t\tthis.fill(full);\n\t\t} else {\n\t\t\tfull.resolve();\n\t\t}\n\t}.bind(this));\n\n\treturn full.promise;\n}\n\nContinuousViewManager.prototype.moveTo = function(offset){\n // var bounds = this.stage.bounds();\n // var dist = Math.floor(offset.top / bounds.height) * bounds.height;\n\tvar distX = 0,\n\t\t\tdistY = 0;\n\n\tvar offsetX = 0,\n\t\t\toffsetY = 0;\n\n\tif(this.settings.axis === \"vertical\") {\n\t\tdistY = offset.top;\n\t\toffsetY = offset.top+this.settings.offset;\n\t} else {\n\t\tdistX = Math.floor(offset.left / this.layout.delta) * this.layout.delta;\n\t\toffsetX = distX+this.settings.offset;\n\t}\n\n return this.check(offsetX, offsetY)\n\t\t.then(function(){\n\t this.scrollBy(distX, distY);\n\t }.bind(this));\n};\n\n/*\nContinuousViewManager.prototype.afterDisplayed = function(currView){\n\tvar next = currView.section.next();\n\tvar prev = currView.section.prev();\n\tvar index = this.views.indexOf(currView);\n\tvar prevView, nextView;\n\n\tif(index + 1 === this.views.length && next) {\n\t\tnextView = this.createView(next);\n\t\tthis.q.enqueue(this.append.bind(this), nextView);\n\t}\n\n\tif(index === 0 && prev) {\n\t\tprevView = this.createView(prev, this.viewSettings);\n\t\tthis.q.enqueue(this.prepend.bind(this), prevView);\n\t}\n\n\t// this.removeShownListeners(currView);\n\t// currView.onShown = this.afterDisplayed.bind(this);\n\tthis.trigger(\"added\", currView.section);\n\n};\n*/\n\nContinuousViewManager.prototype.resize = function(width, height){\n\n\t// Clear the queue\n this.q.clear();\n\n\tthis._stageSize = this.stage.size(width, height);\n\tthis._bounds = this.bounds();\n\n\t// Update for new views\n\tthis.viewSettings.width = this._stageSize.width;\n\tthis.viewSettings.height = this._stageSize.height;\n\n\t// Update for existing views\n\tthis.views.each(function(view) {\n\t\tview.size(this._stageSize.width, this._stageSize.height);\n\t}.bind(this));\n\n this.updateLayout();\n\n // if(this.location) {\n // this.rendition.display(this.location.start);\n // }\n\n this.trigger(\"resized\", {\n width: this.stage.width,\n height: this.stage.height\n });\n\n};\n\nContinuousViewManager.prototype.onResized = function(e) {\n\n // this.views.clear();\n\n clearTimeout(this.resizeTimeout);\n this.resizeTimeout = setTimeout(function(){\n this.resize();\n }.bind(this), 150);\n};\n\nContinuousViewManager.prototype.afterResized = function(view){\n\tthis.trigger(\"resize\", view.section);\n};\n\n// Remove Previous Listeners if present\nContinuousViewManager.prototype.removeShownListeners = function(view){\n\n\t// view.off(\"shown\", this.afterDisplayed);\n\t// view.off(\"shown\", this.afterDisplayedAbove);\n\tview.onDisplayed = function(){};\n\n};\n\n\n// ContinuousViewManager.prototype.append = function(section){\n// \treturn this.q.enqueue(function() {\n//\n// \t\tthis._append(section);\n//\n//\n// \t}.bind(this));\n// };\n//\n// ContinuousViewManager.prototype.prepend = function(section){\n// \treturn this.q.enqueue(function() {\n//\n// \t\tthis._prepend(section);\n//\n// \t}.bind(this));\n//\n// };\n\nContinuousViewManager.prototype.append = function(section){\n\tvar view = this.createView(section);\n\tthis.views.append(view);\n\treturn view;\n};\n\nContinuousViewManager.prototype.prepend = function(section){\n\tvar view = this.createView(section);\n\n\tview.on(\"resized\", this.counter.bind(this));\n\n\tthis.views.prepend(view);\n\treturn view;\n};\n\nContinuousViewManager.prototype.counter = function(bounds){\n\n\tif(this.settings.axis === \"vertical\") {\n\t\tthis.scrollBy(0, bounds.heightDelta, true);\n\t} else {\n\t\tthis.scrollBy(bounds.widthDelta, 0, true);\n\t}\n\n};\n\nContinuousViewManager.prototype.update = function(_offset){\n\tvar container = this.bounds();\n\tvar views = this.views.all();\n\tvar viewsLength = views.length;\n\tvar visible = [];\n\tvar offset = typeof _offset != \"undefined\" ? _offset : (this.settings.offset || 0);\n\tvar isVisible;\n\tvar view;\n\n\tvar updating = new RSVP.defer();\n\tvar promises = [];\n\n\tfor (var i = 0; i < viewsLength; i++) {\n view = views[i];\n\n isVisible = this.isVisible(view, offset, offset, container);\n\n if(isVisible === true) {\n\t\t\tif (!view.displayed) {\n\t\t\t\tpromises.push(view.display(this.request).then(function (view) {\n\t\t\t\t\tview.show();\n\t\t\t\t}));\n\t\t\t}\n visible.push(view);\n } else {\n\t\t\tthis.q.enqueue(view.destroy.bind(view));\n\n\t\t\tclearTimeout(this.trimTimeout);\n\t\t\tthis.trimTimeout = setTimeout(function(){\n\t\t\t\tthis.q.enqueue(this.trim.bind(this));\n\t\t\t}.bind(this), 250);\n }\n\n }\n\n\tif(promises.length){\n return RSVP.all(promises);\n } else {\n updating.resolve();\n return updating.promise;\n }\n\n};\n\nContinuousViewManager.prototype.check = function(_offsetLeft, _offsetTop){\n\tvar last, first, next, prev;\n\n\tvar checking = new RSVP.defer();\n\tvar newViews = [];\n\n\tvar horizontal = (this.settings.axis === \"horizontal\");\n\tvar delta = this.settings.offset || 0;\n\n\tif (_offsetLeft && horizontal) {\n\t\tdelta = _offsetLeft;\n\t}\n\n\tif (_offsetTop && !horizontal) {\n\t\tdelta = _offsetTop;\n\t}\n\n\tvar bounds = this._bounds; // bounds saved this until resize\n\n\tvar offset = horizontal ? this.scrollLeft : this.scrollTop;\n\tvar visibleLength = horizontal ? bounds.width : bounds.height;\n\tvar contentLength = horizontal ? this.container.scrollWidth : this.container.scrollHeight;\n\n\tif (offset + visibleLength + delta >= contentLength) {\n\t\tlast = this.views.last();\n next = last && last.section.next();\n if(next) {\n newViews.push(this.append(next));\n }\n }\n\n if (offset - delta < 0 ) {\n\t\tfirst = this.views.first();\n prev = first && first.section.prev();\n if(prev) {\n newViews.push(this.prepend(prev));\n }\n }\n\n if(newViews.length){\n // RSVP.all(promises)\n // .then(function() {\n // Check to see if anything new is on screen after rendering\n return this.q.enqueue(function(){\n\t\t\t\t\treturn this.update(delta);\n\t\t\t\t}.bind(this));\n\n\n // }.bind(this));\n\n } else {\n checking.resolve(false);\n\t\treturn checking.promise;\n }\n\n\n};\n\nContinuousViewManager.prototype.trim = function(){\n var task = new RSVP.defer();\n var displayed = this.views.displayed();\n var first = displayed[0];\n var last = displayed[displayed.length-1];\n var firstIndex = this.views.indexOf(first);\n var lastIndex = this.views.indexOf(last);\n var above = this.views.slice(0, firstIndex);\n var below = this.views.slice(lastIndex+1);\n\n // Erase all but last above\n for (var i = 0; i < above.length-1; i++) {\n this.erase(above[i], above);\n }\n\n // Erase all except first below\n for (var j = 1; j < below.length; j++) {\n this.erase(below[j]);\n }\n\n task.resolve();\n return task.promise;\n};\n\nContinuousViewManager.prototype.erase = function(view, above){ //Trim\n\n\tvar prevTop;\n\tvar prevLeft;\n\n\tif(this.settings.height) {\n \tprevTop = this.container.scrollTop;\n\t\tprevLeft = this.container.scrollLeft;\n } else {\n \tprevTop = window.scrollY;\n\t\tprevLeft = window.scrollX;\n }\n\n\tvar bounds = view.bounds();\n\n\tthis.views.remove(view);\n\n\tif(above) {\n\n\t\tif(this.settings.axis === \"vertical\") {\n\t\t\tthis.scrollTo(0, prevTop - bounds.height, true);\n\t\t} else {\n\t\t\tthis.scrollTo(prevLeft - bounds.width, 0, true);\n\t\t}\n\t}\n\n};\n\nContinuousViewManager.prototype.addEventListeners = function(stage){\n\n\twindow.addEventListener('unload', function(e){\n\t\tthis.ignore = true;\n\t\t// this.scrollTo(0,0);\n\t\tthis.destroy();\n\t}.bind(this));\n\n\tthis.addScrollListeners();\n};\n\nContinuousViewManager.prototype.addScrollListeners = function() {\n var scroller;\n\n this.tick = core.requestAnimationFrame;\n\n if(this.settings.height) {\n \tthis.prevScrollTop = this.container.scrollTop;\n \tthis.prevScrollLeft = this.container.scrollLeft;\n } else {\n \tthis.prevScrollTop = window.scrollY;\n\t\tthis.prevScrollLeft = window.scrollX;\n }\n\n this.scrollDeltaVert = 0;\n this.scrollDeltaHorz = 0;\n\n if(this.settings.height) {\n \tscroller = this.container;\n\t\tthis.scrollTop = this.container.scrollTop;\n\t\tthis.scrollLeft = this.container.scrollLeft;\n } else {\n \tscroller = window;\n\t\tthis.scrollTop = window.scrollY;\n\t\tthis.scrollLeft = window.scrollX;\n }\n\n scroller.addEventListener(\"scroll\", this.onScroll.bind(this));\n\n // this.tick.call(window, this.onScroll.bind(this));\n\n this.scrolled = false;\n\n};\n\nContinuousViewManager.prototype.onScroll = function(){\n\n // if(!this.ignore) {\n\n if(this.settings.height) {\n\t \tscrollTop = this.container.scrollTop;\n\t \tscrollLeft = this.container.scrollLeft;\n\t } else {\n\t \tscrollTop = window.scrollY;\n\t\t\tscrollLeft = window.scrollX;\n\t }\n\n\t\tthis.scrollTop = scrollTop;\n\t\tthis.scrollLeft = scrollLeft;\n\n if(!this.ignore) {\n\n\t if((this.scrollDeltaVert === 0 &&\n\t \t this.scrollDeltaHorz === 0) ||\n\t \t this.scrollDeltaVert > this.settings.offsetDelta ||\n\t \t this.scrollDeltaHorz > this.settings.offsetDelta) {\n\n\t\t\t\tthis.q.enqueue(function() {\n\t\t\t\t\tthis.check();\n\t\t\t\t}.bind(this));\n\t\t\t\t// this.check();\n\n\t\t\t\tthis.scrollDeltaVert = 0;\n\t \tthis.scrollDeltaHorz = 0;\n\n\t\t\t\tthis.trigger(\"scroll\", {\n\t\t top: scrollTop,\n\t\t left: scrollLeft\n\t\t });\n\n\t\t\t\tclearTimeout(this.afterScrolled);\n\t\t\t\tthis.afterScrolled = setTimeout(function () {\n\t\t\t\t\tthis.trigger(\"scrolled\", {\n\t\t\t top: this.scrollTop,\n\t\t\t left: this.scrollLeft\n\t\t\t });\n\t\t\t\t}.bind(this));\n\n\t\t\t}\n\n\t\t} else {\n\t this.ignore = false;\n\t\t}\n\n this.scrollDeltaVert += Math.abs(scrollTop-this.prevScrollTop);\n this.scrollDeltaHorz += Math.abs(scrollLeft-this.prevScrollLeft);\n\n\t\tthis.prevScrollTop = scrollTop;\n\t\tthis.prevScrollLeft = scrollLeft;\n\n \tclearTimeout(this.scrollTimeout);\n\t\tthis.scrollTimeout = setTimeout(function(){\n\t\t\tthis.scrollDeltaVert = 0;\n\t this.scrollDeltaHorz = 0;\n\t\t}.bind(this), 150);\n\n\n this.scrolled = false;\n // }\n\n // this.tick.call(window, this.onScroll.bind(this));\n\n};\n\n\n// ContinuousViewManager.prototype.resizeView = function(view) {\n//\n// \tif(this.settings.axis === \"horizontal\") {\n// \t\tview.lock(\"height\", this.stage.width, this.stage.height);\n// \t} else {\n// \t\tview.lock(\"width\", this.stage.width, this.stage.height);\n// \t}\n//\n// };\n\nContinuousViewManager.prototype.currentLocation = function(){\n\n if (this.settings.axis === \"vertical\") {\n \tthis.location = this.scrolledLocation();\n } else {\n\t\tthis.location = this.paginatedLocation();\n\t}\n\n\treturn this.location;\n};\n\nContinuousViewManager.prototype.scrolledLocation = function(){\n\n var visible = this.visible();\n var startPage, endPage;\n\n var container = this.container.getBoundingClientRect();\n\n if(visible.length === 1) {\n return this.mapping.page(visible[0].contents, visible[0].section.cfiBase);\n }\n\n if(visible.length > 1) {\n\n startPage = this.mapping.page(visible[0].contents, visible[0].section.cfiBase);\n endPage = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase);\n\n return {\n start: startPage.start,\n end: endPage.end\n };\n }\n\n};\n\nContinuousViewManager.prototype.paginatedLocation = function(){\n var visible = this.visible();\n var startA, startB, endA, endB;\n var pageLeft, pageRight;\n var container = this.container.getBoundingClientRect();\n\n if(visible.length === 1) {\n startA = container.left - visible[0].position().left;\n endA = startA + this.layout.spreadWidth;\n\n return this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA);\n }\n\n if(visible.length > 1) {\n\n // Left Col\n startA = container.left - visible[0].position().left;\n endA = startA + this.layout.columnWidth;\n\n // Right Col\n startB = container.left + this.layout.spreadWidth - visible[visible.length-1].position().left;\n endB = startB + this.layout.columnWidth;\n\n pageLeft = this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA);\n pageRight = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase, startB, endB);\n\n return {\n start: pageLeft.start,\n end: pageRight.end\n };\n }\n};\n\n/*\nContinuous.prototype.current = function(what){\n var view, top;\n var container = this.container.getBoundingClientRect();\n var length = this.views.length - 1;\n\n if(this.settings.axis === \"horizontal\") {\n\n for (var i = length; i >= 0; i--) {\n view = this.views[i];\n left = view.position().left;\n\n if(left < container.right) {\n\n if(this._current == view) {\n break;\n }\n\n this._current = view;\n break;\n }\n }\n\n } else {\n\n for (var i = length; i >= 0; i--) {\n view = this.views[i];\n top = view.bounds().top;\n if(top < container.bottom) {\n\n if(this._current == view) {\n break;\n }\n\n this._current = view;\n\n break;\n }\n }\n\n }\n\n return this._current;\n};\n*/\n\nContinuousViewManager.prototype.updateLayout = function() {\n\n\tif (!this.stage) {\n\t\treturn;\n\t}\n\n\tif(this.settings.axis === \"vertical\") {\n\t\tthis.layout.calculate(this._stageSize.width, this._stageSize.height);\n\t} else {\n\t\tthis.layout.calculate(\n\t\t\tthis._stageSize.width,\n\t\t\tthis._stageSize.height,\n\t\t\tthis.settings.gap\n\t\t);\n\n\t\t// Set the look ahead offset for what is visible\n\t\tthis.settings.offset = this.layout.delta;\n\n\t\tthis.stage.addStyleRules(\"iframe\", [{\"margin-right\" : this.layout.gap + \"px\"}]);\n\n\t}\n\n\t// Set the dimensions for views\n\tthis.viewSettings.width = this.layout.width;\n\tthis.viewSettings.height = this.layout.height;\n\n this.setLayout(this.layout);\n\n};\n\nContinuousViewManager.prototype.next = function(){\n\n\tif(this.settings.axis === \"horizontal\") {\n\n this.scrollLeft = this.container.scrollLeft;\n\n if(this.container.scrollLeft +\n this.container.offsetWidth +\n this.layout.delta < this.container.scrollWidth) {\n this.scrollBy(this.layout.delta, 0);\n } else {\n this.scrollTo(this.container.scrollWidth - this.layout.delta, 0);\n }\n\n\t} else {\n\t\tthis.scrollBy(0, this.layout.height);\n\t}\n};\n\nContinuousViewManager.prototype.prev = function(){\n\tif(this.settings.axis === \"horizontal\") {\n this.scrollBy(-this.layout.delta, 0);\n\t} else {\n\t\tthis.scrollBy(0, -this.layout.height);\n\t}\n};\n\nContinuousViewManager.prototype.updateFlow = function(flow){\n\tvar axis = (flow === \"paginated\") ? \"horizontal\" : \"vertical\";\n\n\tthis.settings.axis = axis;\n\n\tthis.viewSettings.axis = axis;\n\n\tthis.settings.overflow = (flow === \"paginated\") ? \"hidden\" : \"auto\";\n\n\t// this.views.each(function(view){\n\t// \tview.setAxis(axis);\n\t// });\n\n\tif (this.settings.axis === \"vertical\") {\n\t\tthis.settings.infinite = true;\n } else {\n\t\tthis.settings.infinite = false;\n\t}\n\n};\nmodule.exports = ContinuousViewManager;\n","var RSVP = require('rsvp');\nvar core = require('../core');\nvar Stage = require('../stage');\nvar Views = require('../views');\nvar EpubCFI = require('../epubcfi');\n// var Layout = require('../layout');\nvar Mapping = require('../mapping');\nvar Queue = require('../queue');\n\nfunction SingleViewManager(options) {\n\n\tthis.name = \"single\";\n\tthis.View = options.view;\n\tthis.request = options.request;\n\tthis.renditionQueue = options.queue;\n\tthis.q = new Queue(this);\n\n\tthis.settings = core.extend(this.settings || {}, {\n\t\tinfinite: true,\n\t\thidden: false,\n\t\twidth: undefined,\n\t\theight: undefined,\n\t\t// globalLayoutProperties : { layout: 'reflowable', spread: 'auto', orientation: 'auto'},\n\t\t// layout: null,\n\t\taxis: \"vertical\",\n\t\tignoreClass: ''\n\t});\n\n\tcore.extend(this.settings, options.settings || {});\n\n\tthis.viewSettings = {\n\t\tignoreClass: this.settings.ignoreClass,\n\t\taxis: this.settings.axis,\n\t\tlayout: this.layout,\n\t\twidth: 0,\n\t\theight: 0\n\t};\n\n}\n\nSingleViewManager.prototype.render = function(element, size){\n\n\t// Save the stage\n\tthis.stage = new Stage({\n\t\twidth: size.width,\n\t\theight: size.height,\n\t\toverflow: this.settings.overflow,\n\t\thidden: this.settings.hidden,\n\t\taxis: this.settings.axis\n\t});\n\n\tthis.stage.attachTo(element);\n\n\t// Get this stage container div\n\tthis.container = this.stage.getContainer();\n\n\t// Views array methods\n\tthis.views = new Views(this.container);\n\n\t// Calculate Stage Size\n\tthis._bounds = this.bounds();\n\tthis._stageSize = this.stage.size();\n\n\t// Set the dimensions for views\n\tthis.viewSettings.width = this._stageSize.width;\n\tthis.viewSettings.height = this._stageSize.height;\n\n\t// Function to handle a resize event.\n\t// Will only attach if width and height are both fixed.\n\tthis.stage.onResize(this.onResized.bind(this));\n\n\t// Add Event Listeners\n\tthis.addEventListeners();\n\n\t// Add Layout method\n\t// this.applyLayoutMethod();\n\tif (this.layout) {\n\t\tthis.updateLayout();\n\t}\n};\n\nSingleViewManager.prototype.addEventListeners = function(){\n\twindow.addEventListener('unload', function(e){\n\t\tthis.destroy();\n\t}.bind(this));\n};\n\nSingleViewManager.prototype.destroy = function(){\n\t// this.views.each(function(view){\n\t// \tview.destroy();\n\t// });\n};\n\nSingleViewManager.prototype.onResized = function(e) {\n\tclearTimeout(this.resizeTimeout);\n this.resizeTimeout = setTimeout(function(){\n this.resize();\n }.bind(this), 150);\n};\n\nSingleViewManager.prototype.resize = function(width, height){\n\n\t// Clear the queue\n this.q.clear();\n\n\tthis._stageSize = this.stage.size(width, height);\n\tthis._bounds = this.bounds();\n\n\t// Update for new views\n\tthis.viewSettings.width = this._stageSize.width;\n\tthis.viewSettings.height = this._stageSize.height;\n\n\t// Update for existing views\n\tthis.views.each(function(view) {\n\t\tview.size(this._stageSize.width, this._stageSize.height);\n\t}.bind(this));\n\n this.updateLayout();\n\n this.trigger(\"resized\", {\n width: this.stage.width,\n height: this.stage.height\n });\n\n};\n\nSingleViewManager.prototype.createView = function(section) {\n\treturn new this.View(section, this.viewSettings);\n};\n\nSingleViewManager.prototype.display = function(section, target){\n\n\tvar displaying = new RSVP.defer();\n\tvar displayed = displaying.promise;\n\n\t// Check to make sure the section we want isn't already shown\n\tvar visible = this.views.find(section);\n\n\t// View is already shown, just move to correct location\n\tif(visible && target) {\n\t\toffset = visible.locationOf(target);\n\t\tthis.moveTo(offset);\n\t\tdisplaying.resolve();\n\t\treturn displayed;\n\t}\n\n\t// Hide all current views\n\tthis.views.hide();\n\n\tthis.views.clear();\n\n\tthis.add(section)\n\t\t.then(function(){\n\t\t\tvar next;\n\t\t\tif (this.layout.name === \"pre-paginated\" &&\n\t\t\t\t\tthis.layout.divisor > 1) {\n\t\t\t\tnext = section.next();\n\t\t\t\tif (next) {\n\t\t\t\t\treturn this.add(next);\n\t\t\t\t}\n\t\t\t}\n\t\t}.bind(this))\n\t\t.then(function(view){\n\n\t\t\t// Move to correct place within the section, if needed\n\t\t\tif(target) {\n\t\t\t\toffset = view.locationOf(target);\n\t\t\t\tthis.moveTo(offset);\n\t\t\t}\n\n\t\t\tthis.views.show();\n\n\t\t\tdisplaying.resolve();\n\n\t\t}.bind(this))\n\t\t// .then(function(){\n\t\t// \treturn this.hooks.display.trigger(view);\n\t\t// }.bind(this))\n\t\t// .then(function(){\n\t\t// \tthis.views.show();\n\t\t// }.bind(this));\n\t\treturn displayed;\n};\n\nSingleViewManager.prototype.afterDisplayed = function(view){\n\tthis.trigger(\"added\", view);\n};\n\nSingleViewManager.prototype.afterResized = function(view){\n\tthis.trigger(\"resize\", view.section);\n};\n\n// SingleViewManager.prototype.moveTo = function(offset){\n// \tthis.scrollTo(offset.left, offset.top);\n// };\n\nSingleViewManager.prototype.moveTo = function(offset){\n\tvar distX = 0,\n\t\t\tdistY = 0;\n\n\tif(this.settings.axis === \"vertical\") {\n\t\tdistY = offset.top;\n\t} else {\n\t\tdistX = Math.floor(offset.left / this.layout.delta) * this.layout.delta;\n\n\t\tif (distX + this.layout.delta > this.container.scrollWidth) {\n\t\t\tdistX = this.container.scrollWidth - this.layout.delta;\n\t\t}\n\t}\n\n this.scrollTo(distX, distY);\n};\n\nSingleViewManager.prototype.add = function(section){\n\tvar view = this.createView(section);\n\n\tthis.views.append(view);\n\n\t// view.on(\"shown\", this.afterDisplayed.bind(this));\n\tview.onDisplayed = this.afterDisplayed.bind(this);\n\tview.onResize = this.afterResized.bind(this);\n\n\treturn view.display(this.request);\n\n};\n\nSingleViewManager.prototype.append = function(section){\n\tvar view = this.createView(section);\n\tthis.views.append(view);\n\treturn view.display(this.request);\n};\n\nSingleViewManager.prototype.prepend = function(section){\n\tvar view = this.createView(section);\n\n\tthis.views.prepend(view);\n\treturn view.display(this.request);\n};\n// SingleViewManager.prototype.resizeView = function(view) {\n//\n// \tif(this.settings.globalLayoutProperties.layout === \"pre-paginated\") {\n// \t\tview.lock(\"both\", this.bounds.width, this.bounds.height);\n// \t} else {\n// \t\tview.lock(\"width\", this.bounds.width, this.bounds.height);\n// \t}\n//\n// };\n\nSingleViewManager.prototype.next = function(){\n\tvar next;\n\tvar view;\n\tvar left;\n\n\tif(!this.views.length) return;\n\n\tif(this.settings.axis === \"horizontal\") {\n\n\t\tthis.scrollLeft = this.container.scrollLeft;\n\n\t\tleft = this.container.scrollLeft + this.container.offsetWidth + this.layout.delta;\n\n\t\tif(left < this.container.scrollWidth) {\n\t\t\tthis.scrollBy(this.layout.delta, 0);\n\t\t} else if (left - this.layout.columnWidth === this.container.scrollWidth) {\n\t\t\tthis.scrollTo(this.container.scrollWidth - this.layout.delta, 0);\n\t\t} else {\n\t\t\tnext = this.views.last().section.next();\n\t\t}\n\n\n\t} else {\n\n\t\tnext = this.views.last().section.next();\n\n\t}\n\n\tif(next) {\n\t\tthis.views.clear();\n\n\t\treturn this.append(next)\n\t\t\t.then(function(){\n\t\t\t\tvar right;\n\t\t\t\tif (this.layout.name && this.layout.divisor > 1) {\n\t\t\t\t\tright = next.next();\n\t\t\t\t\tif (right) {\n\t\t\t\t\t\treturn this.append(right);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}.bind(this))\n\t\t\t.then(function(){\n\t\t\t\tthis.views.show();\n\t\t\t}.bind(this));\n\t}\n\n\n};\n\nSingleViewManager.prototype.prev = function(){\n\tvar prev;\n\tvar view;\n\tvar left;\n\n\tif(!this.views.length) return;\n\n\tif(this.settings.axis === \"horizontal\") {\n\n\t\tthis.scrollLeft = this.container.scrollLeft;\n\n\t\tleft = this.container.scrollLeft;\n\n\t\tif(left > 0) {\n\t\t\tthis.scrollBy(-this.layout.delta, 0);\n\t\t} else {\n\t\t\tprev = this.views.first().section.prev();\n\t\t}\n\n\n\t} else {\n\n\t\tprev = this.views.first().section.prev();\n\n\t}\n\n\tif(prev) {\n\t\tthis.views.clear();\n\n\t\treturn this.prepend(prev)\n\t\t\t.then(function(){\n\t\t\t\tvar left;\n\t\t\t\tif (this.layout.name && this.layout.divisor > 1) {\n\t\t\t\t\tleft = prev.prev();\n\t\t\t\t\tif (left) {\n\t\t\t\t\t\treturn this.prepend(left);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}.bind(this))\n\t\t\t.then(function(){\n\t\t\t\tif(this.settings.axis === \"horizontal\") {\n\t\t\t\t\tthis.scrollTo(this.container.scrollWidth - this.layout.delta, 0);\n\t\t\t\t}\n\t\t\t\tthis.views.show();\n\t\t\t}.bind(this));\n\t}\n};\n\nSingleViewManager.prototype.current = function(){\n\tvar visible = this.visible();\n\tif(visible.length){\n\t\t// Current is the last visible view\n\t\treturn visible[visible.length-1];\n\t}\n return null;\n};\n\nSingleViewManager.prototype.currentLocation = function(){\n var view;\n var start, end;\n\n if(this.views.length) {\n \tview = this.views.first();\n start = container.left - view.position().left;\n end = start + this.layout.spread;\n\n return this.mapping.page(view, view.section.cfiBase);\n }\n\n};\n\nSingleViewManager.prototype.isVisible = function(view, offsetPrev, offsetNext, _container){\n\tvar position = view.position();\n\tvar container = _container || this.bounds();\n\n\tif(this.settings.axis === \"horizontal\" &&\n\t\tposition.right > container.left - offsetPrev &&\n\t\tposition.left < container.right + offsetNext) {\n\n\t\treturn true;\n\n } else if(this.settings.axis === \"vertical\" &&\n \tposition.bottom > container.top - offsetPrev &&\n\t\tposition.top < container.bottom + offsetNext) {\n\n\t\treturn true;\n }\n\n\treturn false;\n\n};\n\nSingleViewManager.prototype.visible = function(){\n\t// return this.views.displayed();\n\tvar container = this.bounds();\n\tvar views = this.views.displayed();\n\tvar viewsLength = views.length;\n var visible = [];\n var isVisible;\n var view;\n\n for (var i = 0; i < viewsLength; i++) {\n view = views[i];\n isVisible = this.isVisible(view, 0, 0, container);\n\n if(isVisible === true) {\n visible.push(view);\n }\n\n }\n return visible;\n};\n\nSingleViewManager.prototype.scrollBy = function(x, y, silent){\n if(silent) {\n this.ignore = true;\n }\n\n if(this.settings.height) {\n\n if(x) this.container.scrollLeft += x;\n \tif(y) this.container.scrollTop += y;\n\n } else {\n \twindow.scrollBy(x,y);\n }\n // console.log(\"scrollBy\", x, y);\n this.scrolled = true;\n\tthis.onScroll();\n};\n\nSingleViewManager.prototype.scrollTo = function(x, y, silent){\n if(silent) {\n this.ignore = true;\n }\n\n if(this.settings.height) {\n \tthis.container.scrollLeft = x;\n \tthis.container.scrollTop = y;\n } else {\n \twindow.scrollTo(x,y);\n }\n // console.log(\"scrollTo\", x, y);\n this.scrolled = true;\n\tthis.onScroll();\n // if(this.container.scrollLeft != x){\n // setTimeout(function() {\n // this.scrollTo(x, y, silent);\n // }.bind(this), 10);\n // return;\n // };\n };\n\nSingleViewManager.prototype.onScroll = function(){\n\n};\n\nSingleViewManager.prototype.bounds = function() {\n\tvar bounds;\n\n\tbounds = this.stage.bounds();\n\n\treturn bounds;\n};\n\nSingleViewManager.prototype.applyLayout = function(layout) {\n\n\tthis.layout = layout;\n\tthis.updateLayout();\n\n\tthis.mapping = new Mapping(this.layout);\n \t// this.manager.layout(this.layout.format);\n};\n\nSingleViewManager.prototype.updateLayout = function() {\n\tif (!this.stage) {\n\t\treturn;\n\t}\n\n\tthis._stageSize = this.stage.size();\n\n\tif(this.settings.axis === \"vertical\") {\n\t\tthis.layout.calculate(this._stageSize.width, this._stageSize.height);\n\t} else {\n\t\tthis.layout.calculate(\n\t\t\tthis._stageSize.width,\n\t\t\tthis._stageSize.height,\n\t\t\tthis.settings.gap\n\t\t);\n\n\t\t// Set the look ahead offset for what is visible\n\t\tthis.settings.offset = this.layout.delta;\n\n\t\tthis.stage.addStyleRules(\"iframe\", [{\"margin-right\" : this.layout.gap + \"px\"}]);\n\n\t}\n\n\t// Set the dimensions for views\n\tthis.viewSettings.width = this.layout.width;\n\tthis.viewSettings.height = this.layout.height;\n\n\tthis.setLayout(this.layout);\n\n};\n\nSingleViewManager.prototype.setLayout = function(layout){\n\n\tthis.viewSettings.layout = layout;\n\n\tif(this.views) {\n\n\t\tthis.views.each(function(view){\n\t\t\tview.setLayout(layout);\n\t\t});\n\n\t}\n\n};\n\nSingleViewManager.prototype.updateFlow = function(flow){\n\tvar axis = (flow === \"paginated\") ? \"horizontal\" : \"vertical\";\n\n\tthis.settings.axis = axis;\n\n\tthis.viewSettings.axis = axis;\n\n\tthis.settings.overflow = (flow === \"paginated\") ? \"hidden\" : \"auto\";\n\t// this.views.each(function(view){\n\t// \tview.setAxis(axis);\n\t// });\n\n};\n\n //-- Enable binding events to Manager\n RSVP.EventTarget.mixin(SingleViewManager.prototype);\n\n module.exports = SingleViewManager;\n","var EpubCFI = require('./epubcfi');\n\nfunction Mapping(layout){\n this.layout = layout;\n};\n\nMapping.prototype.section = function(view) {\n var ranges = this.findRanges(view);\n var map = this.rangeListToCfiList(view.section.cfiBase, ranges);\n\n return map;\n};\n\nMapping.prototype.page = function(contents, cfiBase, start, end) {\n var root = contents && contents.document ? contents.document.body : false;\n\n if (!root) {\n return;\n }\n\n return this.rangePairToCfiPair(cfiBase, {\n start: this.findStart(root, start, end),\n end: this.findEnd(root, start, end)\n });\n};\n\nMapping.prototype.walk = function(root, func) {\n //var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, null, false);\n var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {\n acceptNode: function (node) {\n if ( node.data.trim().length > 0 ) {\n return NodeFilter.FILTER_ACCEPT;\n } else {\n return NodeFilter.FILTER_REJECT;\n }\n }\n }, false);\n var node;\n var result;\n while ((node = treeWalker.nextNode())) {\n result = func(node);\n if(result) break;\n }\n\n return result;\n};\n\nMapping.prototype.findRanges = function(view){\n var columns = [];\n var scrollWidth = view.contents.scrollWidth();\n var count = this.layout.count(scrollWidth);\n var column = this.layout.column;\n var gap = this.layout.gap;\n var start, end;\n\n for (var i = 0; i < count.pages; i++) {\n start = (column + gap) * i;\n end = (column * (i+1)) + (gap * i);\n columns.push({\n start: this.findStart(view.document.body, start, end),\n end: this.findEnd(view.document.body, start, end)\n });\n }\n\n return columns;\n};\n\nMapping.prototype.findStart = function(root, start, end){\n var stack = [root];\n var $el;\n var found;\n var $prev = root;\n while (stack.length) {\n\n $el = stack.shift();\n\n found = this.walk($el, function(node){\n var left, right;\n var elPos;\n var elRange;\n\n\n if(node.nodeType == Node.TEXT_NODE){\n elRange = document.createRange();\n elRange.selectNodeContents(node);\n elPos = elRange.getBoundingClientRect();\n } else {\n elPos = node.getBoundingClientRect();\n }\n\n left = elPos.left;\n right = elPos.right;\n\n if( left >= start && left <= end ) {\n return node;\n } else if (right > start) {\n return node;\n } else {\n $prev = node;\n stack.push(node);\n }\n\n });\n\n if(found) {\n return this.findTextStartRange(found, start, end);\n }\n\n }\n\n // Return last element\n return this.findTextStartRange($prev, start, end);\n};\n\nMapping.prototype.findEnd = function(root, start, end){\n var stack = [root];\n var $el;\n var $prev = root;\n var found;\n\n while (stack.length) {\n\n $el = stack.shift();\n\n found = this.walk($el, function(node){\n\n var left, right;\n var elPos;\n var elRange;\n\n\n if(node.nodeType == Node.TEXT_NODE){\n elRange = document.createRange();\n elRange.selectNodeContents(node);\n elPos = elRange.getBoundingClientRect();\n } else {\n elPos = node.getBoundingClientRect();\n }\n\n left = elPos.left;\n right = elPos.right;\n\n if(left > end && $prev) {\n return $prev;\n } else if(right > end) {\n return node;\n } else {\n $prev = node;\n stack.push(node);\n }\n\n });\n\n\n if(found){\n return this.findTextEndRange(found, start, end);\n }\n\n }\n\n // end of chapter\n return this.findTextEndRange($prev, start, end);\n};\n\n\nMapping.prototype.findTextStartRange = function(node, start, end){\n var ranges = this.splitTextNodeIntoRanges(node);\n var prev;\n var range;\n var pos;\n\n for (var i = 0; i < ranges.length; i++) {\n range = ranges[i];\n\n pos = range.getBoundingClientRect();\n\n if( pos.left >= start ) {\n return range;\n }\n\n prev = range;\n\n }\n\n return ranges[0];\n};\n\nMapping.prototype.findTextEndRange = function(node, start, end){\n var ranges = this.splitTextNodeIntoRanges(node);\n var prev;\n var range;\n var pos;\n\n for (var i = 0; i < ranges.length; i++) {\n range = ranges[i];\n\n pos = range.getBoundingClientRect();\n\n if(pos.left > end && prev) {\n return prev;\n } else if(pos.right > end) {\n return range;\n }\n\n prev = range;\n\n }\n\n // Ends before limit\n return ranges[ranges.length-1];\n\n};\n\nMapping.prototype.splitTextNodeIntoRanges = function(node, _splitter){\n var ranges = [];\n var textContent = node.textContent || \"\";\n var text = textContent.trim();\n var range;\n var rect;\n var list;\n var doc = node.ownerDocument;\n var splitter = _splitter || \" \";\n\n pos = text.indexOf(splitter);\n\n if(pos === -1 || node.nodeType != Node.TEXT_NODE) {\n range = doc.createRange();\n range.selectNodeContents(node);\n return [range];\n }\n\n range = doc.createRange();\n range.setStart(node, 0);\n range.setEnd(node, pos);\n ranges.push(range);\n range = false;\n\n while ( pos != -1 ) {\n\n pos = text.indexOf(splitter, pos + 1);\n if(pos > 0) {\n\n if(range) {\n range.setEnd(node, pos);\n ranges.push(range);\n }\n\n range = doc.createRange();\n range.setStart(node, pos+1);\n }\n }\n\n if(range) {\n range.setEnd(node, text.length);\n ranges.push(range);\n }\n\n return ranges;\n};\n\n\n\nMapping.prototype.rangePairToCfiPair = function(cfiBase, rangePair){\n\n var startRange = rangePair.start;\n var endRange = rangePair.end;\n\n startRange.collapse(true);\n endRange.collapse(true);\n\n // startCfi = section.cfiFromRange(startRange);\n // endCfi = section.cfiFromRange(endRange);\n startCfi = new EpubCFI(startRange, cfiBase).toString();\n endCfi = new EpubCFI(endRange, cfiBase).toString();\n\n return {\n start: startCfi,\n end: endCfi\n };\n\n};\n\nMapping.prototype.rangeListToCfiList = function(cfiBase, columns){\n var map = [];\n var rangePair, cifPair;\n\n for (var i = 0; i < columns.length; i++) {\n cifPair = this.rangePairToCfiPair(cfiBase, columns[i]);\n\n map.push(cifPair);\n\n }\n\n return map;\n};\n\nmodule.exports = Mapping;\n","var core = require('./core');\nvar Parser = require('./parser');\nvar RSVP = require('rsvp');\nvar URI = require('urijs');\n\nfunction Navigation(_package, _request){\n var navigation = this;\n var parse = new Parser();\n var request = _request || require('./request');\n\n this.package = _package;\n this.toc = [];\n this.tocByHref = {};\n this.tocById = {};\n\n if(_package.navPath) {\n this.navUrl = URI(_package.navPath).absoluteTo(_package.baseUrl).toString();\n this.nav = {};\n\n this.nav.load = function(_request){\n var loading = new RSVP.defer();\n var loaded = loading.promise;\n\n request(navigation.navUrl, 'xml').then(function(xml){\n navigation.toc = parse.nav(xml);\n navigation.loaded(navigation.toc);\n loading.resolve(navigation.toc);\n });\n\n return loaded;\n };\n\n }\n\n if(_package.ncxPath) {\n this.ncxUrl = URI(_package.ncxPath).absoluteTo(_package.baseUrl).toString();\n this.ncx = {};\n\n this.ncx.load = function(_request){\n var loading = new RSVP.defer();\n var loaded = loading.promise;\n\n request(navigation.ncxUrl, 'xml').then(function(xml){\n navigation.toc = parse.toc(xml);\n navigation.loaded(navigation.toc);\n loading.resolve(navigation.toc);\n });\n\n return loaded;\n };\n\n }\n};\n\n// Load the navigation\nNavigation.prototype.load = function(_request) {\n var request = _request || require('./request');\n var loading, loaded;\n\n if(this.nav) {\n loading = this.nav.load();\n } else if(this.ncx) {\n loading = this.ncx.load();\n } else {\n loaded = new RSVP.defer();\n loaded.resolve([]);\n loading = loaded.promise;\n }\n\n return loading;\n\n};\n\nNavigation.prototype.loaded = function(toc) {\n var item;\n\n for (var i = 0; i < toc.length; i++) {\n item = toc[i];\n this.tocByHref[item.href] = i;\n this.tocById[item.id] = i;\n }\n\n};\n\n// Get an item from the navigation\nNavigation.prototype.get = function(target) {\n var index;\n\n if(!target) {\n return this.toc;\n }\n\n if(target.indexOf(\"#\") === 0) {\n index = this.tocById[target.substring(1)];\n } else if(target in this.tocByHref){\n index = this.tocByHref[target];\n }\n\n return this.toc[index];\n};\n\nmodule.exports = Navigation;\n","var URI = require('urijs');\nvar core = require('./core');\nvar EpubCFI = require('./epubcfi');\n\n\nfunction Parser(){};\n\nParser.prototype.container = function(containerXml){\n //-- \n var rootfile, fullpath, folder, encoding;\n\n if(!containerXml) {\n console.error(\"Container File Not Found\");\n return;\n }\n\n rootfile = core.qs(containerXml, \"rootfile\");\n\n if(!rootfile) {\n console.error(\"No RootFile Found\");\n return;\n }\n\n fullpath = rootfile.getAttribute('full-path');\n folder = URI(fullpath).directory();\n encoding = containerXml.xmlEncoding;\n\n //-- Now that we have the path we can parse the contents\n return {\n 'packagePath' : fullpath,\n 'basePath' : folder,\n 'encoding' : encoding\n };\n};\n\nParser.prototype.identifier = function(packageXml){\n var metadataNode;\n\n if(!packageXml) {\n console.error(\"Package File Not Found\");\n return;\n }\n\n metadataNode = core.qs(packageXml, \"metadata\");\n\n if(!metadataNode) {\n console.error(\"No Metadata Found\");\n return;\n }\n\n return this.getElementText(metadataNode, \"identifier\");\n};\n\nParser.prototype.packageContents = function(packageXml){\n var parse = this;\n var metadataNode, manifestNode, spineNode;\n var manifest, navPath, ncxPath, coverPath;\n var spineNodeIndex;\n var spine;\n var spineIndexByURL;\n var metadata;\n\n if(!packageXml) {\n console.error(\"Package File Not Found\");\n return;\n }\n\n metadataNode = core.qs(packageXml, \"metadata\");\n if(!metadataNode) {\n console.error(\"No Metadata Found\");\n return;\n }\n\n manifestNode = core.qs(packageXml, \"manifest\");\n if(!manifestNode) {\n console.error(\"No Manifest Found\");\n return;\n }\n\n spineNode = core.qs(packageXml, \"spine\");\n if(!spineNode) {\n console.error(\"No Spine Found\");\n return;\n }\n\n manifest = parse.manifest(manifestNode);\n navPath = parse.findNavPath(manifestNode);\n ncxPath = parse.findNcxPath(manifestNode, spineNode);\n coverPath = parse.findCoverPath(packageXml);\n\n spineNodeIndex = Array.prototype.indexOf.call(spineNode.parentNode.childNodes, spineNode);\n\n spine = parse.spine(spineNode, manifest);\n\n metadata = parse.metadata(metadataNode);\n\n\tmetadata.direction = spineNode.getAttribute(\"page-progression-direction\");\n\n return {\n 'metadata' : metadata,\n 'spine' : spine,\n 'manifest' : manifest,\n 'navPath' : navPath,\n 'ncxPath' : ncxPath,\n 'coverPath': coverPath,\n 'spineNodeIndex' : spineNodeIndex\n };\n};\n\n//-- Find TOC NAV\nParser.prototype.findNavPath = function(manifestNode){\n\t// Find item with property 'nav'\n\t// Should catch nav irregardless of order\n // var node = manifestNode.querySelector(\"item[properties$='nav'], item[properties^='nav '], item[properties*=' nav ']\");\n var node = core.qsp(manifestNode, \"item\", {\"properties\":\"nav\"});\n return node ? node.getAttribute('href') : false;\n};\n\n//-- Find TOC NCX: media-type=\"application/x-dtbncx+xml\" href=\"toc.ncx\"\nParser.prototype.findNcxPath = function(manifestNode, spineNode){\n\t// var node = manifestNode.querySelector(\"item[media-type='application/x-dtbncx+xml']\");\n var node = core.qsp(manifestNode, \"item\", {\"media-type\":\"application/x-dtbncx+xml\"});\n\tvar tocId;\n\n\t// If we can't find the toc by media-type then try to look for id of the item in the spine attributes as\n\t// according to http://www.idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.4.1.2,\n\t// \"The item that describes the NCX must be referenced by the spine toc attribute.\"\n\tif (!node) {\n\t\ttocId = spineNode.getAttribute(\"toc\");\n\t\tif(tocId) {\n\t\t\t// node = manifestNode.querySelector(\"item[id='\" + tocId + \"']\");\n node = manifestNode.getElementById(tocId);\n\t\t}\n\t}\n\n\treturn node ? node.getAttribute('href') : false;\n};\n\n//-- Expanded to match Readium web components\nParser.prototype.metadata = function(xml){\n var metadata = {},\n p = this;\n\n metadata.title = p.getElementText(xml, 'title');\n metadata.creator = p.getElementText(xml, 'creator');\n metadata.description = p.getElementText(xml, 'description');\n\n metadata.pubdate = p.getElementText(xml, 'date');\n\n metadata.publisher = p.getElementText(xml, 'publisher');\n\n metadata.identifier = p.getElementText(xml, \"identifier\");\n metadata.language = p.getElementText(xml, \"language\");\n metadata.rights = p.getElementText(xml, \"rights\");\n\n metadata.modified_date = p.getPropertyText(xml, 'dcterms:modified');\n\n metadata.layout = p.getPropertyText(xml, \"rendition:layout\");\n metadata.orientation = p.getPropertyText(xml, 'rendition:orientation');\n metadata.flow = p.getPropertyText(xml, 'rendition:flow');\n metadata.viewport = p.getPropertyText(xml, 'rendition:viewport');\n // metadata.page_prog_dir = packageXml.querySelector(\"spine\").getAttribute(\"page-progression-direction\");\n\n return metadata;\n};\n\n//-- Find Cover: \n//-- Fallback for Epub 2.0\nParser.prototype.findCoverPath = function(packageXml){\n var pkg = core.qs(packageXml, \"package\");\n\tvar epubVersion = pkg.getAttribute('version');\n\n\tif (epubVersion === '2.0') {\n\t\tvar metaCover = core.qsp(packageXml, 'meta', {'name':'cover'});\n\t\tif (metaCover) {\n\t\t\tvar coverId = metaCover.getAttribute('content');\n\t\t\t// var cover = packageXml.querySelector(\"item[id='\" + coverId + \"']\");\n var cover = packageXml.getElementById(coverId);\n\t\t\treturn cover ? cover.getAttribute('href') : false;\n\t\t}\n\t\telse {\n\t\t\treturn false;\n\t\t}\n\t}\n\telse {\n // var node = packageXml.querySelector(\"item[properties='cover-image']\");\n var node = core.qsp(packageXml, 'item', {'properties':'cover-image'});\n\t\treturn node ? node.getAttribute('href') : false;\n\t}\n};\n\nParser.prototype.getElementText = function(xml, tag){\n var found = xml.getElementsByTagNameNS(\"http://purl.org/dc/elements/1.1/\", tag),\n el;\n\n if(!found || found.length === 0) return '';\n\n el = found[0];\n\n if(el.childNodes.length){\n return el.childNodes[0].nodeValue;\n }\n\n return '';\n\n};\n\nParser.prototype.getPropertyText = function(xml, property){\n var el = core.qsp(xml, \"meta\", {\"property\":property});\n\n if(el && el.childNodes.length){\n return el.childNodes[0].nodeValue;\n }\n\n return '';\n};\n\nParser.prototype.querySelectorText = function(xml, q){\n var el = xml.querySelector(q);\n\n if(el && el.childNodes.length){\n return el.childNodes[0].nodeValue;\n }\n\n return '';\n};\n\nParser.prototype.manifest = function(manifestXml){\n var manifest = {};\n\n //-- Turn items into an array\n // var selected = manifestXml.querySelectorAll(\"item\");\n var selected = core.qsa(manifestXml, \"item\");\n var items = Array.prototype.slice.call(selected);\n\n //-- Create an object with the id as key\n items.forEach(function(item){\n var id = item.getAttribute('id'),\n href = item.getAttribute('href') || '',\n type = item.getAttribute('media-type') || '',\n properties = item.getAttribute('properties') || '';\n\n manifest[id] = {\n 'href' : href,\n // 'url' : href,\n 'type' : type,\n 'properties' : properties.length ? properties.split(' ') : []\n };\n\n });\n\n return manifest;\n\n};\n\nParser.prototype.spine = function(spineXml, manifest){\n var spine = [];\n\n var selected = spineXml.getElementsByTagName(\"itemref\"),\n items = Array.prototype.slice.call(selected);\n\n var epubcfi = new EpubCFI();\n\n //-- Add to array to mantain ordering and cross reference with manifest\n items.forEach(function(item, index){\n var idref = item.getAttribute('idref');\n // var cfiBase = epubcfi.generateChapterComponent(spineNodeIndex, index, Id);\n var props = item.getAttribute('properties') || '';\n var propArray = props.length ? props.split(' ') : [];\n // var manifestProps = manifest[Id].properties;\n // var manifestPropArray = manifestProps.length ? manifestProps.split(' ') : [];\n\n var itemref = {\n 'idref' : idref,\n 'linear' : item.getAttribute('linear') || '',\n 'properties' : propArray,\n // 'href' : manifest[Id].href,\n // 'url' : manifest[Id].url,\n 'index' : index\n // 'cfiBase' : cfiBase\n };\n spine.push(itemref);\n });\n\n return spine;\n};\n\nParser.prototype.querySelectorByType = function(html, element, type){\n var query;\n if (typeof html.querySelector != \"undefined\") {\n query = html.querySelector(element+'[*|type=\"'+type+'\"]');\n }\n\t// Handle IE not supporting namespaced epub:type in querySelector\n\tif(!query || query.length === 0) {\n\t\tquery = core.qsa(html, element);\n\t\tfor (var i = 0; i < query.length; i++) {\n\t\t\tif(query[i].getAttributeNS(\"http://www.idpf.org/2007/ops\", \"type\") === type) {\n\t\t\t\treturn query[i];\n\t\t\t}\n\t\t}\n\t} else {\n\t\treturn query;\n\t}\n};\n\nParser.prototype.nav = function(navHtml, spineIndexByURL, bookSpine){\n\tvar navElement = this.querySelectorByType(navHtml, \"nav\", \"toc\");\n // var navItems = navElement ? navElement.querySelectorAll(\"ol li\") : [];\n\tvar navItems = navElement ? core.qsa(navElement, \"li\") : [];\n\tvar length = navItems.length;\n\tvar i;\n\tvar toc = {};\n\tvar list = [];\n\tvar item, parent;\n\n\tif(!navItems || length === 0) return list;\n\n\tfor (i = 0; i < length; ++i) {\n\t\titem = this.navItem(navItems[i], spineIndexByURL, bookSpine);\n\t\ttoc[item.id] = item;\n\t\tif(!item.parent) {\n\t\t\tlist.push(item);\n\t\t} else {\n\t\t\tparent = toc[item.parent];\n\t\t\tparent.subitems.push(item);\n\t\t}\n\t}\n\n\treturn list;\n};\n\nParser.prototype.navItem = function(item, spineIndexByURL, bookSpine){\n\tvar id = item.getAttribute('id') || false,\n\t\t\t// content = item.querySelector(\"a, span\"),\n content = core.qs(item, \"a\"),\n\t\t\tsrc = content.getAttribute('href') || '',\n\t\t\ttext = content.textContent || \"\",\n\t\t\t// split = src.split(\"#\"),\n\t\t\t// baseUrl = split[0],\n\t\t\t// spinePos = spineIndexByURL[baseUrl],\n\t\t\t// spineItem = bookSpine[spinePos],\n\t\t\tsubitems = [],\n\t\t\tparentNode = item.parentNode,\n\t\t\tparent;\n\t\t\t// cfi = spineItem ? spineItem.cfi : '';\n\n\tif(parentNode && parentNode.nodeName === \"navPoint\") {\n\t\tparent = parentNode.getAttribute('id');\n\t}\n\n /*\n\tif(!id) {\n\t\tif(spinePos) {\n\t\t\tspineItem = bookSpine[spinePos];\n\t\t\tid = spineItem.id;\n\t\t\tcfi = spineItem.cfi;\n\t\t} else {\n\t\t\tid = 'epubjs-autogen-toc-id-' + EPUBJS.core.uuid();\n\t\t\titem.setAttribute('id', id);\n\t\t}\n\t}\n */\n\n\treturn {\n\t\t\"id\": id,\n\t\t\"href\": src,\n\t\t\"label\": text,\n\t\t\"subitems\" : subitems,\n\t\t\"parent\" : parent\n\t};\n};\n\nParser.prototype.ncx = function(tocXml, spineIndexByURL, bookSpine){\n\t// var navPoints = tocXml.querySelectorAll(\"navMap navPoint\");\n var navPoints = core.qsa(tocXml, \"navPoint\");\n\tvar length = navPoints.length;\n\tvar i;\n\tvar toc = {};\n\tvar list = [];\n\tvar item, parent;\n\n\tif(!navPoints || length === 0) return list;\n\n\tfor (i = 0; i < length; ++i) {\n\t\titem = this.ncxItem(navPoints[i], spineIndexByURL, bookSpine);\n\t\ttoc[item.id] = item;\n\t\tif(!item.parent) {\n\t\t\tlist.push(item);\n\t\t} else {\n\t\t\tparent = toc[item.parent];\n\t\t\tparent.subitems.push(item);\n\t\t}\n\t}\n\n\treturn list;\n};\n\nParser.prototype.ncxItem = function(item, spineIndexByURL, bookSpine){\n\tvar id = item.getAttribute('id') || false,\n\t\t\t// content = item.querySelector(\"content\"),\n\t\t\tcontent = core.qs(item, \"content\"),\n\t\t\tsrc = content.getAttribute('src'),\n // navLabel = item.querySelector(\"navLabel\"),\n navLabel = core.qs(item, \"navLabel\"),\n\t\t\ttext = navLabel.textContent ? navLabel.textContent : \"\",\n\t\t\t// split = src.split(\"#\"),\n\t\t\t// baseUrl = split[0],\n\t\t\t// spinePos = spineIndexByURL[baseUrl],\n\t\t\t// spineItem = bookSpine[spinePos],\n\t\t\tsubitems = [],\n\t\t\tparentNode = item.parentNode,\n\t\t\tparent;\n\t\t\t// cfi = spineItem ? spineItem.cfi : '';\n\n\tif(parentNode && parentNode.nodeName === \"navPoint\") {\n\t\tparent = parentNode.getAttribute('id');\n\t}\n\n /*\n\tif(!id) {\n\t\tif(spinePos) {\n\t\t\tspineItem = bookSpine[spinePos];\n\t\t\tid = spineItem.id;\n\t\t\tcfi = spineItem.cfi;\n\t\t} else {\n\t\t\tid = 'epubjs-autogen-toc-id-' + EPUBJS.core.uuid();\n\t\t\titem.setAttribute('id', id);\n\t\t}\n\t}\n */\n\n\treturn {\n\t\t\"id\": id,\n\t\t\"href\": src,\n\t\t\"label\": text,\n\t\t\"subitems\" : subitems,\n\t\t\"parent\" : parent\n\t};\n};\n\nParser.prototype.pageList = function(navHtml, spineIndexByURL, bookSpine){\n\tvar navElement = this.querySelectorByType(navHtml, \"nav\", \"page-list\");\n // var navItems = navElement ? navElement.querySelectorAll(\"ol li\") : [];\n\tvar navItems = navElement ? core.qsa(navElement, \"li\") : [];\n\tvar length = navItems.length;\n\tvar i;\n\tvar toc = {};\n\tvar list = [];\n\tvar item;\n\n\tif(!navItems || length === 0) return list;\n\n\tfor (i = 0; i < length; ++i) {\n\t\titem = this.pageListItem(navItems[i], spineIndexByURL, bookSpine);\n\t\tlist.push(item);\n\t}\n\n\treturn list;\n};\n\nParser.prototype.pageListItem = function(item, spineIndexByURL, bookSpine){\n\tvar id = item.getAttribute('id') || false,\n\t\t// content = item.querySelector(\"a\"),\n content = core.qs(item, \"a\"),\n\t\thref = content.getAttribute('href') || '',\n\t\ttext = content.textContent || \"\",\n\t\tpage = parseInt(text),\n\t\tisCfi = href.indexOf(\"epubcfi\"),\n\t\tsplit,\n\t\tpackageUrl,\n\t\tcfi;\n\n\tif(isCfi != -1) {\n\t\tsplit = href.split(\"#\");\n\t\tpackageUrl = split[0];\n\t\tcfi = split.length > 1 ? split[1] : false;\n\t\treturn {\n\t\t\t\"cfi\" : cfi,\n\t\t\t\"href\" : href,\n\t\t\t\"packageUrl\" : packageUrl,\n\t\t\t\"page\" : page\n\t\t};\n\t} else {\n\t\treturn {\n\t\t\t\"href\" : href,\n\t\t\t\"page\" : page\n\t\t};\n\t}\n};\n\nmodule.exports = Parser;\n","var RSVP = require('rsvp');\nvar core = require('./core');\n\nfunction Queue(_context){\n this._q = [];\n this.context = _context;\n this.tick = core.requestAnimationFrame;\n this.running = false;\n this.paused = false;\n};\n\n// Add an item to the queue\nQueue.prototype.enqueue = function() {\n var deferred, promise;\n var queued;\n var task = [].shift.call(arguments);\n var args = arguments;\n\n // Handle single args without context\n // if(args && !Array.isArray(args)) {\n // args = [args];\n // }\n if(!task) {\n return console.error(\"No Task Provided\");\n }\n\n if(typeof task === \"function\"){\n\n deferred = new RSVP.defer();\n promise = deferred.promise;\n\n queued = {\n \"task\" : task,\n \"args\" : args,\n //\"context\" : context,\n \"deferred\" : deferred,\n \"promise\" : promise\n };\n\n } else {\n // Task is a promise\n queued = {\n \"promise\" : task\n };\n\n }\n\n this._q.push(queued);\n\n // Wait to start queue flush\n if (this.paused == false && !this.running) {\n // setTimeout(this.flush.bind(this), 0);\n // this.tick.call(window, this.run.bind(this));\n this.run();\n }\n\n return queued.promise;\n};\n\n// Run one item\nQueue.prototype.dequeue = function(){\n var inwait, task, result;\n\n if(this._q.length) {\n inwait = this._q.shift();\n task = inwait.task;\n if(task){\n // console.log(task)\n\n result = task.apply(this.context, inwait.args);\n\n if(result && typeof result[\"then\"] === \"function\") {\n // Task is a function that returns a promise\n return result.then(function(){\n inwait.deferred.resolve.apply(this.context, arguments);\n }.bind(this));\n } else {\n // Task resolves immediately\n inwait.deferred.resolve.apply(this.context, result);\n return inwait.promise;\n }\n\n\n\n } else if(inwait.promise) {\n // Task is a promise\n return inwait.promise;\n }\n\n } else {\n inwait = new RSVP.defer();\n inwait.deferred.resolve();\n return inwait.promise;\n }\n\n};\n\n// Run All Immediately\nQueue.prototype.dump = function(){\n while(this._q.length) {\n this.dequeue();\n }\n};\n\n// Run all sequentially, at convince\n\nQueue.prototype.run = function(){\n\n if(!this.running){\n this.running = true;\n this.defered = new RSVP.defer();\n }\n\n this.tick.call(window, function() {\n\n if(this._q.length) {\n\n this.dequeue()\n .then(function(){\n this.run();\n }.bind(this));\n\n } else {\n this.defered.resolve();\n this.running = undefined;\n }\n\n }.bind(this));\n\n // Unpause\n if(this.paused == true) {\n this.paused = false;\n }\n\n return this.defered.promise;\n};\n\n// Flush all, as quickly as possible\nQueue.prototype.flush = function(){\n\n if(this.running){\n return this.running;\n }\n\n if(this._q.length) {\n this.running = this.dequeue()\n .then(function(){\n this.running = undefined;\n return this.flush();\n }.bind(this));\n\n return this.running;\n }\n\n};\n\n// Clear all items in wait\nQueue.prototype.clear = function(){\n this._q = [];\n this.running = false;\n};\n\nQueue.prototype.length = function(){\n return this._q.length;\n};\n\nQueue.prototype.pause = function(){\n this.paused = true;\n};\n\n// Create a new task from a callback\nfunction Task(task, args, context){\n\n return function(){\n var toApply = arguments || [];\n\n return new RSVP.Promise(function(resolve, reject) {\n var callback = function(value){\n resolve(value);\n };\n // Add the callback to the arguments list\n toApply.push(callback);\n\n // Apply all arguments to the functions\n task.apply(this, toApply);\n\n }.bind(this));\n\n };\n\n};\n\nmodule.exports = Queue;\n","var RSVP = require('rsvp');\nvar URI = require('urijs');\nvar core = require('./core');\nvar replace = require('./replacements');\nvar Hook = require('./hook');\nvar EpubCFI = require('./epubcfi');\nvar Queue = require('./queue');\n// var View = require('./view');\nvar Views = require('./views');\nvar Layout = require('./layout');\nvar Mapping = require('./mapping');\n\nfunction Rendition(book, options) {\n\n\tthis.settings = core.extend(this.settings || {}, {\n\t\twidth: null,\n\t\theight: null,\n\t\tignoreClass: '',\n\t\tmanager: \"single\",\n\t\tview: \"iframe\",\n\t\tflow: null,\n\t\tlayout: null,\n\t\tspread: null,\n\t\tminSpreadWidth: 800, //-- overridden by spread: none (never) / both (always),\n\t\tuseBase64: true\n\t});\n\n\tcore.extend(this.settings, options);\n\n\tthis.viewSettings = {\n\t\tignoreClass: this.settings.ignoreClass\n\t};\n\n\tthis.book = book;\n\n\tthis.views = null;\n\n\t//-- Adds Hook methods to the Rendition prototype\n\tthis.hooks = {};\n\tthis.hooks.display = new Hook(this);\n\tthis.hooks.serialize = new Hook(this);\n\tthis.hooks.content = new Hook(this);\n\tthis.hooks.layout = new Hook(this);\n\tthis.hooks.render = new Hook(this);\n\tthis.hooks.show = new Hook(this);\n\n\tthis.hooks.content.register(replace.links.bind(this));\n\tthis.hooks.content.register(this.passViewEvents.bind(this));\n\n\t// this.hooks.display.register(this.afterDisplay.bind(this));\n\n this.epubcfi = new EpubCFI();\n\n\tthis.q = new Queue(this);\n\n\tthis.q.enqueue(this.book.opened);\n\n\t// Block the queue until rendering is started\n\t// this.starting = new RSVP.defer();\n\t// this.started = this.starting.promise;\n\tthis.q.enqueue(this.start);\n\n\tif(this.book.unarchived) {\n\t\tthis.q.enqueue(this.replacements.bind(this));\n\t}\n\n};\n\nRendition.prototype.setManager = function(manager) {\n\tthis.manager = manager;\n};\n\nRendition.prototype.requireManager = function(manager) {\n\tvar viewManager;\n\n\t// If manager is a string, try to load from register managers,\n\t// or require included managers directly\n\tif (typeof manager === \"string\") {\n\t\t// Use global or require\n\t\tviewManager = typeof ePub != \"undefined\" ? ePub.ViewManagers[manager] : undefined; //require('./managers/'+manager);\n\t} else {\n\t\t// otherwise, assume we were passed a function\n\t\tviewManager = manager\n\t}\n\n return viewManager;\n};\n\nRendition.prototype.requireView = function(view) {\n\tvar View;\n\n\tif (typeof view == \"string\") {\n\t\tView = typeof ePub != \"undefined\" ? ePub.Views[view] : undefined; //require('./views/'+view);\n\t} else {\n\t\t// otherwise, assume we were passed a function\n\t\tView = view\n\t}\n\n return View;\n};\n\nRendition.prototype.start = function(){\n\n\tif(!this.manager) {\n\t\tthis.ViewManager = this.requireManager(this.settings.manager);\n\t\tthis.View = this.requireView(this.settings.view);\n\n\t\tthis.manager = new this.ViewManager({\n\t\t\tview: this.View,\n\t\t\tqueue: this.q,\n\t\t\trequest: this.book.request,\n\t\t\tsettings: this.settings\n\t\t});\n\t}\n\n\t// Parse metadata to get layout props\n\tthis.settings.globalLayoutProperties = this.determineLayoutProperties(this.book.package.metadata);\n\n\tthis.flow(this.settings.globalLayoutProperties.flow);\n\n\tthis.layout(this.settings.globalLayoutProperties);\n\n\t// Listen for displayed views\n\tthis.manager.on(\"added\", this.afterDisplayed.bind(this));\n\n\t// Listen for resizing\n\tthis.manager.on(\"resized\", this.onResized.bind(this));\n\n\t// Listen for scroll changes\n\tthis.manager.on(\"scroll\", this.reportLocation.bind(this));\n\n\n\tthis.on('displayed', this.reportLocation.bind(this));\n\n\t// Trigger that rendering has started\n\tthis.trigger(\"started\");\n\n\t// Start processing queue\n\t// this.starting.resolve();\n};\n\n// Call to attach the container to an element in the dom\n// Container must be attached before rendering can begin\nRendition.prototype.attachTo = function(element){\n\n\treturn this.q.enqueue(function () {\n\n\t\t// Start rendering\n\t\tthis.manager.render(element, {\n\t\t\t\"width\" : this.settings.width,\n\t\t\t\"height\" : this.settings.height\n\t\t});\n\n\t\t// Trigger Attached\n\t\tthis.trigger(\"attached\");\n\n\t}.bind(this));\n\n};\n\nRendition.prototype.display = function(target){\n\n\t// if (!this.book.spine.spineItems.length > 0) {\n\t\t// Book isn't open yet\n\t\t// return this.q.enqueue(this.display, target);\n\t// }\n\n\treturn this.q.enqueue(this._display, target);\n\n};\n\nRendition.prototype._display = function(target){\n\tvar isCfiString = this.epubcfi.isCfiString(target);\n\tvar displaying = new RSVP.defer();\n\tvar displayed = displaying.promise;\n\tvar section;\n\tvar moveTo;\n\n\tsection = this.book.spine.get(target);\n\n\tif(!section){\n\t\tdisplaying.reject(new Error(\"No Section Found\"));\n\t\treturn displayed;\n\t}\n\n\t// Trim the target fragment\n\t// removing the chapter\n\tif(!isCfiString && typeof target === \"string\" &&\n\t\ttarget.indexOf(\"#\") > -1) {\n\t\t\tmoveTo = target.substring(target.indexOf(\"#\")+1);\n\t}\n\n\tif (isCfiString) {\n\t\tmoveTo = target;\n\t}\n\n\treturn this.manager.display(section, moveTo)\n\t\t.then(function(){\n\t\t\tthis.trigger(\"displayed\", section);\n\t\t}.bind(this));\n\n};\n\n/*\nRendition.prototype.render = function(view, show) {\n\n\t// view.onLayout = this.layout.format.bind(this.layout);\n\tview.create();\n\n\t// Fit to size of the container, apply padding\n\tthis.manager.resizeView(view);\n\n\t// Render Chain\n\treturn view.section.render(this.book.request)\n\t\t.then(function(contents){\n\t\t\treturn view.load(contents);\n\t\t}.bind(this))\n\t\t.then(function(doc){\n\t\t\treturn this.hooks.content.trigger(view, this);\n\t\t}.bind(this))\n\t\t.then(function(){\n\t\t\tthis.layout.format(view.contents);\n\t\t\treturn this.hooks.layout.trigger(view, this);\n\t\t}.bind(this))\n\t\t.then(function(){\n\t\t\treturn view.display();\n\t\t}.bind(this))\n\t\t.then(function(){\n\t\t\treturn this.hooks.render.trigger(view, this);\n\t\t}.bind(this))\n\t\t.then(function(){\n\t\t\tif(show !== false) {\n\t\t\t\tthis.q.enqueue(function(view){\n\t\t\t\t\tview.show();\n\t\t\t\t}, view);\n\t\t\t}\n\t\t\t// this.map = new Map(view, this.layout);\n\t\t\tthis.hooks.show.trigger(view, this);\n\t\t\tthis.trigger(\"rendered\", view.section);\n\n\t\t}.bind(this))\n\t\t.catch(function(e){\n\t\t\tthis.trigger(\"loaderror\", e);\n\t\t}.bind(this));\n\n};\n*/\n\nRendition.prototype.afterDisplayed = function(view){\n\tthis.hooks.content.trigger(view, this);\n\tthis.trigger(\"rendered\", view.section);\n\tthis.reportLocation();\n};\n\nRendition.prototype.onResized = function(size){\n\n\tif(this.location) {\n\t\tthis.display(this.location.start);\n\t}\n\n\tthis.trigger(\"resized\", {\n\t\twidth: size.width,\n\t\theight: size.height\n\t});\n\n};\n\nRendition.prototype.moveTo = function(offset){\n\tthis.manager.moveTo(offset);\n};\n\nRendition.prototype.next = function(){\n\treturn this.q.enqueue(this.manager.next.bind(this.manager))\n\t\t.then(this.reportLocation.bind(this));\n};\n\nRendition.prototype.prev = function(){\n\treturn this.q.enqueue(this.manager.prev.bind(this.manager))\n\t\t.then(this.reportLocation.bind(this));\n};\n\n//-- http://www.idpf.org/epub/301/spec/epub-publications.html#meta-properties-rendering\nRendition.prototype.determineLayoutProperties = function(metadata){\n\tvar settings;\n\tvar layout = this.settings.layout || metadata.layout || \"reflowable\";\n\tvar spread = this.settings.spread || metadata.spread || \"auto\";\n\tvar orientation = this.settings.orientation || metadata.orientation || \"auto\";\n\tvar flow = this.settings.flow || metadata.flow || \"auto\";\n\tvar viewport = metadata.viewport || \"\";\n\tvar minSpreadWidth = this.settings.minSpreadWidth || metadata.minSpreadWidth || 800;\n\n\tif (this.settings.width >= 0 && this.settings.height >= 0) {\n\t\tviewport = \"width=\"+this.settings.width+\", height=\"+this.settings.height+\"\";\n\t}\n\n\tsettings = {\n\t\tlayout : layout,\n\t\tspread : spread,\n\t\torientation : orientation,\n\t\tflow : flow,\n\t\tviewport : viewport,\n\t\tminSpreadWidth : minSpreadWidth\n\t};\n\n\treturn settings;\n};\n\n// Rendition.prototype.applyLayoutProperties = function(){\n// \tvar settings = this.determineLayoutProperties(this.book.package.metadata);\n//\n// \tthis.flow(settings.flow);\n//\n// \tthis.layout(settings);\n// };\n\n// paginated | scrolled\n// (scrolled-continuous vs scrolled-doc are handled by different view managers)\nRendition.prototype.flow = function(_flow){\n\tvar flow;\n\tif (_flow === \"scrolled-doc\" || _flow === \"scrolled-continuous\") {\n\t\tflow = \"scrolled\";\n\t}\n\n\tif (_flow === \"auto\" || _flow === \"paginated\") {\n\t\tflow = \"paginated\";\n\t}\n\n\tif (this._layout) {\n\t\tthis._layout.flow(flow);\n\t}\n\n\tif (this.manager) {\n\t\tthis.manager.updateFlow(flow);\n\t}\n};\n\n// reflowable | pre-paginated\nRendition.prototype.layout = function(settings){\n\tif (settings) {\n\t\tthis._layout = new Layout(settings);\n\t\tthis._layout.spread(settings.spread, this.settings.minSpreadWidth);\n\n\t\tthis.mapping = new Mapping(this._layout);\n\t}\n\n\tif (this.manager && this._layout) {\n\t\tthis.manager.applyLayout(this._layout);\n\t}\n\n\treturn this._layout;\n};\n\n// none | auto (TODO: implement landscape, portrait, both)\nRendition.prototype.spread = function(spread, min){\n\n\tthis._layout.spread(spread, min);\n\n\tif (this.manager.isRendered()) {\n\t\tthis.manager.updateLayout();\n\t}\n};\n\n\nRendition.prototype.reportLocation = function(){\n return this.q.enqueue(function(){\n var location = this.manager.currentLocation();\n\t\tif (location && location.then && typeof location.then === 'function') {\n\t\t\tlocation.then(function(result) {\n\t\t\t\tthis.location = result;\n\t\t this.trigger(\"locationChanged\", this.location);\n\t\t\t}.bind(this));\n\t\t} else if (location) {\n\t\t\tthis.location = location;\n\t this.trigger(\"locationChanged\", this.location);\n\t\t}\n\n }.bind(this));\n};\n\n\nRendition.prototype.destroy = function(){\n // Clear the queue\n\tthis.q.clear();\n\n\tthis.views.clear();\n\n\tclearTimeout(this.trimTimeout);\n\tif(this.settings.hidden) {\n\t\tthis.element.removeChild(this.wrapper);\n\t} else {\n\t\tthis.element.removeChild(this.container);\n\t}\n\n};\n\nRendition.prototype.passViewEvents = function(view){\n view.contents.listenedEvents.forEach(function(e){\n\t\tview.on(e, this.triggerViewEvent.bind(this));\n\t}.bind(this));\n\n\tview.on(\"selected\", this.triggerSelectedEvent.bind(this));\n};\n\nRendition.prototype.triggerViewEvent = function(e){\n this.trigger(e.type, e);\n};\n\nRendition.prototype.triggerSelectedEvent = function(cfirange){\n this.trigger(\"selected\", cfirange);\n};\n\nRendition.prototype.replacements = function(){\n\t// Wait for loading\n\t// return this.q.enqueue(function () {\n\t\t// Get thes books manifest\n\t\tvar manifest = this.book.package.manifest;\n\t var manifestArray = Object.keys(manifest).\n\t map(function (key){\n\t return manifest[key];\n\t });\n\n\t // Exclude HTML\n\t var items = manifestArray.\n\t filter(function (item){\n\t if (item.type != \"application/xhtml+xml\" &&\n\t item.type != \"text/html\") {\n\t return true;\n\t }\n\t });\n\n\t // Only CSS\n\t var css = items.\n\t filter(function (item){\n\t if (item.type === \"text/css\") {\n\t return true;\n\t }\n\t });\n\n\t\t// Css Urls\n\t\tvar cssUrls = css.map(function(item) {\n\t\t\treturn item.href;\n\t\t});\n\n\t\t// All Assets Urls\n\t var urls = items.\n\t map(function(item) {\n\t return item.href;\n\t }.bind(this));\n\n\t\t// Create blob urls for all the assets\n\t var processing = urls.\n\t map(function(url) {\n\t\t\t\tvar absolute = URI(url).absoluteTo(this.book.baseUrl).toString();\n\t\t\t\t// Full url from archive base\n\t return this.book.unarchived.createUrl(absolute, {\"base64\": this.settings.useBase64});\n\t }.bind(this));\n\n\t\tvar replacementUrls;\n\n\t\t// After all the urls are created\n\t\treturn RSVP.all(processing)\n\t\t\t.then(function(_replacementUrls) {\n\t\t\t\tvar replaced = [];\n\n\t\t\t\treplacementUrls = _replacementUrls;\n\n\t\t\t\t// Replace Asset Urls in the text of all css files\n\t\t\t\tcssUrls.forEach(function(href) {\n\t\t\t\t\treplaced.push(this.replaceCss(href, urls, replacementUrls));\n\t\t }.bind(this));\n\n\t\t\t\treturn RSVP.all(replaced);\n\n\t }.bind(this))\n\t\t\t.then(function () {\n\t\t\t\t// Replace Asset Urls in chapters\n\t\t\t\t// by registering a hook after the sections contents has been serialized\n\t\t\t\tthis.book.spine.hooks.serialize.register(function(output, section) {\n\n\t\t\t\t\tthis.replaceAssets(section, urls, replacementUrls);\n\n\t\t\t\t}.bind(this));\n\n\t\t\t}.bind(this))\n\t\t\t.catch(function(reason){\n\t console.error(reason);\n\t });\n\t// }.bind(this));\n};\n\nRendition.prototype.replaceCss = function(href, urls, replacementUrls){\n\t\tvar newUrl;\n\t\tvar indexInUrls;\n\n\t\t// Find the absolute url of the css file\n\t\tvar fileUri = URI(href);\n\t\tvar absolute = fileUri.absoluteTo(this.book.baseUrl).toString();\n\t\t// Get the text of the css file from the archive\n\t\tvar textResponse = this.book.unarchived.getText(absolute);\n\t\t// Get asset links relative to css file\n\t\tvar relUrls = urls.\n\t\t\tmap(function(assetHref) {\n\t\t\t\tvar assetUri = URI(assetHref).absoluteTo(this.book.baseUrl);\n\t\t\t\tvar relative = assetUri.relativeTo(absolute).toString();\n\t\t\t\treturn relative;\n\t\t\t}.bind(this));\n\n\t\treturn textResponse.then(function (text) {\n\t\t\t// Replacements in the css text\n\t\t\ttext = replace.substitute(text, relUrls, replacementUrls);\n\n\t\t\t// Get the new url\n\t\t\tif (this.settings.useBase64) {\n\t\t\t\tnewUrl = core.createBase64Url(text, 'text/css');\n\t\t\t} else {\n\t\t\t\tnewUrl = core.createBlobUrl(text, 'text/css');\n\t\t\t}\n\n\t\t\t// switch the url in the replacementUrls\n\t\t\tindexInUrls = urls.indexOf(href);\n\t\t\tif (indexInUrls > -1) {\n\t\t\t\treplacementUrls[indexInUrls] = newUrl;\n\t\t\t}\n\n\t\t\treturn new RSVP.Promise(function(resolve, reject){\n\t\t\t\tresolve(urls, replacementUrls);\n\t\t\t});\n\n\t\t}.bind(this));\n\n};\n\nRendition.prototype.replaceAssets = function(section, urls, replacementUrls){\n\tvar fileUri = URI(section.url);\n\t// Get Urls relative to current sections\n\tvar relUrls = urls.\n\t\tmap(function(href) {\n\t\t\tvar assetUri = URI(href).absoluteTo(this.book.baseUrl);\n\t\t\tvar relative = assetUri.relativeTo(fileUri).toString();\n\t\t\treturn relative;\n\t\t}.bind(this));\n\n\n\tsection.output = replace.substitute(section.output, relUrls, replacementUrls);\n};\n\nRendition.prototype.range = function(_cfi, ignoreClass){\n var cfi = new EpubCFI(_cfi);\n var found = this.visible().filter(function (view) {\n\t\tif(cfi.spinePos === view.index) return true;\n\t});\n\n\t// Should only every return 1 item\n if (found.length) {\n return found[0].range(cfi, ignoreClass);\n }\n};\n\nRendition.prototype.adjustImages = function(view) {\n\n view.addStylesheetRules([\n [\"img\",\n [\"max-width\", (view.layout.spreadWidth) + \"px\"],\n [\"max-height\", (view.layout.height) + \"px\"]\n ]\n ]);\n return new RSVP.Promise(function(resolve, reject){\n // Wait to apply\n setTimeout(function() {\n resolve();\n }, 1);\n });\n};\n\n//-- Enable binding events to Renderer\nRSVP.EventTarget.mixin(Rendition.prototype);\n\nmodule.exports = Rendition;\n","var URI = require('urijs');\nvar core = require('./core');\n\nfunction base(doc, section){\n var base;\n var head;\n\n if(!doc){\n return;\n }\n\n // head = doc.querySelector(\"head\");\n // base = head.querySelector(\"base\");\n head = core.qs(doc, \"head\");\n base = core.qs(head, \"base\");\n\n if(!base) {\n base = doc.createElement(\"base\");\n head.insertBefore(base, head.firstChild);\n }\n\n base.setAttribute(\"href\", section.url);\n}\n\nfunction canonical(doc, section){\n var head;\n var link;\n var url = section.url; // window.location.origin + window.location.pathname + \"?loc=\" + encodeURIComponent(section.url);\n\n if(!doc){\n return;\n }\n\n head = core.qs(doc, \"head\");\n link = core.qs(head, \"link[rel='canonical']\");\n\n if (link) {\n link.setAttribute(\"href\", url);\n } else {\n link = doc.createElement(\"link\");\n link.setAttribute(\"rel\", \"canonical\");\n link.setAttribute(\"href\", url);\n head.appendChild(link);\n }\n}\n\nfunction links(view, renderer) {\n\n var links = view.document.querySelectorAll(\"a[href]\");\n var replaceLinks = function(link){\n var href = link.getAttribute(\"href\");\n\n if(href.indexOf(\"mailto:\") === 0){\n return;\n }\n\n var linkUri = URI(href);\n var absolute = linkUri.absoluteTo(view.section.url);\n var relative = absolute.relativeTo(this.book.baseUrl).toString();\n\n if(linkUri.protocol()){\n\n link.setAttribute(\"target\", \"_blank\");\n\n }else{\n /*\n if(baseDirectory) {\n\t\t\t\t// We must ensure that the file:// protocol is preserved for\n\t\t\t\t// local file links, as in certain contexts (such as under\n\t\t\t\t// Titanium), file links without the file:// protocol will not\n\t\t\t\t// work\n\t\t\t\tif (baseUri.protocol === \"file\") {\n\t\t\t\t\trelative = core.resolveUrl(baseUri.base, href);\n\t\t\t\t} else {\n\t\t\t\t\trelative = core.resolveUrl(baseDirectory, href);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\trelative = href;\n\t\t\t}\n */\n\n if(linkUri.fragment()) {\n // do nothing with fragment yet\n } else {\n link.onclick = function(){\n renderer.display(relative);\n return false;\n };\n }\n\n }\n }.bind(this);\n\n for (var i = 0; i < links.length; i++) {\n replaceLinks(links[i]);\n }\n\n\n};\n\nfunction substitute(content, urls, replacements) {\n urls.forEach(function(url, i){\n if (url && replacements[i]) {\n content = content.replace(new RegExp(url, 'g'), replacements[i]);\n }\n });\n return content;\n}\nmodule.exports = {\n 'base': base,\n 'canonical' : canonical,\n 'links': links,\n 'substitute': substitute\n};\n","var RSVP = require('rsvp');\nvar URI = require('urijs');\nvar core = require('./core');\n\nfunction request(url, type, withCredentials, headers) {\n var supportsURL = (typeof window != \"undefined\") ? window.URL : false; // TODO: fallback for url if window isn't defined\n var BLOB_RESPONSE = supportsURL ? \"blob\" : \"arraybuffer\";\n var uri;\n\n var deferred = new RSVP.defer();\n\n var xhr = new XMLHttpRequest();\n\n //-- Check from PDF.js:\n // https://github.com/mozilla/pdf.js/blob/master/web/compatibility.js\n var xhrPrototype = XMLHttpRequest.prototype;\n\n var header;\n\n if (!('overrideMimeType' in xhrPrototype)) {\n // IE10 might have response, but not overrideMimeType\n Object.defineProperty(xhrPrototype, 'overrideMimeType', {\n value: function xmlHttpRequestOverrideMimeType(mimeType) {}\n });\n }\n if(withCredentials) {\n xhr.withCredentials = true;\n }\n\n xhr.onreadystatechange = handler;\n xhr.onerror = err;\n\n xhr.open(\"GET\", url, true);\n\n for(header in headers) {\n xhr.setRequestHeader(header, headers[header]);\n }\n\n if(type == \"json\") {\n xhr.setRequestHeader(\"Accept\", \"application/json\");\n }\n\n // If type isn't set, determine it from the file extension\n\tif(!type) {\n\t\turi = URI(url);\n\t\ttype = uri.suffix();\n\t}\n\n if(type == 'blob'){\n xhr.responseType = BLOB_RESPONSE;\n }\n\n\n if(core.isXml(type)) {\n\t\t// xhr.responseType = \"document\";\n\t\txhr.overrideMimeType('text/xml'); // for OPF parsing\n\t}\n\n\tif(type == 'xhtml') {\n\t\t// xhr.responseType = \"document\";\n\t}\n\n\tif(type == 'html' || type == 'htm') {\n\t\t// xhr.responseType = \"document\";\n \t}\n\n if(type == \"binary\") {\n xhr.responseType = \"arraybuffer\";\n }\n\n xhr.send();\n\n function err(e) {\n console.error(e);\n deferred.reject(e);\n }\n\n function handler() {\n if (this.readyState === XMLHttpRequest.DONE) {\n\n if (this.status === 200 || this.responseXML ) { //-- Firefox is reporting 0 for blob urls\n var r;\n\n if (!this.response && !this.responseXML) {\n deferred.reject({\n status: this.status,\n message : \"Empty Response\",\n stack : new Error().stack\n });\n return deferred.promise;\n }\n\n if (this.status === 403) {\n deferred.reject({\n status: this.status,\n response: this.response,\n message : \"Forbidden\",\n stack : new Error().stack\n });\n return deferred.promise;\n }\n\n if((this.responseType == '' || this.responseType == 'document')\n && this.responseXML){\n r = this.responseXML;\n } else\n if(core.isXml(type)){\n // xhr.overrideMimeType('text/xml'); // for OPF parsing\n // If this.responseXML wasn't set, try to parse using a DOMParser from text\n r = core.parse(this.response, \"text/xml\");\n }else\n if(type == 'xhtml'){\n r = core.parse(this.response, \"application/xhtml+xml\");\n }else\n if(type == 'html' || type == 'htm'){\n r = core.parse(this.response, \"text/html\");\n }else\n if(type == 'json'){\n r = JSON.parse(this.response);\n }else\n if(type == 'blob'){\n\n if(supportsURL) {\n r = this.response;\n } else {\n //-- Safari doesn't support responseType blob, so create a blob from arraybuffer\n r = new Blob([this.response]);\n }\n\n }else{\n r = this.response;\n }\n\n deferred.resolve(r);\n } else {\n\n deferred.reject({\n status: this.status,\n message : this.response,\n stack : new Error().stack\n });\n\n }\n }\n }\n\n return deferred.promise;\n};\n\nmodule.exports = request;\n","var RSVP = require('rsvp');\nvar URI = require('urijs');\nvar core = require('./core');\nvar EpubCFI = require('./epubcfi');\nvar Hook = require('./hook');\n\nfunction Section(item, hooks){\n this.idref = item.idref;\n this.linear = item.linear;\n this.properties = item.properties;\n this.index = item.index;\n this.href = item.href;\n this.url = item.url;\n this.next = item.next;\n this.prev = item.prev;\n\n this.cfiBase = item.cfiBase;\n\n if (hooks) {\n this.hooks = hooks;\n } else {\n this.hooks = {};\n this.hooks.serialize = new Hook(this);\n this.hooks.content = new Hook(this);\n }\n\n};\n\n\nSection.prototype.load = function(_request){\n var request = _request || this.request || require('./request');\n var loading = new RSVP.defer();\n var loaded = loading.promise;\n\n if(this.contents) {\n loading.resolve(this.contents);\n } else {\n request(this.url)\n .then(function(xml){\n var base;\n var directory = URI(this.url).directory();\n\n this.document = xml;\n this.contents = xml.documentElement;\n\n return this.hooks.content.trigger(this.document, this);\n }.bind(this))\n .then(function(){\n loading.resolve(this.contents);\n }.bind(this))\n .catch(function(error){\n loading.reject(error);\n });\n }\n\n return loaded;\n};\n\nSection.prototype.base = function(_document){\n var task = new RSVP.defer();\n var base = _document.createElement(\"base\"); // TODO: check if exists\n var head;\n console.log(window.location.origin + \"/\" +this.url);\n\n base.setAttribute(\"href\", window.location.origin + \"/\" +this.url);\n\n if(_document) {\n head = _document.querySelector(\"head\");\n }\n if(head) {\n head.insertBefore(base, head.firstChild);\n task.resolve();\n } else {\n task.reject(new Error(\"No head to insert into\"));\n }\n\n\n return task.promise;\n};\n\nSection.prototype.beforeSectionLoad = function(){\n // Stub for a hook - replace me for now\n};\n\nSection.prototype.render = function(_request){\n var rendering = new RSVP.defer();\n var rendered = rendering.promise;\n this.output; // TODO: better way to return this from hooks?\n\n this.load(_request).\n then(function(contents){\n var serializer;\n\n if (typeof XMLSerializer === \"undefined\") {\n XMLSerializer = require('xmldom').XMLSerializer;\n }\n serializer = new XMLSerializer();\n this.output = serializer.serializeToString(contents);\n return this.output;\n }.bind(this)).\n then(function(){\n return this.hooks.serialize.trigger(this.output, this);\n }.bind(this)).\n then(function(){\n rendering.resolve(this.output);\n }.bind(this))\n .catch(function(error){\n rendering.reject(error);\n });\n\n return rendered;\n};\n\nSection.prototype.find = function(_query){\n\n};\n\n/**\n* Reconciles the current chapters layout properies with\n* the global layout properities.\n* Takes: global layout settings object, chapter properties string\n* Returns: Object with layout properties\n*/\nSection.prototype.reconcileLayoutSettings = function(global){\n //-- Get the global defaults\n var settings = {\n layout : global.layout,\n spread : global.spread,\n orientation : global.orientation\n };\n\n //-- Get the chapter's display type\n this.properties.forEach(function(prop){\n var rendition = prop.replace(\"rendition:\", '');\n var split = rendition.indexOf(\"-\");\n var property, value;\n\n if(split != -1){\n property = rendition.slice(0, split);\n value = rendition.slice(split+1);\n\n settings[property] = value;\n }\n });\n return settings;\n};\n\nSection.prototype.cfiFromRange = function(_range) {\n return new EpubCFI(_range, this.cfiBase).toString();\n};\n\nSection.prototype.cfiFromElement = function(el) {\n return new EpubCFI(el, this.cfiBase).toString();\n};\n\nmodule.exports = Section;\n","var RSVP = require('rsvp');\nvar core = require('./core');\nvar EpubCFI = require('./epubcfi');\nvar Hook = require('./hook');\nvar Section = require('./section');\nvar replacements = require('./replacements');\n\nfunction Spine(_request){\n this.request = _request;\n this.spineItems = [];\n this.spineByHref = {};\n this.spineById = {};\n\n this.hooks = {};\n this.hooks.serialize = new Hook();\n this.hooks.content = new Hook();\n\n // Register replacements\n this.hooks.content.register(replacements.base);\n this.hooks.content.register(replacements.canonical);\n\n this.epubcfi = new EpubCFI();\n\n this.loaded = false;\n};\n\nSpine.prototype.load = function(_package) {\n\n this.items = _package.spine;\n this.manifest = _package.manifest;\n this.spineNodeIndex = _package.spineNodeIndex;\n this.baseUrl = _package.baseUrl || '';\n this.length = this.items.length;\n\n this.items.forEach(function(item, index){\n var href, url;\n var manifestItem = this.manifest[item.idref];\n var spineItem;\n\n item.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.idref);\n\n if(manifestItem) {\n item.href = manifestItem.href;\n item.url = this.baseUrl + item.href;\n\n if(manifestItem.properties.length){\n item.properties.push.apply(item.properties, manifestItem.properties);\n }\n }\n\n // if(index > 0) {\n item.prev = function(){ return this.get(index-1); }.bind(this);\n // }\n\n // if(index+1 < this.items.length) {\n item.next = function(){ return this.get(index+1); }.bind(this);\n // }\n\n spineItem = new Section(item, this.hooks);\n\n this.append(spineItem);\n\n\n }.bind(this));\n\n this.loaded = true;\n};\n\n// book.spine.get();\n// book.spine.get(1);\n// book.spine.get(\"chap1.html\");\n// book.spine.get(\"#id1234\");\nSpine.prototype.get = function(target) {\n var index = 0;\n\n if(this.epubcfi.isCfiString(target)) {\n cfi = new EpubCFI(target);\n index = cfi.spinePos;\n } else if(target && (typeof target === \"number\" || isNaN(target) === false)){\n index = target;\n } else if(target && target.indexOf(\"#\") === 0) {\n index = this.spineById[target.substring(1)];\n } else if(target) {\n // Remove fragments\n target = target.split(\"#\")[0];\n index = this.spineByHref[target];\n }\n\n return this.spineItems[index] || null;\n};\n\nSpine.prototype.append = function(section) {\n var index = this.spineItems.length;\n section.index = index;\n\n this.spineItems.push(section);\n\n this.spineByHref[section.href] = index;\n this.spineById[section.idref] = index;\n\n return index;\n};\n\nSpine.prototype.prepend = function(section) {\n var index = this.spineItems.unshift(section);\n this.spineByHref[section.href] = 0;\n this.spineById[section.idref] = 0;\n\n // Re-index\n this.spineItems.forEach(function(item, index){\n item.index = index;\n });\n\n return 0;\n};\n\nSpine.prototype.insert = function(section, index) {\n\n};\n\nSpine.prototype.remove = function(section) {\n var index = this.spineItems.indexOf(section);\n\n if(index > -1) {\n delete this.spineByHref[section.href];\n delete this.spineById[section.idref];\n\n return this.spineItems.splice(index, 1);\n }\n};\n\nSpine.prototype.each = function() {\n\treturn this.spineItems.forEach.apply(this.spineItems, arguments);\n};\n\nmodule.exports = Spine;\n","var core = require('./core');\n\nfunction Stage(_options) {\n\tthis.settings = _options || {};\n\tthis.id = \"epubjs-container-\" + core.uuid();\n\n\tthis.container = this.create(this.settings);\n\n\tif(this.settings.hidden) {\n\t\tthis.wrapper = this.wrap(this.container);\n\t}\n\n}\n\n/**\n* Creates an element to render to.\n* Resizes to passed width and height or to the elements size\n*/\nStage.prototype.create = function(options){\n\tvar height = options.height;// !== false ? options.height : \"100%\";\n\tvar width = options.width;// !== false ? options.width : \"100%\";\n\tvar overflow = options.overflow || false;\n \tvar axis = options.axis || \"vertical\";\n\n\tif(options.height && core.isNumber(options.height)) {\n\t\theight = options.height + \"px\";\n\t}\n\n\tif(options.width && core.isNumber(options.width)) {\n\t\twidth = options.width + \"px\";\n\t}\n\n\t// Create new container element\n\tcontainer = document.createElement(\"div\");\n\n\tcontainer.id = this.id;\n\tcontainer.classList.add(\"epub-container\");\n\n\t// Style Element\n\t// container.style.fontSize = \"0\";\n\tcontainer.style.wordSpacing = \"0\";\n\tcontainer.style.lineHeight = \"0\";\n\tcontainer.style.verticalAlign = \"top\";\n\n\tif(axis === \"horizontal\") {\n\t\tcontainer.style.whiteSpace = \"nowrap\";\n\t}\n\n\tif(width){\n\t\tcontainer.style.width = width;\n\t}\n\n\tif(height){\n\t\tcontainer.style.height = height;\n\t}\n\n\tif (overflow) {\n\t\tcontainer.style.overflow = overflow;\n\t}\n\n\treturn container;\n};\n\nStage.wrap = function(container) {\n\tvar wrapper = document.createElement(\"div\");\n\n\twrapper.style.visibility = \"hidden\";\n\twrapper.style.overflow = \"hidden\";\n\twrapper.style.width = \"0\";\n\twrapper.style.height = \"0\";\n\n\twrapper.appendChild(container);\n\treturn wrapper;\n};\n\n\nStage.prototype.getElement = function(_element){\n\tvar element;\n\n\tif(core.isElement(_element)) {\n\t\telement = _element;\n\t} else if (typeof _element === \"string\") {\n\t\telement = document.getElementById(_element);\n\t}\n\n\tif(!element){\n\t\tconsole.error(\"Not an Element\");\n\t\treturn;\n\t}\n\n\treturn element;\n};\n\nStage.prototype.attachTo = function(what){\n\n\tvar element = this.getElement(what);\n\tvar base;\n\n\tif(!element){\n\t\treturn;\n\t}\n\n\tif(this.settings.hidden) {\n\t\tbase = this.wrapper;\n\t} else {\n\t\tbase = this.container;\n\t}\n\n\telement.appendChild(base);\n\n\tthis.element = element;\n\n\treturn element;\n\n};\n\nStage.prototype.getContainer = function() {\n\treturn this.container;\n};\n\nStage.prototype.onResize = function(func){\n\t// Only listen to window for resize event if width and height are not fixed.\n\t// This applies if it is set to a percent or auto.\n\tif(!core.isNumber(this.settings.width) ||\n\t\t !core.isNumber(this.settings.height) ) {\n\t\twindow.addEventListener(\"resize\", func, false);\n\t}\n\n};\n\nStage.prototype.size = function(width, height){\n\tvar bounds;\n\t// var width = _width || this.settings.width;\n\t// var height = _height || this.settings.height;\n\n\t// If width or height are set to false, inherit them from containing element\n\tif(width === null) {\n\t\tbounds = this.element.getBoundingClientRect();\n\n\t\tif(bounds.width) {\n\t\t\twidth = bounds.width;\n\t\t\tthis.container.style.width = bounds.width + \"px\";\n\t\t}\n\t}\n\n\tif(height === null) {\n\t\tbounds = bounds || this.element.getBoundingClientRect();\n\n\t\tif(bounds.height) {\n\t\t\theight = bounds.height;\n\t\t\tthis.container.style.height = bounds.height + \"px\";\n\t\t}\n\n\t}\n\n\tif(!core.isNumber(width)) {\n\t\tbounds = this.container.getBoundingClientRect();\n\t\twidth = bounds.width;\n\t\t//height = bounds.height;\n\t}\n\n\tif(!core.isNumber(height)) {\n\t\tbounds = bounds || this.container.getBoundingClientRect();\n\t\t//width = bounds.width;\n\t\theight = bounds.height;\n\t}\n\n\n\tthis.containerStyles = window.getComputedStyle(this.container);\n\n\tthis.containerPadding = {\n\t\tleft: parseFloat(this.containerStyles[\"padding-left\"]) || 0,\n\t\tright: parseFloat(this.containerStyles[\"padding-right\"]) || 0,\n\t\ttop: parseFloat(this.containerStyles[\"padding-top\"]) || 0,\n\t\tbottom: parseFloat(this.containerStyles[\"padding-bottom\"]) || 0\n\t};\n\n\treturn {\n\t\twidth: width -\n\t\t\t\t\t\tthis.containerPadding.left -\n\t\t\t\t\t\tthis.containerPadding.right,\n\t\theight: height -\n\t\t\t\t\t\tthis.containerPadding.top -\n\t\t\t\t\t\tthis.containerPadding.bottom\n\t};\n\n};\n\nStage.prototype.bounds = function(){\n\n\tif(!this.container) {\n\t\treturn core.windowBounds();\n\t} else {\n\t\treturn this.container.getBoundingClientRect();\n\t}\n\n}\n\nStage.prototype.getSheet = function(){\n\tvar style = document.createElement(\"style\");\n\n\t// WebKit hack --> https://davidwalsh.name/add-rules-stylesheets\n\tstyle.appendChild(document.createTextNode(\"\"));\n\n\tdocument.head.appendChild(style);\n\n\treturn style.sheet;\n}\n\nStage.prototype.addStyleRules = function(selector, rulesArray){\n\tvar scope = \"#\" + this.id + \" \";\n\tvar rules = \"\";\n\n\tif(!this.sheet){\n\t\tthis.sheet = this.getSheet();\n\t}\n\n\trulesArray.forEach(function(set) {\n\t\tfor (var prop in set) {\n\t\t\tif(set.hasOwnProperty(prop)) {\n\t\t\t\trules += prop + \":\" + set[prop] + \";\";\n\t\t\t}\n\t\t}\n\t})\n\n this.sheet.insertRule(scope + selector + \" {\" + rules + \"}\", 0);\n}\n\n\n\nmodule.exports = Stage;\n","var RSVP = require('rsvp');\nvar URI = require('urijs');\nvar core = require('./core');\nvar request = require('./request');\nvar mime = require('../libs/mime/mime');\n\nfunction Unarchive() {\n\n this.checkRequirements();\n this.urlCache = {};\n\n}\n\nUnarchive.prototype.checkRequirements = function(callback){\n try {\n if (typeof JSZip !== 'undefined') {\n this.zip = new JSZip();\n } else {\n JSZip = require('jszip');\n this.zip = new JSZip();\n }\n } catch (e) {\n console.error(\"JSZip lib not loaded\");\n }\n};\n\nUnarchive.prototype.open = function(zipUrl, isBase64){\n\tif (zipUrl instanceof ArrayBuffer || isBase64) {\n return this.zip.loadAsync(zipUrl, {\"base64\": isBase64});\n\t} else {\n\t\treturn request(zipUrl, \"binary\")\n .then(function(data){\n return this.zip.loadAsync(data);\n\t\t }.bind(this));\n\t}\n};\n\nUnarchive.prototype.request = function(url, type){\n var deferred = new RSVP.defer();\n var response;\n var r;\n\n // If type isn't set, determine it from the file extension\n\tif(!type) {\n\t\turi = URI(url);\n\t\ttype = uri.suffix();\n\t}\n\n if(type == 'blob'){\n response = this.getBlob(url);\n } else {\n response = this.getText(url);\n }\n\n if (response) {\n response.then(function (r) {\n result = this.handleResponse(r, type);\n deferred.resolve(result);\n }.bind(this));\n } else {\n deferred.reject({\n message : \"File not found in the epub: \" + url,\n stack : new Error().stack\n });\n }\n return deferred.promise;\n};\n\nUnarchive.prototype.handleResponse = function(response, type){\n var r;\n\n if(type == \"json\") {\n r = JSON.parse(response);\n }\n else\n if(core.isXml(type)) {\n r = core.parse(response, \"text/xml\");\n\t}\n else\n\tif(type == 'xhtml') {\n r = core.parse(response, \"application/xhtml+xml\");\n\t}\n else\n\tif(type == 'html' || type == 'htm') {\n r = core.parse(response, \"text/html\");\n \t} else {\n \t r = response;\n \t}\n\n return r;\n};\n\nUnarchive.prototype.getBlob = function(url, _mimeType){\n\tvar decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash\n\tvar entry = this.zip.file(decodededUrl);\n var mimeType;\n\n\tif(entry) {\n mimeType = _mimeType || mime.lookup(entry.name);\n return entry.async(\"uint8array\").then(function(uint8array) {\n return new Blob([uint8array], {type : mimeType});\n });\n\t}\n};\n\nUnarchive.prototype.getText = function(url, encoding){\n\tvar decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash\n\tvar entry = this.zip.file(decodededUrl);\n\n\tif(entry) {\n return entry.async(\"string\").then(function(text) {\n return text;\n });\n\t}\n};\n\nUnarchive.prototype.getBase64 = function(url, _mimeType){\n\tvar decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash\n\tvar entry = this.zip.file(decodededUrl);\n var mimeType;\n\n\tif(entry) {\n mimeType = _mimeType || mime.lookup(entry.name);\n return entry.async(\"base64\").then(function(data) {\n return \"data:\" + mimeType + \";base64,\" + data;\n });\n\t}\n};\n\nUnarchive.prototype.createUrl = function(url, options){\n\tvar deferred = new RSVP.defer();\n\tvar _URL = window.URL || window.webkitURL || window.mozURL;\n\tvar tempUrl;\n var blob;\n\tvar response;\n var useBase64 = options && options.base64;\n\n\tif(url in this.urlCache) {\n\t\tdeferred.resolve(this.urlCache[url]);\n\t\treturn deferred.promise;\n\t}\n\n if (useBase64) {\n response = this.getBase64(url);\n\n if (response) {\n response.then(function(tempUrl) {\n\n this.urlCache[url] = tempUrl;\n deferred.resolve(tempUrl);\n\n }.bind(this));\n\n }\n\n } else {\n\n response = this.getBlob(url);\n\n if (response) {\n response.then(function(blob) {\n\n tempUrl = _URL.createObjectURL(blob);\n this.urlCache[url] = tempUrl;\n deferred.resolve(tempUrl);\n\n }.bind(this));\n\n }\n }\n\n\n if (!response) {\n deferred.reject({\n message : \"File not found in the epub: \" + url,\n stack : new Error().stack\n });\n }\n\n\treturn deferred.promise;\n};\n\nUnarchive.prototype.revokeUrl = function(url){\n\tvar _URL = window.URL || window.webkitURL || window.mozURL;\n\tvar fromCache = this.urlCache[url];\n\tif(fromCache) _URL.revokeObjectURL(fromCache);\n};\n\nmodule.exports = Unarchive;\n","function Views(container) {\n this.container = container;\n this._views = [];\n this.length = 0;\n this.hidden = false;\n};\n\nViews.prototype.all = function() {\n\treturn this._views;\n};\n\nViews.prototype.first = function() {\n\treturn this._views[0];\n};\n\nViews.prototype.last = function() {\n\treturn this._views[this._views.length-1];\n};\n\nViews.prototype.indexOf = function(view) {\n\treturn this._views.indexOf(view);\n};\n\nViews.prototype.slice = function() {\n\treturn this._views.slice.apply(this._views, arguments);\n};\n\nViews.prototype.get = function(i) {\n\treturn this._views[i];\n};\n\nViews.prototype.append = function(view){\n\tthis._views.push(view);\n if(this.container){\n this.container.appendChild(view.element);\n }\n this.length++;\n return view;\n};\n\nViews.prototype.prepend = function(view){\n\tthis._views.unshift(view);\n if(this.container){\n this.container.insertBefore(view.element, this.container.firstChild);\n }\n this.length++;\n return view;\n};\n\nViews.prototype.insert = function(view, index) {\n\tthis._views.splice(index, 0, view);\n\n if(this.container){\n \tif(index < this.container.children.length){\n \t\tthis.container.insertBefore(view.element, this.container.children[index]);\n \t} else {\n \t\tthis.container.appendChild(view.element);\n \t}\n }\n\n this.length++;\n return view;\n};\n\nViews.prototype.remove = function(view) {\n\tvar index = this._views.indexOf(view);\n\n\tif(index > -1) {\n\t\tthis._views.splice(index, 1);\n\t}\n\n\n\tthis.destroy(view);\n\n this.length--;\n};\n\nViews.prototype.destroy = function(view) {\n\tview.off(\"resized\");\n\n\tif(view.displayed){\n\t\tview.destroy();\n\t}\n\n if(this.container){\n\t this.container.removeChild(view.element);\n }\n\tview = null;\n};\n\n// Iterators\n\nViews.prototype.each = function() {\n\treturn this._views.forEach.apply(this._views, arguments);\n};\n\nViews.prototype.clear = function(){\n\t// Remove all views\n var view;\n var len = this.length;\n\n if(!this.length) return;\n\n for (var i = 0; i < len; i++) {\n view = this._views[i];\n\t\tthis.destroy(view);\n }\n\n this._views = [];\n this.length = 0;\n};\n\nViews.prototype.find = function(section){\n\n var view;\n var len = this.length;\n\n for (var i = 0; i < len; i++) {\n view = this._views[i];\n\t\tif(view.displayed && view.section.index == section.index) {\n\t\t\treturn view;\n\t\t}\n }\n\n};\n\nViews.prototype.displayed = function(){\n var displayed = [];\n var view;\n var len = this.length;\n\n for (var i = 0; i < len; i++) {\n view = this._views[i];\n if(view.displayed){\n displayed.push(view);\n }\n }\n return displayed;\n};\n\nViews.prototype.show = function(){\n var view;\n var len = this.length;\n\n for (var i = 0; i < len; i++) {\n view = this._views[i];\n if(view.displayed){\n view.show();\n }\n }\n this.hidden = false;\n};\n\nViews.prototype.hide = function(){\n var view;\n var len = this.length;\n\n for (var i = 0; i < len; i++) {\n view = this._views[i];\n if(view.displayed){\n view.hide();\n }\n }\n this.hidden = true;\n};\n\nmodule.exports = Views;\n","var RSVP = require('rsvp');\nvar core = require('../core');\nvar EpubCFI = require('../epubcfi');\nvar Contents = require('../contents');\n\nfunction IframeView(section, options) {\n this.settings = core.extend({\n ignoreClass : '',\n axis: 'vertical',\n width: 0,\n height: 0,\n layout: undefined,\n globalLayoutProperties: {},\n }, options || {});\n\n this.id = \"epubjs-view-\" + core.uuid();\n this.section = section;\n this.index = section.index;\n\n this.element = this.container(this.settings.axis);\n\n this.added = false;\n this.displayed = false;\n this.rendered = false;\n\n this.width = this.settings.width;\n this.height = this.settings.height;\n\n this.fixedWidth = 0;\n this.fixedHeight = 0;\n\n // Blank Cfi for Parsing\n this.epubcfi = new EpubCFI();\n\n this.layout = this.settings.layout;\n // Dom events to listen for\n // this.listenedEvents = [\"keydown\", \"keyup\", \"keypressed\", \"mouseup\", \"mousedown\", \"click\", \"touchend\", \"touchstart\"];\n};\n\nIframeView.prototype.container = function(axis) {\n var element = document.createElement('div');\n\n element.classList.add(\"epub-view\");\n\n // this.element.style.minHeight = \"100px\";\n element.style.height = \"0px\";\n element.style.width = \"0px\";\n element.style.overflow = \"hidden\";\n\n if(axis && axis == \"horizontal\"){\n element.style.display = \"inline-block\";\n } else {\n element.style.display = \"block\";\n }\n\n return element;\n};\n\nIframeView.prototype.create = function() {\n\n if(this.iframe) {\n return this.iframe;\n }\n\n if(!this.element) {\n this.element = this.createContainer();\n }\n\n this.iframe = document.createElement('iframe');\n this.iframe.id = this.id;\n this.iframe.scrolling = \"no\"; // Might need to be removed: breaks ios width calculations\n this.iframe.style.overflow = \"hidden\";\n this.iframe.seamless = \"seamless\";\n // Back up if seamless isn't supported\n this.iframe.style.border = \"none\";\n\n this.resizing = true;\n\n // this.iframe.style.display = \"none\";\n this.element.style.visibility = \"hidden\";\n this.iframe.style.visibility = \"hidden\";\n\n this.iframe.style.width = \"0\";\n this.iframe.style.height = \"0\";\n this._width = 0;\n this._height = 0;\n\n this.element.appendChild(this.iframe);\n this.added = true;\n\n this.elementBounds = core.bounds(this.element);\n\n // if(width || height){\n // this.resize(width, height);\n // } else if(this.width && this.height){\n // this.resize(this.width, this.height);\n // } else {\n // this.iframeBounds = core.bounds(this.iframe);\n // }\n\n // Firefox has trouble with baseURI and srcdoc\n // TODO: Disable for now in firefox\n\n if(!!(\"srcdoc\" in this.iframe)) {\n this.supportsSrcdoc = true;\n } else {\n this.supportsSrcdoc = false;\n }\n\n return this.iframe;\n};\n\nIframeView.prototype.render = function(request, show) {\n\n\t// view.onLayout = this.layout.format.bind(this.layout);\n\tthis.create();\n\n\t// Fit to size of the container, apply padding\n this.size();\n\n if(!this.sectionRender) {\n this.sectionRender = this.section.render(request);\n }\n\n\t// Render Chain\n\treturn this.sectionRender\n\t\t.then(function(contents){\n\t\t\treturn this.load(contents);\n\t\t}.bind(this))\n\t\t// .then(function(doc){\n\t\t// \treturn this.hooks.content.trigger(view, this);\n\t\t// }.bind(this))\n\t\t.then(function(){\n\t\t\t// this.settings.layout.format(view.contents);\n\t\t\t// return this.hooks.layout.trigger(view, this);\n\t\t}.bind(this))\n\t\t// .then(function(){\n\t\t// \treturn this.display();\n\t\t// }.bind(this))\n\t\t// .then(function(){\n\t\t// \treturn this.hooks.render.trigger(view, this);\n\t\t// }.bind(this))\n\t\t.then(function(){\n\n // apply the layout function to the contents\n this.settings.layout.format(this.contents);\n\n // Expand the iframe to the full size of the content\n this.expand();\n\n // Listen for events that require an expansion of the iframe\n this.addListeners();\n\n\t\t\tif(show !== false) {\n\t\t\t\t//this.q.enqueue(function(view){\n\t\t\t\t\t// this.show();\n\t\t\t\t//}, view);\n\t\t\t}\n\t\t\t// this.map = new Map(view, this.layout);\n\t\t\t//this.hooks.show.trigger(view, this);\n\t\t\tthis.trigger(\"rendered\", this.section);\n\n\t\t}.bind(this))\n\t\t.catch(function(e){\n\t\t\tthis.trigger(\"loaderror\", e);\n\t\t}.bind(this));\n\n};\n\n// Determine locks base on settings\nIframeView.prototype.size = function(_width, _height) {\n var width = _width || this.settings.width;\n var height = _height || this.settings.height;\n\n if(this.layout.name === \"pre-paginated\") {\n this.lock(\"both\", width, height);\n } else if(this.settings.axis === \"horizontal\") {\n\t\tthis.lock(\"height\", width, height);\n\t} else {\n\t\tthis.lock(\"width\", width, height);\n\t}\n\n};\n\n// Lock an axis to element dimensions, taking borders into account\nIframeView.prototype.lock = function(what, width, height) {\n var elBorders = core.borders(this.element);\n var iframeBorders;\n\n if(this.iframe) {\n iframeBorders = core.borders(this.iframe);\n } else {\n iframeBorders = {width: 0, height: 0};\n }\n\n if(what == \"width\" && core.isNumber(width)){\n this.lockedWidth = width - elBorders.width - iframeBorders.width;\n this.resize(this.lockedWidth, width); // width keeps ratio correct\n }\n\n if(what == \"height\" && core.isNumber(height)){\n this.lockedHeight = height - elBorders.height - iframeBorders.height;\n this.resize(width, this.lockedHeight);\n }\n\n if(what === \"both\" &&\n core.isNumber(width) &&\n core.isNumber(height)){\n\n this.lockedWidth = width - elBorders.width - iframeBorders.width;\n this.lockedHeight = height - elBorders.height - iframeBorders.height;\n\n this.resize(this.lockedWidth, this.lockedHeight);\n }\n\n if(this.displayed && this.iframe) {\n\n // this.contents.layout();\n this.expand();\n\n }\n\n\n\n};\n\n// Resize a single axis based on content dimensions\nIframeView.prototype.expand = function(force) {\n var width = this.lockedWidth;\n var height = this.lockedHeight;\n var columns;\n\n var textWidth, textHeight;\n\n if(!this.iframe || this._expanding) return;\n\n this._expanding = true;\n\n // Expand Horizontally\n // if(height && !width) {\n if(this.settings.axis === \"horizontal\") {\n // Get the width of the text\n textWidth = this.contents.textWidth();\n // Check if the textWidth has changed\n if(textWidth != this._textWidth){\n // Get the contentWidth by resizing the iframe\n // Check with a min reset of the textWidth\n width = this.contentWidth(textWidth);\n\n columns = Math.ceil(width / (this.settings.layout.columnWidth + this.settings.layout.gap));\n\n if ( this.settings.layout.divisor > 1 &&\n this.settings.layout.name === \"reflowable\" &&\n (columns % 2 > 0)) {\n // add a blank page\n width += this.settings.layout.gap + this.settings.layout.columnWidth;\n }\n\n // Save the textWdith\n this._textWidth = textWidth;\n // Save the contentWidth\n this._contentWidth = width;\n } else {\n // Otherwise assume content height hasn't changed\n width = this._contentWidth;\n }\n } // Expand Vertically\n else if(this.settings.axis === \"vertical\") {\n textHeight = this.contents.textHeight();\n if(textHeight != this._textHeight){\n height = this.contentHeight(textHeight);\n this._textHeight = textHeight;\n this._contentHeight = height;\n } else {\n height = this._contentHeight;\n }\n\n }\n\n // Only Resize if dimensions have changed or\n // if Frame is still hidden, so needs reframing\n if(this._needsReframe || width != this._width || height != this._height){\n this.resize(width, height);\n }\n\n this._expanding = false;\n};\n\nIframeView.prototype.contentWidth = function(min) {\n var prev;\n var width;\n\n // Save previous width\n prev = this.iframe.style.width;\n // Set the iframe size to min, width will only ever be greater\n // Will preserve the aspect ratio\n this.iframe.style.width = (min || 0) + \"px\";\n // Get the scroll overflow width\n width = this.contents.scrollWidth();\n // Reset iframe size back\n this.iframe.style.width = prev;\n return width;\n};\n\nIframeView.prototype.contentHeight = function(min) {\n var prev;\n var height;\n\n prev = this.iframe.style.height;\n this.iframe.style.height = (min || 0) + \"px\";\n height = this.contents.scrollHeight();\n\n this.iframe.style.height = prev;\n return height;\n};\n\n\nIframeView.prototype.resize = function(width, height) {\n\n if(!this.iframe) return;\n\n if(core.isNumber(width)){\n this.iframe.style.width = width + \"px\";\n this._width = width;\n }\n\n if(core.isNumber(height)){\n this.iframe.style.height = height + \"px\";\n this._height = height;\n }\n\n this.iframeBounds = core.bounds(this.iframe);\n\n this.reframe(this.iframeBounds.width, this.iframeBounds.height);\n\n};\n\nIframeView.prototype.reframe = function(width, height) {\n var size;\n\n // if(!this.displayed) {\n // this._needsReframe = true;\n // return;\n // }\n if(core.isNumber(width)){\n this.element.style.width = width + \"px\";\n }\n\n if(core.isNumber(height)){\n this.element.style.height = height + \"px\";\n }\n\n this.prevBounds = this.elementBounds;\n\n this.elementBounds = core.bounds(this.element);\n\n size = {\n width: this.elementBounds.width,\n height: this.elementBounds.height,\n widthDelta: this.elementBounds.width - this.prevBounds.width,\n heightDelta: this.elementBounds.height - this.prevBounds.height,\n };\n\n this.onResize(this, size);\n\n this.trigger(\"resized\", size);\n\n};\n\n\nIframeView.prototype.load = function(contents) {\n var loading = new RSVP.defer();\n var loaded = loading.promise;\n\n if(!this.iframe) {\n loading.reject(new Error(\"No Iframe Available\"));\n return loaded;\n }\n\n this.iframe.onload = function(event) {\n\n this.onLoad(event, loading);\n\n }.bind(this);\n\n if(this.supportsSrcdoc){\n this.iframe.srcdoc = contents;\n } else {\n\n this.document = this.iframe.contentDocument;\n\n if(!this.document) {\n loading.reject(new Error(\"No Document Available\"));\n return loaded;\n }\n\n this.iframe.contentDocument.open();\n this.iframe.contentDocument.write(contents);\n this.iframe.contentDocument.close();\n\n }\n\n return loaded;\n};\n\nIframeView.prototype.onLoad = function(event, promise) {\n\n this.window = this.iframe.contentWindow;\n this.document = this.iframe.contentDocument;\n\n this.contents = new Contents(this.document, this.document.body, this.section.cfiBase);\n\n this.rendering = false;\n\n var link = this.document.querySelector(\"link[rel='canonical']\");\n if (link) {\n link.setAttribute(\"href\", this.section.url);\n } else {\n link = this.document.createElement(\"link\");\n link.setAttribute(\"rel\", \"canonical\");\n link.setAttribute(\"href\", this.section.url);\n this.document.querySelector(\"head\").appendChild(link);\n }\n\n this.contents.on(\"expand\", function () {\n if(this.displayed && this.iframe) {\n this.expand();\n }\n });\n\n promise.resolve(this.contents);\n};\n\n\n\n// IframeView.prototype.layout = function(layoutFunc) {\n//\n// this.iframe.style.display = \"inline-block\";\n//\n// // Reset Body Styles\n// // this.document.body.style.margin = \"0\";\n// //this.document.body.style.display = \"inline-block\";\n// //this.document.documentElement.style.width = \"auto\";\n//\n// if(layoutFunc){\n// this.layoutFunc = layoutFunc;\n// }\n//\n// this.contents.layout(this.layoutFunc);\n//\n// };\n//\n// IframeView.prototype.onLayout = function(view) {\n// // stub\n// };\n\nIframeView.prototype.setLayout = function(layout) {\n this.layout = layout;\n};\n\nIframeView.prototype.setAxis = function(axis) {\n this.settings.axis = axis;\n};\n\nIframeView.prototype.resizeListenters = function() {\n // Test size again\n clearTimeout(this.expanding);\n this.expanding = setTimeout(this.expand.bind(this), 350);\n};\n\nIframeView.prototype.addListeners = function() {\n //TODO: Add content listeners for expanding\n};\n\nIframeView.prototype.removeListeners = function(layoutFunc) {\n //TODO: remove content listeners for expanding\n};\n\nIframeView.prototype.display = function(request) {\n var displayed = new RSVP.defer();\n\n if (!this.displayed) {\n\n this.render(request).then(function () {\n\n this.trigger(\"displayed\", this);\n this.onDisplayed(this);\n\n this.displayed = true;\n displayed.resolve(this);\n\n }.bind(this));\n\n } else {\n displayed.resolve(this);\n }\n\n\n return displayed.promise;\n};\n\nIframeView.prototype.show = function() {\n\n this.element.style.visibility = \"visible\";\n\n if(this.iframe){\n this.iframe.style.visibility = \"visible\";\n }\n\n this.trigger(\"shown\", this);\n};\n\nIframeView.prototype.hide = function() {\n // this.iframe.style.display = \"none\";\n this.element.style.visibility = \"hidden\";\n this.iframe.style.visibility = \"hidden\";\n\n this.stopExpanding = true;\n this.trigger(\"hidden\", this);\n};\n\nIframeView.prototype.position = function() {\n return this.element.getBoundingClientRect();\n};\n\nIframeView.prototype.locationOf = function(target) {\n var parentPos = this.iframe.getBoundingClientRect();\n var targetPos = this.contents.locationOf(target, this.settings.ignoreClass);\n\n return {\n \"left\": window.scrollX + parentPos.left + targetPos.left,\n \"top\": window.scrollY + parentPos.top + targetPos.top\n };\n};\n\nIframeView.prototype.onDisplayed = function(view) {\n // Stub, override with a custom functions\n};\n\nIframeView.prototype.onResize = function(view, e) {\n // Stub, override with a custom functions\n};\n\nIframeView.prototype.bounds = function() {\n if(!this.elementBounds) {\n this.elementBounds = core.bounds(this.element);\n }\n return this.elementBounds;\n};\n\nIframeView.prototype.destroy = function() {\n\n if(this.displayed){\n this.displayed = false;\n\n this.removeListeners();\n\n this.stopExpanding = true;\n this.element.removeChild(this.iframe);\n this.displayed = false;\n this.iframe = null;\n\n this._textWidth = null;\n this._textHeight = null;\n this._width = null;\n this._height = null;\n }\n // this.element.style.height = \"0px\";\n // this.element.style.width = \"0px\";\n};\n\nRSVP.EventTarget.mixin(IframeView.prototype);\n\nmodule.exports = IframeView;\n","var Book = require('./book');\nvar EpubCFI = require('./epubcfi');\nvar Rendition = require('./rendition');\nvar Contents = require('./contents');\nvar RSVP = require('rsvp');\n\nfunction ePub(_url) {\n\treturn new Book(_url);\n};\n\nePub.VERSION = \"0.3.0\";\n\nePub.CFI = EpubCFI;\nePub.Rendition = Rendition;\nePub.Contents = Contents;\nePub.RSVP = RSVP;\n\nePub.ViewManagers = {};\nePub.Views = {};\nePub.register = {\n\tmanager : function(name, manager){\n \treturn ePub.ViewManagers[name] = manager;\n\t},\n\tview : function(name, view){\n\t\treturn ePub.Views[name] = view;\n\t}\n};\n\n// Default Views\nePub.register.view(\"iframe\", require('./views/iframe'));\n// ePub.register.view(\"inline\", require('./views/inline'));\n\n// Default View Managers\nePub.register.manager(\"single\", require('./managers/single'));\nePub.register.manager(\"continuous\", require('./managers/continuous'));\n\nmodule.exports = ePub;\n"]} \ No newline at end of file +{"version":3,"sources":["node_modules/browser-pack/_prelude.js","libs/mime/mime.js","node_modules/base64-js/index.js","node_modules/browserify/lib/_empty.js","node_modules/process/browser.js","node_modules/rsvp/dist/rsvp.js","node_modules/urijs/src/SecondLevelDomains.js","node_modules/urijs/src/URI.js","src/book.js","src/contents.js","src/core.js","src/epubcfi.js","src/hook.js","src/layout.js","src/locations.js","src/managers/continuous.js","src/managers/single.js","src/mapping.js","src/navigation.js","src/parser.js","src/queue.js","src/rendition.js","src/replacements.js","src/request.js","src/section.js","src/spine.js","src/stage.js","src/unarchive.js","src/views.js","src/views/iframe.js","src/epub.js"],"names":[],"mappings":"AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClHA;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;ACh8EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClqEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3VA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxpBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5hBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC16BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxqBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACthBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3eA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClkBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9jBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"epub.js","sourceRoot":"/source/","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o 0) {\n throw new Error('Invalid string. Length must be a multiple of 4')\n }\n\n // the number of equal signs (place holders)\n // if there are two placeholders, than the two characters before it\n // represent one byte\n // if there is only one, then the three characters before it represent 2 bytes\n // this is just a cheap hack to not do indexOf twice\n return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0\n}\n\nfunction byteLength (b64) {\n // base64 is 4/3 + up to two characters of the original data\n return b64.length * 3 / 4 - placeHoldersCount(b64)\n}\n\nfunction toByteArray (b64) {\n var i, j, l, tmp, placeHolders, arr\n var len = b64.length\n placeHolders = placeHoldersCount(b64)\n\n arr = new Arr(len * 3 / 4 - placeHolders)\n\n // if there are placeholders, only get up to the last complete 4 chars\n l = placeHolders > 0 ? len - 4 : len\n\n var L = 0\n\n for (i = 0, j = 0; i < l; i += 4, j += 3) {\n tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]\n arr[L++] = (tmp >> 16) & 0xFF\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n if (placeHolders === 2) {\n tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)\n arr[L++] = tmp & 0xFF\n } else if (placeHolders === 1) {\n tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n return arr\n}\n\nfunction tripletToBase64 (num) {\n return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n var tmp\n var output = []\n for (var i = start; i < end; i += 3) {\n tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n output.push(tripletToBase64(tmp))\n }\n return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n var tmp\n var len = uint8.length\n var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n var output = ''\n var parts = []\n var maxChunkLength = 16383 // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1]\n output += lookup[tmp >> 2]\n output += lookup[(tmp << 4) & 0x3F]\n output += '=='\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + (uint8[len - 1])\n output += lookup[tmp >> 10]\n output += lookup[(tmp >> 4) & 0x3F]\n output += lookup[(tmp << 2) & 0x3F]\n output += '='\n }\n\n parts.push(output)\n\n return parts.join('')\n}\n","","// shim for using process in browser\nvar process = module.exports = {};\n\n// cached from whatever global is present so that test runners that stub it\n// don't break things. But we need to wrap it in a try catch in case it is\n// wrapped in strict mode code which doesn't define any globals. It's inside a\n// function because try/catches deoptimize in certain engines.\n\nvar cachedSetTimeout;\nvar cachedClearTimeout;\n\nfunction defaultSetTimout() {\n throw new Error('setTimeout has not been defined');\n}\nfunction defaultClearTimeout () {\n throw new Error('clearTimeout has not been defined');\n}\n(function () {\n try {\n if (typeof setTimeout === 'function') {\n cachedSetTimeout = setTimeout;\n } else {\n cachedSetTimeout = defaultSetTimout;\n }\n } catch (e) {\n cachedSetTimeout = defaultSetTimout;\n }\n try {\n if (typeof clearTimeout === 'function') {\n cachedClearTimeout = clearTimeout;\n } else {\n cachedClearTimeout = defaultClearTimeout;\n }\n } catch (e) {\n cachedClearTimeout = defaultClearTimeout;\n }\n} ())\nfunction runTimeout(fun) {\n if (cachedSetTimeout === setTimeout) {\n //normal enviroments in sane situations\n return setTimeout(fun, 0);\n }\n // if setTimeout wasn't available but was latter defined\n if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\n cachedSetTimeout = setTimeout;\n return setTimeout(fun, 0);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedSetTimeout(fun, 0);\n } catch(e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedSetTimeout.call(null, fun, 0);\n } catch(e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n return cachedSetTimeout.call(this, fun, 0);\n }\n }\n\n\n}\nfunction runClearTimeout(marker) {\n if (cachedClearTimeout === clearTimeout) {\n //normal enviroments in sane situations\n return clearTimeout(marker);\n }\n // if clearTimeout wasn't available but was latter defined\n if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\n cachedClearTimeout = clearTimeout;\n return clearTimeout(marker);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedClearTimeout(marker);\n } catch (e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedClearTimeout.call(null, marker);\n } catch (e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n return cachedClearTimeout.call(this, marker);\n }\n }\n\n\n\n}\nvar queue = [];\nvar draining = false;\nvar currentQueue;\nvar queueIndex = -1;\n\nfunction cleanUpNextTick() {\n if (!draining || !currentQueue) {\n return;\n }\n draining = false;\n if (currentQueue.length) {\n queue = currentQueue.concat(queue);\n } else {\n queueIndex = -1;\n }\n if (queue.length) {\n drainQueue();\n }\n}\n\nfunction drainQueue() {\n if (draining) {\n return;\n }\n var timeout = runTimeout(cleanUpNextTick);\n draining = true;\n\n var len = queue.length;\n while(len) {\n currentQueue = queue;\n queue = [];\n while (++queueIndex < len) {\n if (currentQueue) {\n currentQueue[queueIndex].run();\n }\n }\n queueIndex = -1;\n len = queue.length;\n }\n currentQueue = null;\n draining = false;\n runClearTimeout(timeout);\n}\n\nprocess.nextTick = function (fun) {\n var args = new Array(arguments.length - 1);\n if (arguments.length > 1) {\n for (var i = 1; i < arguments.length; i++) {\n args[i - 1] = arguments[i];\n }\n }\n queue.push(new Item(fun, args));\n if (queue.length === 1 && !draining) {\n runTimeout(drainQueue);\n }\n};\n\n// v8 likes predictible objects\nfunction Item(fun, array) {\n this.fun = fun;\n this.array = array;\n}\nItem.prototype.run = function () {\n this.fun.apply(null, this.array);\n};\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\nprocess.version = ''; // empty string to avoid regexp issues\nprocess.versions = {};\n\nfunction noop() {}\n\nprocess.on = noop;\nprocess.addListener = noop;\nprocess.once = noop;\nprocess.off = noop;\nprocess.removeListener = noop;\nprocess.removeAllListeners = noop;\nprocess.emit = noop;\n\nprocess.binding = function (name) {\n throw new Error('process.binding is not supported');\n};\n\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n throw new Error('process.chdir is not supported');\n};\nprocess.umask = function() { return 0; };\n","/*!\n * @overview RSVP - a tiny implementation of Promises/A+.\n * @copyright Copyright (c) 2016 Yehuda Katz, Tom Dale, Stefan Penner and contributors\n * @license Licensed under MIT license\n * See https://raw.githubusercontent.com/tildeio/rsvp.js/master/LICENSE\n * @version 3.3.2\n */\n\n(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n typeof define === 'function' && define.amd ? define(['exports'], factory) :\n (factory((global.RSVP = global.RSVP || {})));\n}(this, (function (exports) { 'use strict';\n\nfunction indexOf(callbacks, callback) {\n for (var i = 0, l = callbacks.length; i < l; i++) {\n if (callbacks[i] === callback) {\n return i;\n }\n }\n\n return -1;\n}\n\nfunction callbacksFor(object) {\n var callbacks = object._promiseCallbacks;\n\n if (!callbacks) {\n callbacks = object._promiseCallbacks = {};\n }\n\n return callbacks;\n}\n\n/**\n @class RSVP.EventTarget\n*/\nvar EventTarget = {\n\n /**\n `RSVP.EventTarget.mixin` extends an object with EventTarget methods. For\n Example:\n ```javascript\n let object = {};\n RSVP.EventTarget.mixin(object);\n object.on('finished', function(event) {\n // handle event\n });\n object.trigger('finished', { detail: value });\n ```\n `EventTarget.mixin` also works with prototypes:\n ```javascript\n let Person = function() {};\n RSVP.EventTarget.mixin(Person.prototype);\n let yehuda = new Person();\n let tom = new Person();\n yehuda.on('poke', function(event) {\n console.log('Yehuda says OW');\n });\n tom.on('poke', function(event) {\n console.log('Tom says OW');\n });\n yehuda.trigger('poke');\n tom.trigger('poke');\n ```\n @method mixin\n @for RSVP.EventTarget\n @private\n @param {Object} object object to extend with EventTarget methods\n */\n mixin: function mixin(object) {\n object['on'] = this['on'];\n object['off'] = this['off'];\n object['trigger'] = this['trigger'];\n object._promiseCallbacks = undefined;\n return object;\n },\n\n /**\n Registers a callback to be executed when `eventName` is triggered\n ```javascript\n object.on('event', function(eventInfo){\n // handle the event\n });\n object.trigger('event');\n ```\n @method on\n @for RSVP.EventTarget\n @private\n @param {String} eventName name of the event to listen for\n @param {Function} callback function to be called when the event is triggered.\n */\n on: function on(eventName, callback) {\n if (typeof callback !== 'function') {\n throw new TypeError('Callback must be a function');\n }\n\n var allCallbacks = callbacksFor(this),\n callbacks = undefined;\n\n callbacks = allCallbacks[eventName];\n\n if (!callbacks) {\n callbacks = allCallbacks[eventName] = [];\n }\n\n if (indexOf(callbacks, callback) === -1) {\n callbacks.push(callback);\n }\n },\n\n /**\n You can use `off` to stop firing a particular callback for an event:\n ```javascript\n function doStuff() { // do stuff! }\n object.on('stuff', doStuff);\n object.trigger('stuff'); // doStuff will be called\n // Unregister ONLY the doStuff callback\n object.off('stuff', doStuff);\n object.trigger('stuff'); // doStuff will NOT be called\n ```\n If you don't pass a `callback` argument to `off`, ALL callbacks for the\n event will not be executed when the event fires. For example:\n ```javascript\n let callback1 = function(){};\n let callback2 = function(){};\n object.on('stuff', callback1);\n object.on('stuff', callback2);\n object.trigger('stuff'); // callback1 and callback2 will be executed.\n object.off('stuff');\n object.trigger('stuff'); // callback1 and callback2 will not be executed!\n ```\n @method off\n @for RSVP.EventTarget\n @private\n @param {String} eventName event to stop listening to\n @param {Function} callback optional argument. If given, only the function\n given will be removed from the event's callback queue. If no `callback`\n argument is given, all callbacks will be removed from the event's callback\n queue.\n */\n off: function off(eventName, callback) {\n var allCallbacks = callbacksFor(this),\n callbacks = undefined,\n index = undefined;\n\n if (!callback) {\n allCallbacks[eventName] = [];\n return;\n }\n\n callbacks = allCallbacks[eventName];\n\n index = indexOf(callbacks, callback);\n\n if (index !== -1) {\n callbacks.splice(index, 1);\n }\n },\n\n /**\n Use `trigger` to fire custom events. For example:\n ```javascript\n object.on('foo', function(){\n console.log('foo event happened!');\n });\n object.trigger('foo');\n // 'foo event happened!' logged to the console\n ```\n You can also pass a value as a second argument to `trigger` that will be\n passed as an argument to all event listeners for the event:\n ```javascript\n object.on('foo', function(value){\n console.log(value.name);\n });\n object.trigger('foo', { name: 'bar' });\n // 'bar' logged to the console\n ```\n @method trigger\n @for RSVP.EventTarget\n @private\n @param {String} eventName name of the event to be triggered\n @param {*} options optional value to be passed to any event handlers for\n the given `eventName`\n */\n trigger: function trigger(eventName, options, label) {\n var allCallbacks = callbacksFor(this),\n callbacks = undefined,\n callback = undefined;\n\n if (callbacks = allCallbacks[eventName]) {\n // Don't cache the callbacks.length since it may grow\n for (var i = 0; i < callbacks.length; i++) {\n callback = callbacks[i];\n\n callback(options, label);\n }\n }\n }\n};\n\nvar config = {\n instrument: false\n};\n\nEventTarget['mixin'](config);\n\nfunction configure(name, value) {\n if (name === 'onerror') {\n // handle for legacy users that expect the actual\n // error to be passed to their function added via\n // `RSVP.configure('onerror', someFunctionHere);`\n config['on']('error', value);\n return;\n }\n\n if (arguments.length === 2) {\n config[name] = value;\n } else {\n return config[name];\n }\n}\n\nfunction objectOrFunction(x) {\n return typeof x === 'function' || typeof x === 'object' && x !== null;\n}\n\nfunction isFunction(x) {\n return typeof x === 'function';\n}\n\nfunction isMaybeThenable(x) {\n return typeof x === 'object' && x !== null;\n}\n\nvar _isArray = undefined;\nif (!Array.isArray) {\n _isArray = function (x) {\n return Object.prototype.toString.call(x) === '[object Array]';\n };\n} else {\n _isArray = Array.isArray;\n}\n\nvar isArray = _isArray;\n\n// Date.now is not available in browsers < IE9\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility\nvar now = Date.now || function () {\n return new Date().getTime();\n};\n\nfunction F() {}\n\nvar o_create = Object.create || function (o) {\n if (arguments.length > 1) {\n throw new Error('Second argument not supported');\n }\n if (typeof o !== 'object') {\n throw new TypeError('Argument must be an object');\n }\n F.prototype = o;\n return new F();\n};\n\nvar queue = [];\n\nfunction scheduleFlush() {\n setTimeout(function () {\n for (var i = 0; i < queue.length; i++) {\n var entry = queue[i];\n\n var payload = entry.payload;\n\n payload.guid = payload.key + payload.id;\n payload.childGuid = payload.key + payload.childId;\n if (payload.error) {\n payload.stack = payload.error.stack;\n }\n\n config['trigger'](entry.name, entry.payload);\n }\n queue.length = 0;\n }, 50);\n}\nfunction instrument(eventName, promise, child) {\n if (1 === queue.push({\n name: eventName,\n payload: {\n key: promise._guidKey,\n id: promise._id,\n eventName: eventName,\n detail: promise._result,\n childId: child && child._id,\n label: promise._label,\n timeStamp: now(),\n error: config[\"instrument-with-stack\"] ? new Error(promise._label) : null\n } })) {\n scheduleFlush();\n }\n}\n\n/**\n `RSVP.Promise.resolve` returns a promise that will become resolved with the\n passed `value`. It is shorthand for the following:\n\n ```javascript\n let promise = new RSVP.Promise(function(resolve, reject){\n resolve(1);\n });\n\n promise.then(function(value){\n // value === 1\n });\n ```\n\n Instead of writing the above, your code now simply becomes the following:\n\n ```javascript\n let promise = RSVP.Promise.resolve(1);\n\n promise.then(function(value){\n // value === 1\n });\n ```\n\n @method resolve\n @static\n @param {*} object value that the returned promise will be resolved with\n @param {String} label optional string for identifying the returned promise.\n Useful for tooling.\n @return {Promise} a promise that will become fulfilled with the given\n `value`\n*/\nfunction resolve$1(object, label) {\n /*jshint validthis:true */\n var Constructor = this;\n\n if (object && typeof object === 'object' && object.constructor === Constructor) {\n return object;\n }\n\n var promise = new Constructor(noop, label);\n resolve(promise, object);\n return promise;\n}\n\nfunction withOwnPromise() {\n return new TypeError('A promises callback cannot return that same promise.');\n}\n\nfunction noop() {}\n\nvar PENDING = void 0;\nvar FULFILLED = 1;\nvar REJECTED = 2;\n\nvar GET_THEN_ERROR = new ErrorObject();\n\nfunction getThen(promise) {\n try {\n return promise.then;\n } catch (error) {\n GET_THEN_ERROR.error = error;\n return GET_THEN_ERROR;\n }\n}\n\nfunction tryThen(then, value, fulfillmentHandler, rejectionHandler) {\n try {\n then.call(value, fulfillmentHandler, rejectionHandler);\n } catch (e) {\n return e;\n }\n}\n\nfunction handleForeignThenable(promise, thenable, then) {\n config.async(function (promise) {\n var sealed = false;\n var error = tryThen(then, thenable, function (value) {\n if (sealed) {\n return;\n }\n sealed = true;\n if (thenable !== value) {\n resolve(promise, value, undefined);\n } else {\n fulfill(promise, value);\n }\n }, function (reason) {\n if (sealed) {\n return;\n }\n sealed = true;\n\n reject(promise, reason);\n }, 'Settle: ' + (promise._label || ' unknown promise'));\n\n if (!sealed && error) {\n sealed = true;\n reject(promise, error);\n }\n }, promise);\n}\n\nfunction handleOwnThenable(promise, thenable) {\n if (thenable._state === FULFILLED) {\n fulfill(promise, thenable._result);\n } else if (thenable._state === REJECTED) {\n thenable._onError = null;\n reject(promise, thenable._result);\n } else {\n subscribe(thenable, undefined, function (value) {\n if (thenable !== value) {\n resolve(promise, value, undefined);\n } else {\n fulfill(promise, value);\n }\n }, function (reason) {\n return reject(promise, reason);\n });\n }\n}\n\nfunction handleMaybeThenable(promise, maybeThenable, then$$) {\n if (maybeThenable.constructor === promise.constructor && then$$ === then && promise.constructor.resolve === resolve$1) {\n handleOwnThenable(promise, maybeThenable);\n } else {\n if (then$$ === GET_THEN_ERROR) {\n reject(promise, GET_THEN_ERROR.error);\n } else if (then$$ === undefined) {\n fulfill(promise, maybeThenable);\n } else if (isFunction(then$$)) {\n handleForeignThenable(promise, maybeThenable, then$$);\n } else {\n fulfill(promise, maybeThenable);\n }\n }\n}\n\nfunction resolve(promise, value) {\n if (promise === value) {\n fulfill(promise, value);\n } else if (objectOrFunction(value)) {\n handleMaybeThenable(promise, value, getThen(value));\n } else {\n fulfill(promise, value);\n }\n}\n\nfunction publishRejection(promise) {\n if (promise._onError) {\n promise._onError(promise._result);\n }\n\n publish(promise);\n}\n\nfunction fulfill(promise, value) {\n if (promise._state !== PENDING) {\n return;\n }\n\n promise._result = value;\n promise._state = FULFILLED;\n\n if (promise._subscribers.length === 0) {\n if (config.instrument) {\n instrument('fulfilled', promise);\n }\n } else {\n config.async(publish, promise);\n }\n}\n\nfunction reject(promise, reason) {\n if (promise._state !== PENDING) {\n return;\n }\n promise._state = REJECTED;\n promise._result = reason;\n config.async(publishRejection, promise);\n}\n\nfunction subscribe(parent, child, onFulfillment, onRejection) {\n var subscribers = parent._subscribers;\n var length = subscribers.length;\n\n parent._onError = null;\n\n subscribers[length] = child;\n subscribers[length + FULFILLED] = onFulfillment;\n subscribers[length + REJECTED] = onRejection;\n\n if (length === 0 && parent._state) {\n config.async(publish, parent);\n }\n}\n\nfunction publish(promise) {\n var subscribers = promise._subscribers;\n var settled = promise._state;\n\n if (config.instrument) {\n instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise);\n }\n\n if (subscribers.length === 0) {\n return;\n }\n\n var child = undefined,\n callback = undefined,\n detail = promise._result;\n\n for (var i = 0; i < subscribers.length; i += 3) {\n child = subscribers[i];\n callback = subscribers[i + settled];\n\n if (child) {\n invokeCallback(settled, child, callback, detail);\n } else {\n callback(detail);\n }\n }\n\n promise._subscribers.length = 0;\n}\n\nfunction ErrorObject() {\n this.error = null;\n}\n\nvar TRY_CATCH_ERROR = new ErrorObject();\n\nfunction tryCatch(callback, detail) {\n try {\n return callback(detail);\n } catch (e) {\n TRY_CATCH_ERROR.error = e;\n return TRY_CATCH_ERROR;\n }\n}\n\nfunction invokeCallback(settled, promise, callback, detail) {\n var hasCallback = isFunction(callback),\n value = undefined,\n error = undefined,\n succeeded = undefined,\n failed = undefined;\n\n if (hasCallback) {\n value = tryCatch(callback, detail);\n\n if (value === TRY_CATCH_ERROR) {\n failed = true;\n error = value.error;\n value = null;\n } else {\n succeeded = true;\n }\n\n if (promise === value) {\n reject(promise, withOwnPromise());\n return;\n }\n } else {\n value = detail;\n succeeded = true;\n }\n\n if (promise._state !== PENDING) {\n // noop\n } else if (hasCallback && succeeded) {\n resolve(promise, value);\n } else if (failed) {\n reject(promise, error);\n } else if (settled === FULFILLED) {\n fulfill(promise, value);\n } else if (settled === REJECTED) {\n reject(promise, value);\n }\n}\n\nfunction initializePromise(promise, resolver) {\n var resolved = false;\n try {\n resolver(function (value) {\n if (resolved) {\n return;\n }\n resolved = true;\n resolve(promise, value);\n }, function (reason) {\n if (resolved) {\n return;\n }\n resolved = true;\n reject(promise, reason);\n });\n } catch (e) {\n reject(promise, e);\n }\n}\n\nfunction then(onFulfillment, onRejection, label) {\n var _arguments = arguments;\n\n var parent = this;\n var state = parent._state;\n\n if (state === FULFILLED && !onFulfillment || state === REJECTED && !onRejection) {\n config.instrument && instrument('chained', parent, parent);\n return parent;\n }\n\n parent._onError = null;\n\n var child = new parent.constructor(noop, label);\n var result = parent._result;\n\n config.instrument && instrument('chained', parent, child);\n\n if (state) {\n (function () {\n var callback = _arguments[state - 1];\n config.async(function () {\n return invokeCallback(state, child, callback, result);\n });\n })();\n } else {\n subscribe(parent, child, onFulfillment, onRejection);\n }\n\n return child;\n}\n\nfunction makeSettledResult(state, position, value) {\n if (state === FULFILLED) {\n return {\n state: 'fulfilled',\n value: value\n };\n } else {\n return {\n state: 'rejected',\n reason: value\n };\n }\n}\n\nfunction Enumerator(Constructor, input, abortOnReject, label) {\n this._instanceConstructor = Constructor;\n this.promise = new Constructor(noop, label);\n this._abortOnReject = abortOnReject;\n\n if (this._validateInput(input)) {\n this._input = input;\n this.length = input.length;\n this._remaining = input.length;\n\n this._init();\n\n if (this.length === 0) {\n fulfill(this.promise, this._result);\n } else {\n this.length = this.length || 0;\n this._enumerate();\n if (this._remaining === 0) {\n fulfill(this.promise, this._result);\n }\n }\n } else {\n reject(this.promise, this._validationError());\n }\n}\n\nEnumerator.prototype._validateInput = function (input) {\n return isArray(input);\n};\n\nEnumerator.prototype._validationError = function () {\n return new Error('Array Methods must be provided an Array');\n};\n\nEnumerator.prototype._init = function () {\n this._result = new Array(this.length);\n};\n\nEnumerator.prototype._enumerate = function () {\n var length = this.length;\n var promise = this.promise;\n var input = this._input;\n\n for (var i = 0; promise._state === PENDING && i < length; i++) {\n this._eachEntry(input[i], i);\n }\n};\n\nEnumerator.prototype._settleMaybeThenable = function (entry, i) {\n var c = this._instanceConstructor;\n var resolve = c.resolve;\n\n if (resolve === resolve$1) {\n var then$$ = getThen(entry);\n\n if (then$$ === then && entry._state !== PENDING) {\n entry._onError = null;\n this._settledAt(entry._state, i, entry._result);\n } else if (typeof then$$ !== 'function') {\n this._remaining--;\n this._result[i] = this._makeResult(FULFILLED, i, entry);\n } else if (c === Promise) {\n var promise = new c(noop);\n handleMaybeThenable(promise, entry, then$$);\n this._willSettleAt(promise, i);\n } else {\n this._willSettleAt(new c(function (resolve) {\n return resolve(entry);\n }), i);\n }\n } else {\n this._willSettleAt(resolve(entry), i);\n }\n};\n\nEnumerator.prototype._eachEntry = function (entry, i) {\n if (isMaybeThenable(entry)) {\n this._settleMaybeThenable(entry, i);\n } else {\n this._remaining--;\n this._result[i] = this._makeResult(FULFILLED, i, entry);\n }\n};\n\nEnumerator.prototype._settledAt = function (state, i, value) {\n var promise = this.promise;\n\n if (promise._state === PENDING) {\n this._remaining--;\n\n if (this._abortOnReject && state === REJECTED) {\n reject(promise, value);\n } else {\n this._result[i] = this._makeResult(state, i, value);\n }\n }\n\n if (this._remaining === 0) {\n fulfill(promise, this._result);\n }\n};\n\nEnumerator.prototype._makeResult = function (state, i, value) {\n return value;\n};\n\nEnumerator.prototype._willSettleAt = function (promise, i) {\n var enumerator = this;\n\n subscribe(promise, undefined, function (value) {\n return enumerator._settledAt(FULFILLED, i, value);\n }, function (reason) {\n return enumerator._settledAt(REJECTED, i, reason);\n });\n};\n\n/**\n `RSVP.Promise.all` accepts an array of promises, and returns a new promise which\n is fulfilled with an array of fulfillment values for the passed promises, or\n rejected with the reason of the first passed promise to be rejected. It casts all\n elements of the passed iterable to promises as it runs this algorithm.\n\n Example:\n\n ```javascript\n let promise1 = RSVP.resolve(1);\n let promise2 = RSVP.resolve(2);\n let promise3 = RSVP.resolve(3);\n let promises = [ promise1, promise2, promise3 ];\n\n RSVP.Promise.all(promises).then(function(array){\n // The array here would be [ 1, 2, 3 ];\n });\n ```\n\n If any of the `promises` given to `RSVP.all` are rejected, the first promise\n that is rejected will be given as an argument to the returned promises's\n rejection handler. For example:\n\n Example:\n\n ```javascript\n let promise1 = RSVP.resolve(1);\n let promise2 = RSVP.reject(new Error(\"2\"));\n let promise3 = RSVP.reject(new Error(\"3\"));\n let promises = [ promise1, promise2, promise3 ];\n\n RSVP.Promise.all(promises).then(function(array){\n // Code here never runs because there are rejected promises!\n }, function(error) {\n // error.message === \"2\"\n });\n ```\n\n @method all\n @static\n @param {Array} entries array of promises\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @return {Promise} promise that is fulfilled when all `promises` have been\n fulfilled, or rejected if any of them become rejected.\n @static\n*/\nfunction all(entries, label) {\n return new Enumerator(this, entries, true, /* abort on reject */label).promise;\n}\n\n/**\n `RSVP.Promise.race` returns a new promise which is settled in the same way as the\n first passed promise to settle.\n\n Example:\n\n ```javascript\n let promise1 = new RSVP.Promise(function(resolve, reject){\n setTimeout(function(){\n resolve('promise 1');\n }, 200);\n });\n\n let promise2 = new RSVP.Promise(function(resolve, reject){\n setTimeout(function(){\n resolve('promise 2');\n }, 100);\n });\n\n RSVP.Promise.race([promise1, promise2]).then(function(result){\n // result === 'promise 2' because it was resolved before promise1\n // was resolved.\n });\n ```\n\n `RSVP.Promise.race` is deterministic in that only the state of the first\n settled promise matters. For example, even if other promises given to the\n `promises` array argument are resolved, but the first settled promise has\n become rejected before the other promises became fulfilled, the returned\n promise will become rejected:\n\n ```javascript\n let promise1 = new RSVP.Promise(function(resolve, reject){\n setTimeout(function(){\n resolve('promise 1');\n }, 200);\n });\n\n let promise2 = new RSVP.Promise(function(resolve, reject){\n setTimeout(function(){\n reject(new Error('promise 2'));\n }, 100);\n });\n\n RSVP.Promise.race([promise1, promise2]).then(function(result){\n // Code here never runs\n }, function(reason){\n // reason.message === 'promise 2' because promise 2 became rejected before\n // promise 1 became fulfilled\n });\n ```\n\n An example real-world use case is implementing timeouts:\n\n ```javascript\n RSVP.Promise.race([ajax('foo.json'), timeout(5000)])\n ```\n\n @method race\n @static\n @param {Array} entries array of promises to observe\n @param {String} label optional string for describing the promise returned.\n Useful for tooling.\n @return {Promise} a promise which settles in the same way as the first passed\n promise to settle.\n*/\nfunction race(entries, label) {\n /*jshint validthis:true */\n var Constructor = this;\n\n var promise = new Constructor(noop, label);\n\n if (!isArray(entries)) {\n reject(promise, new TypeError('You must pass an array to race.'));\n return promise;\n }\n\n for (var i = 0; promise._state === PENDING && i < entries.length; i++) {\n subscribe(Constructor.resolve(entries[i]), undefined, function (value) {\n return resolve(promise, value);\n }, function (reason) {\n return reject(promise, reason);\n });\n }\n\n return promise;\n}\n\n/**\n `RSVP.Promise.reject` returns a promise rejected with the passed `reason`.\n It is shorthand for the following:\n\n ```javascript\n let promise = new RSVP.Promise(function(resolve, reject){\n reject(new Error('WHOOPS'));\n });\n\n promise.then(function(value){\n // Code here doesn't run because the promise is rejected!\n }, function(reason){\n // reason.message === 'WHOOPS'\n });\n ```\n\n Instead of writing the above, your code now simply becomes the following:\n\n ```javascript\n let promise = RSVP.Promise.reject(new Error('WHOOPS'));\n\n promise.then(function(value){\n // Code here doesn't run because the promise is rejected!\n }, function(reason){\n // reason.message === 'WHOOPS'\n });\n ```\n\n @method reject\n @static\n @param {*} reason value that the returned promise will be rejected with.\n @param {String} label optional string for identifying the returned promise.\n Useful for tooling.\n @return {Promise} a promise rejected with the given `reason`.\n*/\nfunction reject$1(reason, label) {\n /*jshint validthis:true */\n var Constructor = this;\n var promise = new Constructor(noop, label);\n reject(promise, reason);\n return promise;\n}\n\nvar guidKey = 'rsvp_' + now() + '-';\nvar counter = 0;\n\nfunction needsResolver() {\n throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');\n}\n\nfunction needsNew() {\n throw new TypeError(\"Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.\");\n}\n\n/**\n Promise objects represent the eventual result of an asynchronous operation. The\n primary way of interacting with a promise is through its `then` method, which\n registers callbacks to receive either a promise’s eventual value or the reason\n why the promise cannot be fulfilled.\n\n Terminology\n -----------\n\n - `promise` is an object or function with a `then` method whose behavior conforms to this specification.\n - `thenable` is an object or function that defines a `then` method.\n - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).\n - `exception` is a value that is thrown using the throw statement.\n - `reason` is a value that indicates why a promise was rejected.\n - `settled` the final resting state of a promise, fulfilled or rejected.\n\n A promise can be in one of three states: pending, fulfilled, or rejected.\n\n Promises that are fulfilled have a fulfillment value and are in the fulfilled\n state. Promises that are rejected have a rejection reason and are in the\n rejected state. A fulfillment value is never a thenable.\n\n Promises can also be said to *resolve* a value. If this value is also a\n promise, then the original promise's settled state will match the value's\n settled state. So a promise that *resolves* a promise that rejects will\n itself reject, and a promise that *resolves* a promise that fulfills will\n itself fulfill.\n\n\n Basic Usage:\n ------------\n\n ```js\n let promise = new Promise(function(resolve, reject) {\n // on success\n resolve(value);\n\n // on failure\n reject(reason);\n });\n\n promise.then(function(value) {\n // on fulfillment\n }, function(reason) {\n // on rejection\n });\n ```\n\n Advanced Usage:\n ---------------\n\n Promises shine when abstracting away asynchronous interactions such as\n `XMLHttpRequest`s.\n\n ```js\n function getJSON(url) {\n return new Promise(function(resolve, reject){\n let xhr = new XMLHttpRequest();\n\n xhr.open('GET', url);\n xhr.onreadystatechange = handler;\n xhr.responseType = 'json';\n xhr.setRequestHeader('Accept', 'application/json');\n xhr.send();\n\n function handler() {\n if (this.readyState === this.DONE) {\n if (this.status === 200) {\n resolve(this.response);\n } else {\n reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));\n }\n }\n };\n });\n }\n\n getJSON('/posts.json').then(function(json) {\n // on fulfillment\n }, function(reason) {\n // on rejection\n });\n ```\n\n Unlike callbacks, promises are great composable primitives.\n\n ```js\n Promise.all([\n getJSON('/posts'),\n getJSON('/comments')\n ]).then(function(values){\n values[0] // => postsJSON\n values[1] // => commentsJSON\n\n return values;\n });\n ```\n\n @class RSVP.Promise\n @param {function} resolver\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @constructor\n*/\nfunction Promise(resolver, label) {\n this._id = counter++;\n this._label = label;\n this._state = undefined;\n this._result = undefined;\n this._subscribers = [];\n\n config.instrument && instrument('created', this);\n\n if (noop !== resolver) {\n typeof resolver !== 'function' && needsResolver();\n this instanceof Promise ? initializePromise(this, resolver) : needsNew();\n }\n}\n\nPromise.cast = resolve$1; // deprecated\nPromise.all = all;\nPromise.race = race;\nPromise.resolve = resolve$1;\nPromise.reject = reject$1;\n\nPromise.prototype = {\n constructor: Promise,\n\n _guidKey: guidKey,\n\n _onError: function _onError(reason) {\n var promise = this;\n config.after(function () {\n if (promise._onError) {\n config['trigger']('error', reason, promise._label);\n }\n });\n },\n\n /**\n The primary way of interacting with a promise is through its `then` method,\n which registers callbacks to receive either a promise's eventual value or the\n reason why the promise cannot be fulfilled.\n \n ```js\n findUser().then(function(user){\n // user is available\n }, function(reason){\n // user is unavailable, and you are given the reason why\n });\n ```\n \n Chaining\n --------\n \n The return value of `then` is itself a promise. This second, 'downstream'\n promise is resolved with the return value of the first promise's fulfillment\n or rejection handler, or rejected if the handler throws an exception.\n \n ```js\n findUser().then(function (user) {\n return user.name;\n }, function (reason) {\n return 'default name';\n }).then(function (userName) {\n // If `findUser` fulfilled, `userName` will be the user's name, otherwise it\n // will be `'default name'`\n });\n \n findUser().then(function (user) {\n throw new Error('Found user, but still unhappy');\n }, function (reason) {\n throw new Error('`findUser` rejected and we\\'re unhappy');\n }).then(function (value) {\n // never reached\n }, function (reason) {\n // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.\n // If `findUser` rejected, `reason` will be '`findUser` rejected and we\\'re unhappy'.\n });\n ```\n If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.\n \n ```js\n findUser().then(function (user) {\n throw new PedagogicalException('Upstream error');\n }).then(function (value) {\n // never reached\n }).then(function (value) {\n // never reached\n }, function (reason) {\n // The `PedgagocialException` is propagated all the way down to here\n });\n ```\n \n Assimilation\n ------------\n \n Sometimes the value you want to propagate to a downstream promise can only be\n retrieved asynchronously. This can be achieved by returning a promise in the\n fulfillment or rejection handler. The downstream promise will then be pending\n until the returned promise is settled. This is called *assimilation*.\n \n ```js\n findUser().then(function (user) {\n return findCommentsByAuthor(user);\n }).then(function (comments) {\n // The user's comments are now available\n });\n ```\n \n If the assimliated promise rejects, then the downstream promise will also reject.\n \n ```js\n findUser().then(function (user) {\n return findCommentsByAuthor(user);\n }).then(function (comments) {\n // If `findCommentsByAuthor` fulfills, we'll have the value here\n }, function (reason) {\n // If `findCommentsByAuthor` rejects, we'll have the reason here\n });\n ```\n \n Simple Example\n --------------\n \n Synchronous Example\n \n ```javascript\n let result;\n \n try {\n result = findResult();\n // success\n } catch(reason) {\n // failure\n }\n ```\n \n Errback Example\n \n ```js\n findResult(function(result, err){\n if (err) {\n // failure\n } else {\n // success\n }\n });\n ```\n \n Promise Example;\n \n ```javascript\n findResult().then(function(result){\n // success\n }, function(reason){\n // failure\n });\n ```\n \n Advanced Example\n --------------\n \n Synchronous Example\n \n ```javascript\n let author, books;\n \n try {\n author = findAuthor();\n books = findBooksByAuthor(author);\n // success\n } catch(reason) {\n // failure\n }\n ```\n \n Errback Example\n \n ```js\n \n function foundBooks(books) {\n \n }\n \n function failure(reason) {\n \n }\n \n findAuthor(function(author, err){\n if (err) {\n failure(err);\n // failure\n } else {\n try {\n findBoooksByAuthor(author, function(books, err) {\n if (err) {\n failure(err);\n } else {\n try {\n foundBooks(books);\n } catch(reason) {\n failure(reason);\n }\n }\n });\n } catch(error) {\n failure(err);\n }\n // success\n }\n });\n ```\n \n Promise Example;\n \n ```javascript\n findAuthor().\n then(findBooksByAuthor).\n then(function(books){\n // found books\n }).catch(function(reason){\n // something went wrong\n });\n ```\n \n @method then\n @param {Function} onFulfillment\n @param {Function} onRejection\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @return {Promise}\n */\n then: then,\n\n /**\n `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same\n as the catch block of a try/catch statement.\n \n ```js\n function findAuthor(){\n throw new Error('couldn\\'t find that author');\n }\n \n // synchronous\n try {\n findAuthor();\n } catch(reason) {\n // something went wrong\n }\n \n // async with promises\n findAuthor().catch(function(reason){\n // something went wrong\n });\n ```\n \n @method catch\n @param {Function} onRejection\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @return {Promise}\n */\n 'catch': function _catch(onRejection, label) {\n return this.then(undefined, onRejection, label);\n },\n\n /**\n `finally` will be invoked regardless of the promise's fate just as native\n try/catch/finally behaves\n \n Synchronous example:\n \n ```js\n findAuthor() {\n if (Math.random() > 0.5) {\n throw new Error();\n }\n return new Author();\n }\n \n try {\n return findAuthor(); // succeed or fail\n } catch(error) {\n return findOtherAuther();\n } finally {\n // always runs\n // doesn't affect the return value\n }\n ```\n \n Asynchronous example:\n \n ```js\n findAuthor().catch(function(reason){\n return findOtherAuther();\n }).finally(function(){\n // author was either found, or not\n });\n ```\n \n @method finally\n @param {Function} callback\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @return {Promise}\n */\n 'finally': function _finally(callback, label) {\n var promise = this;\n var constructor = promise.constructor;\n\n return promise.then(function (value) {\n return constructor.resolve(callback()).then(function () {\n return value;\n });\n }, function (reason) {\n return constructor.resolve(callback()).then(function () {\n throw reason;\n });\n }, label);\n }\n};\n\nfunction Result() {\n this.value = undefined;\n}\n\nvar ERROR = new Result();\nvar GET_THEN_ERROR$1 = new Result();\n\nfunction getThen$1(obj) {\n try {\n return obj.then;\n } catch (error) {\n ERROR.value = error;\n return ERROR;\n }\n}\n\nfunction tryApply(f, s, a) {\n try {\n f.apply(s, a);\n } catch (error) {\n ERROR.value = error;\n return ERROR;\n }\n}\n\nfunction makeObject(_, argumentNames) {\n var obj = {};\n var length = _.length;\n var args = new Array(length);\n\n for (var x = 0; x < length; x++) {\n args[x] = _[x];\n }\n\n for (var i = 0; i < argumentNames.length; i++) {\n var _name = argumentNames[i];\n obj[_name] = args[i + 1];\n }\n\n return obj;\n}\n\nfunction arrayResult(_) {\n var length = _.length;\n var args = new Array(length - 1);\n\n for (var i = 1; i < length; i++) {\n args[i - 1] = _[i];\n }\n\n return args;\n}\n\nfunction wrapThenable(_then, promise) {\n return {\n then: function then(onFulFillment, onRejection) {\n return _then.call(promise, onFulFillment, onRejection);\n }\n };\n}\n\n/**\n `RSVP.denodeify` takes a 'node-style' function and returns a function that\n will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the\n browser when you'd prefer to use promises over using callbacks. For example,\n `denodeify` transforms the following:\n\n ```javascript\n let fs = require('fs');\n\n fs.readFile('myfile.txt', function(err, data){\n if (err) return handleError(err);\n handleData(data);\n });\n ```\n\n into:\n\n ```javascript\n let fs = require('fs');\n let readFile = RSVP.denodeify(fs.readFile);\n\n readFile('myfile.txt').then(handleData, handleError);\n ```\n\n If the node function has multiple success parameters, then `denodeify`\n just returns the first one:\n\n ```javascript\n let request = RSVP.denodeify(require('request'));\n\n request('http://example.com').then(function(res) {\n // ...\n });\n ```\n\n However, if you need all success parameters, setting `denodeify`'s\n second parameter to `true` causes it to return all success parameters\n as an array:\n\n ```javascript\n let request = RSVP.denodeify(require('request'), true);\n\n request('http://example.com').then(function(result) {\n // result[0] -> res\n // result[1] -> body\n });\n ```\n\n Or if you pass it an array with names it returns the parameters as a hash:\n\n ```javascript\n let request = RSVP.denodeify(require('request'), ['res', 'body']);\n\n request('http://example.com').then(function(result) {\n // result.res\n // result.body\n });\n ```\n\n Sometimes you need to retain the `this`:\n\n ```javascript\n let app = require('express')();\n let render = RSVP.denodeify(app.render.bind(app));\n ```\n\n The denodified function inherits from the original function. It works in all\n environments, except IE 10 and below. Consequently all properties of the original\n function are available to you. However, any properties you change on the\n denodeified function won't be changed on the original function. Example:\n\n ```javascript\n let request = RSVP.denodeify(require('request')),\n cookieJar = request.jar(); // <- Inheritance is used here\n\n request('http://example.com', {jar: cookieJar}).then(function(res) {\n // cookieJar.cookies holds now the cookies returned by example.com\n });\n ```\n\n Using `denodeify` makes it easier to compose asynchronous operations instead\n of using callbacks. For example, instead of:\n\n ```javascript\n let fs = require('fs');\n\n fs.readFile('myfile.txt', function(err, data){\n if (err) { ... } // Handle error\n fs.writeFile('myfile2.txt', data, function(err){\n if (err) { ... } // Handle error\n console.log('done')\n });\n });\n ```\n\n you can chain the operations together using `then` from the returned promise:\n\n ```javascript\n let fs = require('fs');\n let readFile = RSVP.denodeify(fs.readFile);\n let writeFile = RSVP.denodeify(fs.writeFile);\n\n readFile('myfile.txt').then(function(data){\n return writeFile('myfile2.txt', data);\n }).then(function(){\n console.log('done')\n }).catch(function(error){\n // Handle error\n });\n ```\n\n @method denodeify\n @static\n @for RSVP\n @param {Function} nodeFunc a 'node-style' function that takes a callback as\n its last argument. The callback expects an error to be passed as its first\n argument (if an error occurred, otherwise null), and the value from the\n operation as its second argument ('function(err, value){ }').\n @param {Boolean|Array} [options] An optional paramter that if set\n to `true` causes the promise to fulfill with the callback's success arguments\n as an array. This is useful if the node function has multiple success\n paramters. If you set this paramter to an array with names, the promise will\n fulfill with a hash with these names as keys and the success parameters as\n values.\n @return {Function} a function that wraps `nodeFunc` to return an\n `RSVP.Promise`\n @static\n*/\nfunction denodeify(nodeFunc, options) {\n var fn = function fn() {\n var self = this;\n var l = arguments.length;\n var args = new Array(l + 1);\n var promiseInput = false;\n\n for (var i = 0; i < l; ++i) {\n var arg = arguments[i];\n\n if (!promiseInput) {\n // TODO: clean this up\n promiseInput = needsPromiseInput(arg);\n if (promiseInput === GET_THEN_ERROR$1) {\n var p = new Promise(noop);\n reject(p, GET_THEN_ERROR$1.value);\n return p;\n } else if (promiseInput && promiseInput !== true) {\n arg = wrapThenable(promiseInput, arg);\n }\n }\n args[i] = arg;\n }\n\n var promise = new Promise(noop);\n\n args[l] = function (err, val) {\n if (err) reject(promise, err);else if (options === undefined) resolve(promise, val);else if (options === true) resolve(promise, arrayResult(arguments));else if (isArray(options)) resolve(promise, makeObject(arguments, options));else resolve(promise, val);\n };\n\n if (promiseInput) {\n return handlePromiseInput(promise, args, nodeFunc, self);\n } else {\n return handleValueInput(promise, args, nodeFunc, self);\n }\n };\n\n fn.__proto__ = nodeFunc;\n\n return fn;\n}\n\nfunction handleValueInput(promise, args, nodeFunc, self) {\n var result = tryApply(nodeFunc, self, args);\n if (result === ERROR) {\n reject(promise, result.value);\n }\n return promise;\n}\n\nfunction handlePromiseInput(promise, args, nodeFunc, self) {\n return Promise.all(args).then(function (args) {\n var result = tryApply(nodeFunc, self, args);\n if (result === ERROR) {\n reject(promise, result.value);\n }\n return promise;\n });\n}\n\nfunction needsPromiseInput(arg) {\n if (arg && typeof arg === 'object') {\n if (arg.constructor === Promise) {\n return true;\n } else {\n return getThen$1(arg);\n }\n } else {\n return false;\n }\n}\n\n/**\n This is a convenient alias for `RSVP.Promise.all`.\n\n @method all\n @static\n @for RSVP\n @param {Array} array Array of promises.\n @param {String} label An optional label. This is useful\n for tooling.\n*/\nfunction all$1(array, label) {\n return Promise.all(array, label);\n}\n\nfunction AllSettled(Constructor, entries, label) {\n this._superConstructor(Constructor, entries, false, /* don't abort on reject */label);\n}\n\nAllSettled.prototype = o_create(Enumerator.prototype);\nAllSettled.prototype._superConstructor = Enumerator;\nAllSettled.prototype._makeResult = makeSettledResult;\nAllSettled.prototype._validationError = function () {\n return new Error('allSettled must be called with an array');\n};\n\n/**\n `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing\n a fail-fast method, it waits until all the promises have returned and\n shows you all the results. This is useful if you want to handle multiple\n promises' failure states together as a set.\n\n Returns a promise that is fulfilled when all the given promises have been\n settled. The return promise is fulfilled with an array of the states of\n the promises passed into the `promises` array argument.\n\n Each state object will either indicate fulfillment or rejection, and\n provide the corresponding value or reason. The states will take one of\n the following formats:\n\n ```javascript\n { state: 'fulfilled', value: value }\n or\n { state: 'rejected', reason: reason }\n ```\n\n Example:\n\n ```javascript\n let promise1 = RSVP.Promise.resolve(1);\n let promise2 = RSVP.Promise.reject(new Error('2'));\n let promise3 = RSVP.Promise.reject(new Error('3'));\n let promises = [ promise1, promise2, promise3 ];\n\n RSVP.allSettled(promises).then(function(array){\n // array == [\n // { state: 'fulfilled', value: 1 },\n // { state: 'rejected', reason: Error },\n // { state: 'rejected', reason: Error }\n // ]\n // Note that for the second item, reason.message will be '2', and for the\n // third item, reason.message will be '3'.\n }, function(error) {\n // Not run. (This block would only be called if allSettled had failed,\n // for instance if passed an incorrect argument type.)\n });\n ```\n\n @method allSettled\n @static\n @for RSVP\n @param {Array} entries\n @param {String} label - optional string that describes the promise.\n Useful for tooling.\n @return {Promise} promise that is fulfilled with an array of the settled\n states of the constituent promises.\n*/\nfunction allSettled(entries, label) {\n return new AllSettled(Promise, entries, label).promise;\n}\n\n/**\n This is a convenient alias for `RSVP.Promise.race`.\n\n @method race\n @static\n @for RSVP\n @param {Array} array Array of promises.\n @param {String} label An optional label. This is useful\n for tooling.\n */\nfunction race$1(array, label) {\n return Promise.race(array, label);\n}\n\nfunction PromiseHash(Constructor, object, label) {\n this._superConstructor(Constructor, object, true, label);\n}\n\nPromiseHash.prototype = o_create(Enumerator.prototype);\nPromiseHash.prototype._superConstructor = Enumerator;\nPromiseHash.prototype._init = function () {\n this._result = {};\n};\n\nPromiseHash.prototype._validateInput = function (input) {\n return input && typeof input === 'object';\n};\n\nPromiseHash.prototype._validationError = function () {\n return new Error('Promise.hash must be called with an object');\n};\n\nPromiseHash.prototype._enumerate = function () {\n var enumerator = this;\n var promise = enumerator.promise;\n var input = enumerator._input;\n var results = [];\n\n for (var key in input) {\n if (promise._state === PENDING && Object.prototype.hasOwnProperty.call(input, key)) {\n results.push({\n position: key,\n entry: input[key]\n });\n }\n }\n\n var length = results.length;\n enumerator._remaining = length;\n var result = undefined;\n\n for (var i = 0; promise._state === PENDING && i < length; i++) {\n result = results[i];\n enumerator._eachEntry(result.entry, result.position);\n }\n};\n\n/**\n `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array\n for its `promises` argument.\n\n Returns a promise that is fulfilled when all the given promises have been\n fulfilled, or rejected if any of them become rejected. The returned promise\n is fulfilled with a hash that has the same key names as the `promises` object\n argument. If any of the values in the object are not promises, they will\n simply be copied over to the fulfilled object.\n\n Example:\n\n ```javascript\n let promises = {\n myPromise: RSVP.resolve(1),\n yourPromise: RSVP.resolve(2),\n theirPromise: RSVP.resolve(3),\n notAPromise: 4\n };\n\n RSVP.hash(promises).then(function(hash){\n // hash here is an object that looks like:\n // {\n // myPromise: 1,\n // yourPromise: 2,\n // theirPromise: 3,\n // notAPromise: 4\n // }\n });\n ````\n\n If any of the `promises` given to `RSVP.hash` are rejected, the first promise\n that is rejected will be given as the reason to the rejection handler.\n\n Example:\n\n ```javascript\n let promises = {\n myPromise: RSVP.resolve(1),\n rejectedPromise: RSVP.reject(new Error('rejectedPromise')),\n anotherRejectedPromise: RSVP.reject(new Error('anotherRejectedPromise')),\n };\n\n RSVP.hash(promises).then(function(hash){\n // Code here never runs because there are rejected promises!\n }, function(reason) {\n // reason.message === 'rejectedPromise'\n });\n ```\n\n An important note: `RSVP.hash` is intended for plain JavaScript objects that\n are just a set of keys and values. `RSVP.hash` will NOT preserve prototype\n chains.\n\n Example:\n\n ```javascript\n function MyConstructor(){\n this.example = RSVP.resolve('Example');\n }\n\n MyConstructor.prototype = {\n protoProperty: RSVP.resolve('Proto Property')\n };\n\n let myObject = new MyConstructor();\n\n RSVP.hash(myObject).then(function(hash){\n // protoProperty will not be present, instead you will just have an\n // object that looks like:\n // {\n // example: 'Example'\n // }\n //\n // hash.hasOwnProperty('protoProperty'); // false\n // 'undefined' === typeof hash.protoProperty\n });\n ```\n\n @method hash\n @static\n @for RSVP\n @param {Object} object\n @param {String} label optional string that describes the promise.\n Useful for tooling.\n @return {Promise} promise that is fulfilled when all properties of `promises`\n have been fulfilled, or rejected if any of them become rejected.\n*/\nfunction hash(object, label) {\n return new PromiseHash(Promise, object, label).promise;\n}\n\nfunction HashSettled(Constructor, object, label) {\n this._superConstructor(Constructor, object, false, label);\n}\n\nHashSettled.prototype = o_create(PromiseHash.prototype);\nHashSettled.prototype._superConstructor = Enumerator;\nHashSettled.prototype._makeResult = makeSettledResult;\n\nHashSettled.prototype._validationError = function () {\n return new Error('hashSettled must be called with an object');\n};\n\n/**\n `RSVP.hashSettled` is similar to `RSVP.allSettled`, but takes an object\n instead of an array for its `promises` argument.\n\n Unlike `RSVP.all` or `RSVP.hash`, which implement a fail-fast method,\n but like `RSVP.allSettled`, `hashSettled` waits until all the\n constituent promises have returned and then shows you all the results\n with their states and values/reasons. This is useful if you want to\n handle multiple promises' failure states together as a set.\n\n Returns a promise that is fulfilled when all the given promises have been\n settled, or rejected if the passed parameters are invalid.\n\n The returned promise is fulfilled with a hash that has the same key names as\n the `promises` object argument. If any of the values in the object are not\n promises, they will be copied over to the fulfilled object and marked with state\n 'fulfilled'.\n\n Example:\n\n ```javascript\n let promises = {\n myPromise: RSVP.Promise.resolve(1),\n yourPromise: RSVP.Promise.resolve(2),\n theirPromise: RSVP.Promise.resolve(3),\n notAPromise: 4\n };\n\n RSVP.hashSettled(promises).then(function(hash){\n // hash here is an object that looks like:\n // {\n // myPromise: { state: 'fulfilled', value: 1 },\n // yourPromise: { state: 'fulfilled', value: 2 },\n // theirPromise: { state: 'fulfilled', value: 3 },\n // notAPromise: { state: 'fulfilled', value: 4 }\n // }\n });\n ```\n\n If any of the `promises` given to `RSVP.hash` are rejected, the state will\n be set to 'rejected' and the reason for rejection provided.\n\n Example:\n\n ```javascript\n let promises = {\n myPromise: RSVP.Promise.resolve(1),\n rejectedPromise: RSVP.Promise.reject(new Error('rejection')),\n anotherRejectedPromise: RSVP.Promise.reject(new Error('more rejection')),\n };\n\n RSVP.hashSettled(promises).then(function(hash){\n // hash here is an object that looks like:\n // {\n // myPromise: { state: 'fulfilled', value: 1 },\n // rejectedPromise: { state: 'rejected', reason: Error },\n // anotherRejectedPromise: { state: 'rejected', reason: Error },\n // }\n // Note that for rejectedPromise, reason.message == 'rejection',\n // and for anotherRejectedPromise, reason.message == 'more rejection'.\n });\n ```\n\n An important note: `RSVP.hashSettled` is intended for plain JavaScript objects that\n are just a set of keys and values. `RSVP.hashSettled` will NOT preserve prototype\n chains.\n\n Example:\n\n ```javascript\n function MyConstructor(){\n this.example = RSVP.Promise.resolve('Example');\n }\n\n MyConstructor.prototype = {\n protoProperty: RSVP.Promise.resolve('Proto Property')\n };\n\n let myObject = new MyConstructor();\n\n RSVP.hashSettled(myObject).then(function(hash){\n // protoProperty will not be present, instead you will just have an\n // object that looks like:\n // {\n // example: { state: 'fulfilled', value: 'Example' }\n // }\n //\n // hash.hasOwnProperty('protoProperty'); // false\n // 'undefined' === typeof hash.protoProperty\n });\n ```\n\n @method hashSettled\n @for RSVP\n @param {Object} object\n @param {String} label optional string that describes the promise.\n Useful for tooling.\n @return {Promise} promise that is fulfilled when when all properties of `promises`\n have been settled.\n @static\n*/\nfunction hashSettled(object, label) {\n return new HashSettled(Promise, object, label).promise;\n}\n\nfunction rethrow(reason) {\n setTimeout(function () {\n throw reason;\n });\n throw reason;\n}\n\n/**\n `RSVP.defer` returns an object similar to jQuery's `$.Deferred`.\n `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s\n interface. New code should use the `RSVP.Promise` constructor instead.\n\n The object returned from `RSVP.defer` is a plain object with three properties:\n\n * promise - an `RSVP.Promise`.\n * reject - a function that causes the `promise` property on this object to\n become rejected\n * resolve - a function that causes the `promise` property on this object to\n become fulfilled.\n\n Example:\n\n ```javascript\n let deferred = RSVP.defer();\n\n deferred.resolve(\"Success!\");\n\n deferred.promise.then(function(value){\n // value here is \"Success!\"\n });\n ```\n\n @method defer\n @static\n @for RSVP\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @return {Object}\n */\nfunction defer(label) {\n var deferred = { resolve: undefined, reject: undefined };\n\n deferred.promise = new Promise(function (resolve, reject) {\n deferred.resolve = resolve;\n deferred.reject = reject;\n }, label);\n\n return deferred;\n}\n\n/**\n `RSVP.map` is similar to JavaScript's native `map` method, except that it\n waits for all promises to become fulfilled before running the `mapFn` on\n each item in given to `promises`. `RSVP.map` returns a promise that will\n become fulfilled with the result of running `mapFn` on the values the promises\n become fulfilled with.\n\n For example:\n\n ```javascript\n\n let promise1 = RSVP.resolve(1);\n let promise2 = RSVP.resolve(2);\n let promise3 = RSVP.resolve(3);\n let promises = [ promise1, promise2, promise3 ];\n\n let mapFn = function(item){\n return item + 1;\n };\n\n RSVP.map(promises, mapFn).then(function(result){\n // result is [ 2, 3, 4 ]\n });\n ```\n\n If any of the `promises` given to `RSVP.map` are rejected, the first promise\n that is rejected will be given as an argument to the returned promise's\n rejection handler. For example:\n\n ```javascript\n let promise1 = RSVP.resolve(1);\n let promise2 = RSVP.reject(new Error('2'));\n let promise3 = RSVP.reject(new Error('3'));\n let promises = [ promise1, promise2, promise3 ];\n\n let mapFn = function(item){\n return item + 1;\n };\n\n RSVP.map(promises, mapFn).then(function(array){\n // Code here never runs because there are rejected promises!\n }, function(reason) {\n // reason.message === '2'\n });\n ```\n\n `RSVP.map` will also wait if a promise is returned from `mapFn`. For example,\n say you want to get all comments from a set of blog posts, but you need\n the blog posts first because they contain a url to those comments.\n\n ```javscript\n\n let mapFn = function(blogPost){\n // getComments does some ajax and returns an RSVP.Promise that is fulfilled\n // with some comments data\n return getComments(blogPost.comments_url);\n };\n\n // getBlogPosts does some ajax and returns an RSVP.Promise that is fulfilled\n // with some blog post data\n RSVP.map(getBlogPosts(), mapFn).then(function(comments){\n // comments is the result of asking the server for the comments\n // of all blog posts returned from getBlogPosts()\n });\n ```\n\n @method map\n @static\n @for RSVP\n @param {Array} promises\n @param {Function} mapFn function to be called on each fulfilled promise.\n @param {String} label optional string for labeling the promise.\n Useful for tooling.\n @return {Promise} promise that is fulfilled with the result of calling\n `mapFn` on each fulfilled promise or value when they become fulfilled.\n The promise will be rejected if any of the given `promises` become rejected.\n @static\n*/\nfunction map(promises, mapFn, label) {\n return Promise.all(promises, label).then(function (values) {\n if (!isFunction(mapFn)) {\n throw new TypeError(\"You must pass a function as map's second argument.\");\n }\n\n var length = values.length;\n var results = new Array(length);\n\n for (var i = 0; i < length; i++) {\n results[i] = mapFn(values[i]);\n }\n\n return Promise.all(results, label);\n });\n}\n\n/**\n This is a convenient alias for `RSVP.Promise.resolve`.\n\n @method resolve\n @static\n @for RSVP\n @param {*} value value that the returned promise will be resolved with\n @param {String} label optional string for identifying the returned promise.\n Useful for tooling.\n @return {Promise} a promise that will become fulfilled with the given\n `value`\n*/\nfunction resolve$2(value, label) {\n return Promise.resolve(value, label);\n}\n\n/**\n This is a convenient alias for `RSVP.Promise.reject`.\n\n @method reject\n @static\n @for RSVP\n @param {*} reason value that the returned promise will be rejected with.\n @param {String} label optional string for identifying the returned promise.\n Useful for tooling.\n @return {Promise} a promise rejected with the given `reason`.\n*/\nfunction reject$2(reason, label) {\n return Promise.reject(reason, label);\n}\n\n/**\n `RSVP.filter` is similar to JavaScript's native `filter` method, except that it\n waits for all promises to become fulfilled before running the `filterFn` on\n each item in given to `promises`. `RSVP.filter` returns a promise that will\n become fulfilled with the result of running `filterFn` on the values the\n promises become fulfilled with.\n\n For example:\n\n ```javascript\n\n let promise1 = RSVP.resolve(1);\n let promise2 = RSVP.resolve(2);\n let promise3 = RSVP.resolve(3);\n\n let promises = [promise1, promise2, promise3];\n\n let filterFn = function(item){\n return item > 1;\n };\n\n RSVP.filter(promises, filterFn).then(function(result){\n // result is [ 2, 3 ]\n });\n ```\n\n If any of the `promises` given to `RSVP.filter` are rejected, the first promise\n that is rejected will be given as an argument to the returned promise's\n rejection handler. For example:\n\n ```javascript\n let promise1 = RSVP.resolve(1);\n let promise2 = RSVP.reject(new Error('2'));\n let promise3 = RSVP.reject(new Error('3'));\n let promises = [ promise1, promise2, promise3 ];\n\n let filterFn = function(item){\n return item > 1;\n };\n\n RSVP.filter(promises, filterFn).then(function(array){\n // Code here never runs because there are rejected promises!\n }, function(reason) {\n // reason.message === '2'\n });\n ```\n\n `RSVP.filter` will also wait for any promises returned from `filterFn`.\n For instance, you may want to fetch a list of users then return a subset\n of those users based on some asynchronous operation:\n\n ```javascript\n\n let alice = { name: 'alice' };\n let bob = { name: 'bob' };\n let users = [ alice, bob ];\n\n let promises = users.map(function(user){\n return RSVP.resolve(user);\n });\n\n let filterFn = function(user){\n // Here, Alice has permissions to create a blog post, but Bob does not.\n return getPrivilegesForUser(user).then(function(privs){\n return privs.can_create_blog_post === true;\n });\n };\n RSVP.filter(promises, filterFn).then(function(users){\n // true, because the server told us only Alice can create a blog post.\n users.length === 1;\n // false, because Alice is the only user present in `users`\n users[0] === bob;\n });\n ```\n\n @method filter\n @static\n @for RSVP\n @param {Array} promises\n @param {Function} filterFn - function to be called on each resolved value to\n filter the final results.\n @param {String} label optional string describing the promise. Useful for\n tooling.\n @return {Promise}\n*/\n\nfunction resolveAll(promises, label) {\n return Promise.all(promises, label);\n}\n\nfunction resolveSingle(promise, label) {\n return Promise.resolve(promise, label).then(function (promises) {\n return resolveAll(promises, label);\n });\n}\nfunction filter(promises, filterFn, label) {\n var promise = isArray(promises) ? resolveAll(promises, label) : resolveSingle(promises, label);\n return promise.then(function (values) {\n if (!isFunction(filterFn)) {\n throw new TypeError(\"You must pass a function as filter's second argument.\");\n }\n\n var length = values.length;\n var filtered = new Array(length);\n\n for (var i = 0; i < length; i++) {\n filtered[i] = filterFn(values[i]);\n }\n\n return resolveAll(filtered, label).then(function (filtered) {\n var results = new Array(length);\n var newLength = 0;\n\n for (var i = 0; i < length; i++) {\n if (filtered[i]) {\n results[newLength] = values[i];\n newLength++;\n }\n }\n\n results.length = newLength;\n\n return results;\n });\n });\n}\n\nvar len = 0;\nvar vertxNext = undefined;\nfunction asap(callback, arg) {\n queue$1[len] = callback;\n queue$1[len + 1] = arg;\n len += 2;\n if (len === 2) {\n // If len is 1, that means that we need to schedule an async flush.\n // If additional callbacks are queued before the queue is flushed, they\n // will be processed by this flush that we are scheduling.\n scheduleFlush$1();\n }\n}\n\nvar browserWindow = typeof window !== 'undefined' ? window : undefined;\nvar browserGlobal = browserWindow || {};\nvar BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;\nvar isNode = typeof self === 'undefined' && typeof process !== 'undefined' && ({}).toString.call(process) === '[object process]';\n\n// test for web worker but not in IE10\nvar isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';\n\n// node\nfunction useNextTick() {\n var nextTick = process.nextTick;\n // node version 0.10.x displays a deprecation warning when nextTick is used recursively\n // setImmediate should be used instead instead\n var version = process.versions.node.match(/^(?:(\\d+)\\.)?(?:(\\d+)\\.)?(\\*|\\d+)$/);\n if (Array.isArray(version) && version[1] === '0' && version[2] === '10') {\n nextTick = setImmediate;\n }\n return function () {\n return nextTick(flush);\n };\n}\n\n// vertx\nfunction useVertxTimer() {\n return function () {\n return vertxNext(flush);\n };\n}\n\nfunction useMutationObserver() {\n var iterations = 0;\n var observer = new BrowserMutationObserver(flush);\n var node = document.createTextNode('');\n observer.observe(node, { characterData: true });\n\n return function () {\n return node.data = iterations = ++iterations % 2;\n };\n}\n\n// web worker\nfunction useMessageChannel() {\n var channel = new MessageChannel();\n channel.port1.onmessage = flush;\n return function () {\n return channel.port2.postMessage(0);\n };\n}\n\nfunction useSetTimeout() {\n return function () {\n return setTimeout(flush, 1);\n };\n}\n\nvar queue$1 = new Array(1000);\n\nfunction flush() {\n for (var i = 0; i < len; i += 2) {\n var callback = queue$1[i];\n var arg = queue$1[i + 1];\n\n callback(arg);\n\n queue$1[i] = undefined;\n queue$1[i + 1] = undefined;\n }\n\n len = 0;\n}\n\nfunction attemptVertex() {\n try {\n var r = require;\n var vertx = r('vertx');\n vertxNext = vertx.runOnLoop || vertx.runOnContext;\n return useVertxTimer();\n } catch (e) {\n return useSetTimeout();\n }\n}\n\nvar scheduleFlush$1 = undefined;\n// Decide what async method to use to triggering processing of queued callbacks:\nif (isNode) {\n scheduleFlush$1 = useNextTick();\n} else if (BrowserMutationObserver) {\n scheduleFlush$1 = useMutationObserver();\n} else if (isWorker) {\n scheduleFlush$1 = useMessageChannel();\n} else if (browserWindow === undefined && typeof require === 'function') {\n scheduleFlush$1 = attemptVertex();\n} else {\n scheduleFlush$1 = useSetTimeout();\n}\n\nvar platform = undefined;\n\n/* global self */\nif (typeof self === 'object') {\n platform = self;\n\n /* global global */\n} else if (typeof global === 'object') {\n platform = global;\n } else {\n throw new Error('no global: `self` or `global` found');\n }\n\nvar _async$filter;\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n// defaults\n\n// the default export here is for backwards compat:\n// https://github.com/tildeio/rsvp.js/issues/434\nconfig.async = asap;\nconfig.after = function (cb) {\n return setTimeout(cb, 0);\n};\nvar cast = resolve$2;\n\nvar async = function async(callback, arg) {\n return config.async(callback, arg);\n};\n\nfunction on() {\n config['on'].apply(config, arguments);\n}\n\nfunction off() {\n config['off'].apply(config, arguments);\n}\n\n// Set up instrumentation through `window.__PROMISE_INTRUMENTATION__`\nif (typeof window !== 'undefined' && typeof window['__PROMISE_INSTRUMENTATION__'] === 'object') {\n var callbacks = window['__PROMISE_INSTRUMENTATION__'];\n configure('instrument', true);\n for (var eventName in callbacks) {\n if (callbacks.hasOwnProperty(eventName)) {\n on(eventName, callbacks[eventName]);\n }\n }\n}var rsvp = (_async$filter = {\n cast: cast,\n Promise: Promise,\n EventTarget: EventTarget,\n all: all$1,\n allSettled: allSettled,\n race: race$1,\n hash: hash,\n hashSettled: hashSettled,\n rethrow: rethrow,\n defer: defer,\n denodeify: denodeify,\n configure: configure,\n on: on,\n off: off,\n resolve: resolve$2,\n reject: reject$2,\n map: map\n}, _defineProperty(_async$filter, 'async', async), _defineProperty(_async$filter, 'filter', // babel seems to error if async isn't a computed prop here...\nfilter), _async$filter);\n\nexports['default'] = rsvp;\nexports.cast = cast;\nexports.Promise = Promise;\nexports.EventTarget = EventTarget;\nexports.all = all$1;\nexports.allSettled = allSettled;\nexports.race = race$1;\nexports.hash = hash;\nexports.hashSettled = hashSettled;\nexports.rethrow = rethrow;\nexports.defer = defer;\nexports.denodeify = denodeify;\nexports.configure = configure;\nexports.on = on;\nexports.off = off;\nexports.resolve = resolve$2;\nexports.reject = reject$2;\nexports.map = map;\nexports.async = async;\nexports.filter = filter;\n\nObject.defineProperty(exports, '__esModule', { value: true });\n\n})));\n//# sourceMappingURL=rsvp.map","/*!\n * URI.js - Mutating URLs\n * Second Level Domain (SLD) Support\n *\n * Version: 1.18.1\n *\n * Author: Rodney Rehm\n * Web: http://medialize.github.io/URI.js/\n *\n * Licensed under\n * MIT License http://www.opensource.org/licenses/mit-license\n *\n */\n\n(function (root, factory) {\n 'use strict';\n // https://github.com/umdjs/umd/blob/master/returnExports.js\n if (typeof exports === 'object') {\n // Node\n module.exports = factory();\n } else if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define(factory);\n } else {\n // Browser globals (root is window)\n root.SecondLevelDomains = factory(root);\n }\n}(this, function (root) {\n 'use strict';\n\n // save current SecondLevelDomains variable, if any\n var _SecondLevelDomains = root && root.SecondLevelDomains;\n\n var SLD = {\n // list of known Second Level Domains\n // converted list of SLDs from https://github.com/gavingmiller/second-level-domains\n // ----\n // publicsuffix.org is more current and actually used by a couple of browsers internally.\n // downside is it also contains domains like \"dyndns.org\" - which is fine for the security\n // issues browser have to deal with (SOP for cookies, etc) - but is way overboard for URI.js\n // ----\n list: {\n 'ac':' com gov mil net org ',\n 'ae':' ac co gov mil name net org pro sch ',\n 'af':' com edu gov net org ',\n 'al':' com edu gov mil net org ',\n 'ao':' co ed gv it og pb ',\n 'ar':' com edu gob gov int mil net org tur ',\n 'at':' ac co gv or ',\n 'au':' asn com csiro edu gov id net org ',\n 'ba':' co com edu gov mil net org rs unbi unmo unsa untz unze ',\n 'bb':' biz co com edu gov info net org store tv ',\n 'bh':' biz cc com edu gov info net org ',\n 'bn':' com edu gov net org ',\n 'bo':' com edu gob gov int mil net org tv ',\n 'br':' adm adv agr am arq art ato b bio blog bmd cim cng cnt com coop ecn edu eng esp etc eti far flog fm fnd fot fst g12 ggf gov imb ind inf jor jus lel mat med mil mus net nom not ntr odo org ppg pro psc psi qsl rec slg srv tmp trd tur tv vet vlog wiki zlg ',\n 'bs':' com edu gov net org ',\n 'bz':' du et om ov rg ',\n 'ca':' ab bc mb nb nf nl ns nt nu on pe qc sk yk ',\n 'ck':' biz co edu gen gov info net org ',\n 'cn':' ac ah bj com cq edu fj gd gov gs gx gz ha hb he hi hl hn jl js jx ln mil net nm nx org qh sc sd sh sn sx tj tw xj xz yn zj ',\n 'co':' com edu gov mil net nom org ',\n 'cr':' ac c co ed fi go or sa ',\n 'cy':' ac biz com ekloges gov ltd name net org parliament press pro tm ',\n 'do':' art com edu gob gov mil net org sld web ',\n 'dz':' art asso com edu gov net org pol ',\n 'ec':' com edu fin gov info med mil net org pro ',\n 'eg':' com edu eun gov mil name net org sci ',\n 'er':' com edu gov ind mil net org rochest w ',\n 'es':' com edu gob nom org ',\n 'et':' biz com edu gov info name net org ',\n 'fj':' ac biz com info mil name net org pro ',\n 'fk':' ac co gov net nom org ',\n 'fr':' asso com f gouv nom prd presse tm ',\n 'gg':' co net org ',\n 'gh':' com edu gov mil org ',\n 'gn':' ac com gov net org ',\n 'gr':' com edu gov mil net org ',\n 'gt':' com edu gob ind mil net org ',\n 'gu':' com edu gov net org ',\n 'hk':' com edu gov idv net org ',\n 'hu':' 2000 agrar bolt casino city co erotica erotika film forum games hotel info ingatlan jogasz konyvelo lakas media news org priv reklam sex shop sport suli szex tm tozsde utazas video ',\n 'id':' ac co go mil net or sch web ',\n 'il':' ac co gov idf k12 muni net org ',\n 'in':' ac co edu ernet firm gen gov i ind mil net nic org res ',\n 'iq':' com edu gov i mil net org ',\n 'ir':' ac co dnssec gov i id net org sch ',\n 'it':' edu gov ',\n 'je':' co net org ',\n 'jo':' com edu gov mil name net org sch ',\n 'jp':' ac ad co ed go gr lg ne or ',\n 'ke':' ac co go info me mobi ne or sc ',\n 'kh':' com edu gov mil net org per ',\n 'ki':' biz com de edu gov info mob net org tel ',\n 'km':' asso com coop edu gouv k medecin mil nom notaires pharmaciens presse tm veterinaire ',\n 'kn':' edu gov net org ',\n 'kr':' ac busan chungbuk chungnam co daegu daejeon es gangwon go gwangju gyeongbuk gyeonggi gyeongnam hs incheon jeju jeonbuk jeonnam k kg mil ms ne or pe re sc seoul ulsan ',\n 'kw':' com edu gov net org ',\n 'ky':' com edu gov net org ',\n 'kz':' com edu gov mil net org ',\n 'lb':' com edu gov net org ',\n 'lk':' assn com edu gov grp hotel int ltd net ngo org sch soc web ',\n 'lr':' com edu gov net org ',\n 'lv':' asn com conf edu gov id mil net org ',\n 'ly':' com edu gov id med net org plc sch ',\n 'ma':' ac co gov m net org press ',\n 'mc':' asso tm ',\n 'me':' ac co edu gov its net org priv ',\n 'mg':' com edu gov mil nom org prd tm ',\n 'mk':' com edu gov inf name net org pro ',\n 'ml':' com edu gov net org presse ',\n 'mn':' edu gov org ',\n 'mo':' com edu gov net org ',\n 'mt':' com edu gov net org ',\n 'mv':' aero biz com coop edu gov info int mil museum name net org pro ',\n 'mw':' ac co com coop edu gov int museum net org ',\n 'mx':' com edu gob net org ',\n 'my':' com edu gov mil name net org sch ',\n 'nf':' arts com firm info net other per rec store web ',\n 'ng':' biz com edu gov mil mobi name net org sch ',\n 'ni':' ac co com edu gob mil net nom org ',\n 'np':' com edu gov mil net org ',\n 'nr':' biz com edu gov info net org ',\n 'om':' ac biz co com edu gov med mil museum net org pro sch ',\n 'pe':' com edu gob mil net nom org sld ',\n 'ph':' com edu gov i mil net ngo org ',\n 'pk':' biz com edu fam gob gok gon gop gos gov net org web ',\n 'pl':' art bialystok biz com edu gda gdansk gorzow gov info katowice krakow lodz lublin mil net ngo olsztyn org poznan pwr radom slupsk szczecin torun warszawa waw wroc wroclaw zgora ',\n 'pr':' ac biz com edu est gov info isla name net org pro prof ',\n 'ps':' com edu gov net org plo sec ',\n 'pw':' belau co ed go ne or ',\n 'ro':' arts com firm info nom nt org rec store tm www ',\n 'rs':' ac co edu gov in org ',\n 'sb':' com edu gov net org ',\n 'sc':' com edu gov net org ',\n 'sh':' co com edu gov net nom org ',\n 'sl':' com edu gov net org ',\n 'st':' co com consulado edu embaixada gov mil net org principe saotome store ',\n 'sv':' com edu gob org red ',\n 'sz':' ac co org ',\n 'tr':' av bbs bel biz com dr edu gen gov info k12 name net org pol tel tsk tv web ',\n 'tt':' aero biz cat co com coop edu gov info int jobs mil mobi museum name net org pro tel travel ',\n 'tw':' club com ebiz edu game gov idv mil net org ',\n 'mu':' ac co com gov net or org ',\n 'mz':' ac co edu gov org ',\n 'na':' co com ',\n 'nz':' ac co cri geek gen govt health iwi maori mil net org parliament school ',\n 'pa':' abo ac com edu gob ing med net nom org sld ',\n 'pt':' com edu gov int net nome org publ ',\n 'py':' com edu gov mil net org ',\n 'qa':' com edu gov mil net org ',\n 're':' asso com nom ',\n 'ru':' ac adygeya altai amur arkhangelsk astrakhan bashkiria belgorod bir bryansk buryatia cbg chel chelyabinsk chita chukotka chuvashia com dagestan e-burg edu gov grozny int irkutsk ivanovo izhevsk jar joshkar-ola kalmykia kaluga kamchatka karelia kazan kchr kemerovo khabarovsk khakassia khv kirov koenig komi kostroma kranoyarsk kuban kurgan kursk lipetsk magadan mari mari-el marine mil mordovia mosreg msk murmansk nalchik net nnov nov novosibirsk nsk omsk orenburg org oryol penza perm pp pskov ptz rnd ryazan sakhalin samara saratov simbirsk smolensk spb stavropol stv surgut tambov tatarstan tom tomsk tsaritsyn tsk tula tuva tver tyumen udm udmurtia ulan-ude vladikavkaz vladimir vladivostok volgograd vologda voronezh vrn vyatka yakutia yamal yekaterinburg yuzhno-sakhalinsk ',\n 'rw':' ac co com edu gouv gov int mil net ',\n 'sa':' com edu gov med net org pub sch ',\n 'sd':' com edu gov info med net org tv ',\n 'se':' a ac b bd c d e f g h i k l m n o org p parti pp press r s t tm u w x y z ',\n 'sg':' com edu gov idn net org per ',\n 'sn':' art com edu gouv org perso univ ',\n 'sy':' com edu gov mil net news org ',\n 'th':' ac co go in mi net or ',\n 'tj':' ac biz co com edu go gov info int mil name net nic org test web ',\n 'tn':' agrinet com defense edunet ens fin gov ind info intl mincom nat net org perso rnrt rns rnu tourism ',\n 'tz':' ac co go ne or ',\n 'ua':' biz cherkassy chernigov chernovtsy ck cn co com crimea cv dn dnepropetrovsk donetsk dp edu gov if in ivano-frankivsk kh kharkov kherson khmelnitskiy kiev kirovograd km kr ks kv lg lugansk lutsk lviv me mk net nikolaev od odessa org pl poltava pp rovno rv sebastopol sumy te ternopil uzhgorod vinnica vn zaporizhzhe zhitomir zp zt ',\n 'ug':' ac co go ne or org sc ',\n 'uk':' ac bl british-library co cym gov govt icnet jet lea ltd me mil mod national-library-scotland nel net nhs nic nls org orgn parliament plc police sch scot soc ',\n 'us':' dni fed isa kids nsn ',\n 'uy':' com edu gub mil net org ',\n 've':' co com edu gob info mil net org web ',\n 'vi':' co com k12 net org ',\n 'vn':' ac biz com edu gov health info int name net org pro ',\n 'ye':' co com gov ltd me net org plc ',\n 'yu':' ac co edu gov org ',\n 'za':' ac agric alt bourse city co cybernet db edu gov grondar iaccess imt inca landesign law mil net ngo nis nom olivetti org pix school tm web ',\n 'zm':' ac co com edu gov net org sch '\n },\n // gorhill 2013-10-25: Using indexOf() instead Regexp(). Significant boost\n // in both performance and memory footprint. No initialization required.\n // http://jsperf.com/uri-js-sld-regex-vs-binary-search/4\n // Following methods use lastIndexOf() rather than array.split() in order\n // to avoid any memory allocations.\n has: function(domain) {\n var tldOffset = domain.lastIndexOf('.');\n if (tldOffset <= 0 || tldOffset >= (domain.length-1)) {\n return false;\n }\n var sldOffset = domain.lastIndexOf('.', tldOffset-1);\n if (sldOffset <= 0 || sldOffset >= (tldOffset-1)) {\n return false;\n }\n var sldList = SLD.list[domain.slice(tldOffset+1)];\n if (!sldList) {\n return false;\n }\n return sldList.indexOf(' ' + domain.slice(sldOffset+1, tldOffset) + ' ') >= 0;\n },\n is: function(domain) {\n var tldOffset = domain.lastIndexOf('.');\n if (tldOffset <= 0 || tldOffset >= (domain.length-1)) {\n return false;\n }\n var sldOffset = domain.lastIndexOf('.', tldOffset-1);\n if (sldOffset >= 0) {\n return false;\n }\n var sldList = SLD.list[domain.slice(tldOffset+1)];\n if (!sldList) {\n return false;\n }\n return sldList.indexOf(' ' + domain.slice(0, tldOffset) + ' ') >= 0;\n },\n get: function(domain) {\n var tldOffset = domain.lastIndexOf('.');\n if (tldOffset <= 0 || tldOffset >= (domain.length-1)) {\n return null;\n }\n var sldOffset = domain.lastIndexOf('.', tldOffset-1);\n if (sldOffset <= 0 || sldOffset >= (tldOffset-1)) {\n return null;\n }\n var sldList = SLD.list[domain.slice(tldOffset+1)];\n if (!sldList) {\n return null;\n }\n if (sldList.indexOf(' ' + domain.slice(sldOffset+1, tldOffset) + ' ') < 0) {\n return null;\n }\n return domain.slice(sldOffset+1);\n },\n noConflict: function(){\n if (root.SecondLevelDomains === this) {\n root.SecondLevelDomains = _SecondLevelDomains;\n }\n return this;\n }\n };\n\n return SLD;\n}));\n","/*!\n * URI.js - Mutating URLs\n *\n * Version: 1.18.1\n *\n * Author: Rodney Rehm\n * Web: http://medialize.github.io/URI.js/\n *\n * Licensed under\n * MIT License http://www.opensource.org/licenses/mit-license\n *\n */\n(function (root, factory) {\n 'use strict';\n // https://github.com/umdjs/umd/blob/master/returnExports.js\n if (typeof exports === 'object') {\n // Node\n module.exports = factory(require('./punycode'), require('./IPv6'), require('./SecondLevelDomains'));\n } else if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define(['./punycode', './IPv6', './SecondLevelDomains'], factory);\n } else {\n // Browser globals (root is window)\n root.URI = factory(root.punycode, root.IPv6, root.SecondLevelDomains, root);\n }\n}(this, function (punycode, IPv6, SLD, root) {\n 'use strict';\n /*global location, escape, unescape */\n // FIXME: v2.0.0 renamce non-camelCase properties to uppercase\n /*jshint camelcase: false */\n\n // save current URI variable, if any\n var _URI = root && root.URI;\n\n function URI(url, base) {\n var _urlSupplied = arguments.length >= 1;\n var _baseSupplied = arguments.length >= 2;\n\n // Allow instantiation without the 'new' keyword\n if (!(this instanceof URI)) {\n if (_urlSupplied) {\n if (_baseSupplied) {\n return new URI(url, base);\n }\n\n return new URI(url);\n }\n\n return new URI();\n }\n\n if (url === undefined) {\n if (_urlSupplied) {\n throw new TypeError('undefined is not a valid argument for URI');\n }\n\n if (typeof location !== 'undefined') {\n url = location.href + '';\n } else {\n url = '';\n }\n }\n\n this.href(url);\n\n // resolve to base according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#constructor\n if (base !== undefined) {\n return this.absoluteTo(base);\n }\n\n return this;\n }\n\n URI.version = '1.18.1';\n\n var p = URI.prototype;\n var hasOwn = Object.prototype.hasOwnProperty;\n\n function escapeRegEx(string) {\n // https://github.com/medialize/URI.js/commit/85ac21783c11f8ccab06106dba9735a31a86924d#commitcomment-821963\n return string.replace(/([.*+?^=!:${}()|[\\]\\/\\\\])/g, '\\\\$1');\n }\n\n function getType(value) {\n // IE8 doesn't return [Object Undefined] but [Object Object] for undefined value\n if (value === undefined) {\n return 'Undefined';\n }\n\n return String(Object.prototype.toString.call(value)).slice(8, -1);\n }\n\n function isArray(obj) {\n return getType(obj) === 'Array';\n }\n\n function filterArrayValues(data, value) {\n var lookup = {};\n var i, length;\n\n if (getType(value) === 'RegExp') {\n lookup = null;\n } else if (isArray(value)) {\n for (i = 0, length = value.length; i < length; i++) {\n lookup[value[i]] = true;\n }\n } else {\n lookup[value] = true;\n }\n\n for (i = 0, length = data.length; i < length; i++) {\n /*jshint laxbreak: true */\n var _match = lookup && lookup[data[i]] !== undefined\n || !lookup && value.test(data[i]);\n /*jshint laxbreak: false */\n if (_match) {\n data.splice(i, 1);\n length--;\n i--;\n }\n }\n\n return data;\n }\n\n function arrayContains(list, value) {\n var i, length;\n\n // value may be string, number, array, regexp\n if (isArray(value)) {\n // Note: this can be optimized to O(n) (instead of current O(m * n))\n for (i = 0, length = value.length; i < length; i++) {\n if (!arrayContains(list, value[i])) {\n return false;\n }\n }\n\n return true;\n }\n\n var _type = getType(value);\n for (i = 0, length = list.length; i < length; i++) {\n if (_type === 'RegExp') {\n if (typeof list[i] === 'string' && list[i].match(value)) {\n return true;\n }\n } else if (list[i] === value) {\n return true;\n }\n }\n\n return false;\n }\n\n function arraysEqual(one, two) {\n if (!isArray(one) || !isArray(two)) {\n return false;\n }\n\n // arrays can't be equal if they have different amount of content\n if (one.length !== two.length) {\n return false;\n }\n\n one.sort();\n two.sort();\n\n for (var i = 0, l = one.length; i < l; i++) {\n if (one[i] !== two[i]) {\n return false;\n }\n }\n\n return true;\n }\n\n function trimSlashes(text) {\n var trim_expression = /^\\/+|\\/+$/g;\n return text.replace(trim_expression, '');\n }\n\n URI._parts = function() {\n return {\n protocol: null,\n username: null,\n password: null,\n hostname: null,\n urn: null,\n port: null,\n path: null,\n query: null,\n fragment: null,\n // state\n duplicateQueryParameters: URI.duplicateQueryParameters,\n escapeQuerySpace: URI.escapeQuerySpace\n };\n };\n // state: allow duplicate query parameters (a=1&a=1)\n URI.duplicateQueryParameters = false;\n // state: replaces + with %20 (space in query strings)\n URI.escapeQuerySpace = true;\n // static properties\n URI.protocol_expression = /^[a-z][a-z0-9.+-]*$/i;\n URI.idn_expression = /[^a-z0-9\\.-]/i;\n URI.punycode_expression = /(xn--)/i;\n // well, 333.444.555.666 matches, but it sure ain't no IPv4 - do we care?\n URI.ip4_expression = /^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/;\n // credits to Rich Brown\n // source: http://forums.intermapper.com/viewtopic.php?p=1096#1096\n // specification: http://www.ietf.org/rfc/rfc4291.txt\n URI.ip6_expression = /^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$/;\n // expression used is \"gruber revised\" (@gruber v2) determined to be the\n // best solution in a regex-golf we did a couple of ages ago at\n // * http://mathiasbynens.be/demo/url-regex\n // * http://rodneyrehm.de/t/url-regex.html\n URI.find_uri_expression = /\\b((?:[a-z][\\w-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'\".,<>?«»“”‘’]))/ig;\n URI.findUri = {\n // valid \"scheme://\" or \"www.\"\n start: /\\b(?:([a-z][a-z0-9.+-]*:\\/\\/)|www\\.)/gi,\n // everything up to the next whitespace\n end: /[\\s\\r\\n]|$/,\n // trim trailing punctuation captured by end RegExp\n trim: /[`!()\\[\\]{};:'\".,<>?«»“”„‘’]+$/\n };\n // http://www.iana.org/assignments/uri-schemes.html\n // http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers#Well-known_ports\n URI.defaultPorts = {\n http: '80',\n https: '443',\n ftp: '21',\n gopher: '70',\n ws: '80',\n wss: '443'\n };\n // allowed hostname characters according to RFC 3986\n // ALPHA DIGIT \"-\" \".\" \"_\" \"~\" \"!\" \"$\" \"&\" \"'\" \"(\" \")\" \"*\" \"+\" \",\" \";\" \"=\" %encoded\n // I've never seen a (non-IDN) hostname other than: ALPHA DIGIT . -\n URI.invalid_hostname_characters = /[^a-zA-Z0-9\\.-]/;\n // map DOM Elements to their URI attribute\n URI.domAttributes = {\n 'a': 'href',\n 'blockquote': 'cite',\n 'link': 'href',\n 'base': 'href',\n 'script': 'src',\n 'form': 'action',\n 'img': 'src',\n 'area': 'href',\n 'iframe': 'src',\n 'embed': 'src',\n 'source': 'src',\n 'track': 'src',\n 'input': 'src', // but only if type=\"image\"\n 'audio': 'src',\n 'video': 'src'\n };\n URI.getDomAttribute = function(node) {\n if (!node || !node.nodeName) {\n return undefined;\n }\n\n var nodeName = node.nodeName.toLowerCase();\n // should only expose src for type=\"image\"\n if (nodeName === 'input' && node.type !== 'image') {\n return undefined;\n }\n\n return URI.domAttributes[nodeName];\n };\n\n function escapeForDumbFirefox36(value) {\n // https://github.com/medialize/URI.js/issues/91\n return escape(value);\n }\n\n // encoding / decoding according to RFC3986\n function strictEncodeURIComponent(string) {\n // see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/encodeURIComponent\n return encodeURIComponent(string)\n .replace(/[!'()*]/g, escapeForDumbFirefox36)\n .replace(/\\*/g, '%2A');\n }\n URI.encode = strictEncodeURIComponent;\n URI.decode = decodeURIComponent;\n URI.iso8859 = function() {\n URI.encode = escape;\n URI.decode = unescape;\n };\n URI.unicode = function() {\n URI.encode = strictEncodeURIComponent;\n URI.decode = decodeURIComponent;\n };\n URI.characters = {\n pathname: {\n encode: {\n // RFC3986 2.1: For consistency, URI producers and normalizers should\n // use uppercase hexadecimal digits for all percent-encodings.\n expression: /%(24|26|2B|2C|3B|3D|3A|40)/ig,\n map: {\n // -._~!'()*\n '%24': '$',\n '%26': '&',\n '%2B': '+',\n '%2C': ',',\n '%3B': ';',\n '%3D': '=',\n '%3A': ':',\n '%40': '@'\n }\n },\n decode: {\n expression: /[\\/\\?#]/g,\n map: {\n '/': '%2F',\n '?': '%3F',\n '#': '%23'\n }\n }\n },\n reserved: {\n encode: {\n // RFC3986 2.1: For consistency, URI producers and normalizers should\n // use uppercase hexadecimal digits for all percent-encodings.\n expression: /%(21|23|24|26|27|28|29|2A|2B|2C|2F|3A|3B|3D|3F|40|5B|5D)/ig,\n map: {\n // gen-delims\n '%3A': ':',\n '%2F': '/',\n '%3F': '?',\n '%23': '#',\n '%5B': '[',\n '%5D': ']',\n '%40': '@',\n // sub-delims\n '%21': '!',\n '%24': '$',\n '%26': '&',\n '%27': '\\'',\n '%28': '(',\n '%29': ')',\n '%2A': '*',\n '%2B': '+',\n '%2C': ',',\n '%3B': ';',\n '%3D': '='\n }\n }\n },\n urnpath: {\n // The characters under `encode` are the characters called out by RFC 2141 as being acceptable\n // for usage in a URN. RFC2141 also calls out \"-\", \".\", and \"_\" as acceptable characters, but\n // these aren't encoded by encodeURIComponent, so we don't have to call them out here. Also\n // note that the colon character is not featured in the encoding map; this is because URI.js\n // gives the colons in URNs semantic meaning as the delimiters of path segements, and so it\n // should not appear unencoded in a segment itself.\n // See also the note above about RFC3986 and capitalalized hex digits.\n encode: {\n expression: /%(21|24|27|28|29|2A|2B|2C|3B|3D|40)/ig,\n map: {\n '%21': '!',\n '%24': '$',\n '%27': '\\'',\n '%28': '(',\n '%29': ')',\n '%2A': '*',\n '%2B': '+',\n '%2C': ',',\n '%3B': ';',\n '%3D': '=',\n '%40': '@'\n }\n },\n // These characters are the characters called out by RFC2141 as \"reserved\" characters that\n // should never appear in a URN, plus the colon character (see note above).\n decode: {\n expression: /[\\/\\?#:]/g,\n map: {\n '/': '%2F',\n '?': '%3F',\n '#': '%23',\n ':': '%3A'\n }\n }\n }\n };\n URI.encodeQuery = function(string, escapeQuerySpace) {\n var escaped = URI.encode(string + '');\n if (escapeQuerySpace === undefined) {\n escapeQuerySpace = URI.escapeQuerySpace;\n }\n\n return escapeQuerySpace ? escaped.replace(/%20/g, '+') : escaped;\n };\n URI.decodeQuery = function(string, escapeQuerySpace) {\n string += '';\n if (escapeQuerySpace === undefined) {\n escapeQuerySpace = URI.escapeQuerySpace;\n }\n\n try {\n return URI.decode(escapeQuerySpace ? string.replace(/\\+/g, '%20') : string);\n } catch(e) {\n // we're not going to mess with weird encodings,\n // give up and return the undecoded original string\n // see https://github.com/medialize/URI.js/issues/87\n // see https://github.com/medialize/URI.js/issues/92\n return string;\n }\n };\n // generate encode/decode path functions\n var _parts = {'encode':'encode', 'decode':'decode'};\n var _part;\n var generateAccessor = function(_group, _part) {\n return function(string) {\n try {\n return URI[_part](string + '').replace(URI.characters[_group][_part].expression, function(c) {\n return URI.characters[_group][_part].map[c];\n });\n } catch (e) {\n // we're not going to mess with weird encodings,\n // give up and return the undecoded original string\n // see https://github.com/medialize/URI.js/issues/87\n // see https://github.com/medialize/URI.js/issues/92\n return string;\n }\n };\n };\n\n for (_part in _parts) {\n URI[_part + 'PathSegment'] = generateAccessor('pathname', _parts[_part]);\n URI[_part + 'UrnPathSegment'] = generateAccessor('urnpath', _parts[_part]);\n }\n\n var generateSegmentedPathFunction = function(_sep, _codingFuncName, _innerCodingFuncName) {\n return function(string) {\n // Why pass in names of functions, rather than the function objects themselves? The\n // definitions of some functions (but in particular, URI.decode) will occasionally change due\n // to URI.js having ISO8859 and Unicode modes. Passing in the name and getting it will ensure\n // that the functions we use here are \"fresh\".\n var actualCodingFunc;\n if (!_innerCodingFuncName) {\n actualCodingFunc = URI[_codingFuncName];\n } else {\n actualCodingFunc = function(string) {\n return URI[_codingFuncName](URI[_innerCodingFuncName](string));\n };\n }\n\n var segments = (string + '').split(_sep);\n\n for (var i = 0, length = segments.length; i < length; i++) {\n segments[i] = actualCodingFunc(segments[i]);\n }\n\n return segments.join(_sep);\n };\n };\n\n // This takes place outside the above loop because we don't want, e.g., encodeUrnPath functions.\n URI.decodePath = generateSegmentedPathFunction('/', 'decodePathSegment');\n URI.decodeUrnPath = generateSegmentedPathFunction(':', 'decodeUrnPathSegment');\n URI.recodePath = generateSegmentedPathFunction('/', 'encodePathSegment', 'decode');\n URI.recodeUrnPath = generateSegmentedPathFunction(':', 'encodeUrnPathSegment', 'decode');\n\n URI.encodeReserved = generateAccessor('reserved', 'encode');\n\n URI.parse = function(string, parts) {\n var pos;\n if (!parts) {\n parts = {};\n }\n // [protocol\"://\"[username[\":\"password]\"@\"]hostname[\":\"port]\"/\"?][path][\"?\"querystring][\"#\"fragment]\n\n // extract fragment\n pos = string.indexOf('#');\n if (pos > -1) {\n // escaping?\n parts.fragment = string.substring(pos + 1) || null;\n string = string.substring(0, pos);\n }\n\n // extract query\n pos = string.indexOf('?');\n if (pos > -1) {\n // escaping?\n parts.query = string.substring(pos + 1) || null;\n string = string.substring(0, pos);\n }\n\n // extract protocol\n if (string.substring(0, 2) === '//') {\n // relative-scheme\n parts.protocol = null;\n string = string.substring(2);\n // extract \"user:pass@host:port\"\n string = URI.parseAuthority(string, parts);\n } else {\n pos = string.indexOf(':');\n if (pos > -1) {\n parts.protocol = string.substring(0, pos) || null;\n if (parts.protocol && !parts.protocol.match(URI.protocol_expression)) {\n // : may be within the path\n parts.protocol = undefined;\n } else if (string.substring(pos + 1, pos + 3) === '//') {\n string = string.substring(pos + 3);\n\n // extract \"user:pass@host:port\"\n string = URI.parseAuthority(string, parts);\n } else {\n string = string.substring(pos + 1);\n parts.urn = true;\n }\n }\n }\n\n // what's left must be the path\n parts.path = string;\n\n // and we're done\n return parts;\n };\n URI.parseHost = function(string, parts) {\n // Copy chrome, IE, opera backslash-handling behavior.\n // Back slashes before the query string get converted to forward slashes\n // See: https://github.com/joyent/node/blob/386fd24f49b0e9d1a8a076592a404168faeecc34/lib/url.js#L115-L124\n // See: https://code.google.com/p/chromium/issues/detail?id=25916\n // https://github.com/medialize/URI.js/pull/233\n string = string.replace(/\\\\/g, '/');\n\n // extract host:port\n var pos = string.indexOf('/');\n var bracketPos;\n var t;\n\n if (pos === -1) {\n pos = string.length;\n }\n\n if (string.charAt(0) === '[') {\n // IPv6 host - http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-04#section-6\n // I claim most client software breaks on IPv6 anyways. To simplify things, URI only accepts\n // IPv6+port in the format [2001:db8::1]:80 (for the time being)\n bracketPos = string.indexOf(']');\n parts.hostname = string.substring(1, bracketPos) || null;\n parts.port = string.substring(bracketPos + 2, pos) || null;\n if (parts.port === '/') {\n parts.port = null;\n }\n } else {\n var firstColon = string.indexOf(':');\n var firstSlash = string.indexOf('/');\n var nextColon = string.indexOf(':', firstColon + 1);\n if (nextColon !== -1 && (firstSlash === -1 || nextColon < firstSlash)) {\n // IPv6 host contains multiple colons - but no port\n // this notation is actually not allowed by RFC 3986, but we're a liberal parser\n parts.hostname = string.substring(0, pos) || null;\n parts.port = null;\n } else {\n t = string.substring(0, pos).split(':');\n parts.hostname = t[0] || null;\n parts.port = t[1] || null;\n }\n }\n\n if (parts.hostname && string.substring(pos).charAt(0) !== '/') {\n pos++;\n string = '/' + string;\n }\n\n return string.substring(pos) || '/';\n };\n URI.parseAuthority = function(string, parts) {\n string = URI.parseUserinfo(string, parts);\n return URI.parseHost(string, parts);\n };\n URI.parseUserinfo = function(string, parts) {\n // extract username:password\n var firstSlash = string.indexOf('/');\n var pos = string.lastIndexOf('@', firstSlash > -1 ? firstSlash : string.length - 1);\n var t;\n\n // authority@ must come before /path\n if (pos > -1 && (firstSlash === -1 || pos < firstSlash)) {\n t = string.substring(0, pos).split(':');\n parts.username = t[0] ? URI.decode(t[0]) : null;\n t.shift();\n parts.password = t[0] ? URI.decode(t.join(':')) : null;\n string = string.substring(pos + 1);\n } else {\n parts.username = null;\n parts.password = null;\n }\n\n return string;\n };\n URI.parseQuery = function(string, escapeQuerySpace) {\n if (!string) {\n return {};\n }\n\n // throw out the funky business - \"?\"[name\"=\"value\"&\"]+\n string = string.replace(/&+/g, '&').replace(/^\\?*&*|&+$/g, '');\n\n if (!string) {\n return {};\n }\n\n var items = {};\n var splits = string.split('&');\n var length = splits.length;\n var v, name, value;\n\n for (var i = 0; i < length; i++) {\n v = splits[i].split('=');\n name = URI.decodeQuery(v.shift(), escapeQuerySpace);\n // no \"=\" is null according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#collect-url-parameters\n value = v.length ? URI.decodeQuery(v.join('='), escapeQuerySpace) : null;\n\n if (hasOwn.call(items, name)) {\n if (typeof items[name] === 'string' || items[name] === null) {\n items[name] = [items[name]];\n }\n\n items[name].push(value);\n } else {\n items[name] = value;\n }\n }\n\n return items;\n };\n\n URI.build = function(parts) {\n var t = '';\n\n if (parts.protocol) {\n t += parts.protocol + ':';\n }\n\n if (!parts.urn && (t || parts.hostname)) {\n t += '//';\n }\n\n t += (URI.buildAuthority(parts) || '');\n\n if (typeof parts.path === 'string') {\n if (parts.path.charAt(0) !== '/' && typeof parts.hostname === 'string') {\n t += '/';\n }\n\n t += parts.path;\n }\n\n if (typeof parts.query === 'string' && parts.query) {\n t += '?' + parts.query;\n }\n\n if (typeof parts.fragment === 'string' && parts.fragment) {\n t += '#' + parts.fragment;\n }\n return t;\n };\n URI.buildHost = function(parts) {\n var t = '';\n\n if (!parts.hostname) {\n return '';\n } else if (URI.ip6_expression.test(parts.hostname)) {\n t += '[' + parts.hostname + ']';\n } else {\n t += parts.hostname;\n }\n\n if (parts.port) {\n t += ':' + parts.port;\n }\n\n return t;\n };\n URI.buildAuthority = function(parts) {\n return URI.buildUserinfo(parts) + URI.buildHost(parts);\n };\n URI.buildUserinfo = function(parts) {\n var t = '';\n\n if (parts.username) {\n t += URI.encode(parts.username);\n }\n\n if (parts.password) {\n t += ':' + URI.encode(parts.password);\n }\n\n if (t) {\n t += '@';\n }\n\n return t;\n };\n URI.buildQuery = function(data, duplicateQueryParameters, escapeQuerySpace) {\n // according to http://tools.ietf.org/html/rfc3986 or http://labs.apache.org/webarch/uri/rfc/rfc3986.html\n // being »-._~!$&'()*+,;=:@/?« %HEX and alnum are allowed\n // the RFC explicitly states ?/foo being a valid use case, no mention of parameter syntax!\n // URI.js treats the query string as being application/x-www-form-urlencoded\n // see http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type\n\n var t = '';\n var unique, key, i, length;\n for (key in data) {\n if (hasOwn.call(data, key) && key) {\n if (isArray(data[key])) {\n unique = {};\n for (i = 0, length = data[key].length; i < length; i++) {\n if (data[key][i] !== undefined && unique[data[key][i] + ''] === undefined) {\n t += '&' + URI.buildQueryParameter(key, data[key][i], escapeQuerySpace);\n if (duplicateQueryParameters !== true) {\n unique[data[key][i] + ''] = true;\n }\n }\n }\n } else if (data[key] !== undefined) {\n t += '&' + URI.buildQueryParameter(key, data[key], escapeQuerySpace);\n }\n }\n }\n\n return t.substring(1);\n };\n URI.buildQueryParameter = function(name, value, escapeQuerySpace) {\n // http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type -- application/x-www-form-urlencoded\n // don't append \"=\" for null values, according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#url-parameter-serialization\n return URI.encodeQuery(name, escapeQuerySpace) + (value !== null ? '=' + URI.encodeQuery(value, escapeQuerySpace) : '');\n };\n\n URI.addQuery = function(data, name, value) {\n if (typeof name === 'object') {\n for (var key in name) {\n if (hasOwn.call(name, key)) {\n URI.addQuery(data, key, name[key]);\n }\n }\n } else if (typeof name === 'string') {\n if (data[name] === undefined) {\n data[name] = value;\n return;\n } else if (typeof data[name] === 'string') {\n data[name] = [data[name]];\n }\n\n if (!isArray(value)) {\n value = [value];\n }\n\n data[name] = (data[name] || []).concat(value);\n } else {\n throw new TypeError('URI.addQuery() accepts an object, string as the name parameter');\n }\n };\n URI.removeQuery = function(data, name, value) {\n var i, length, key;\n\n if (isArray(name)) {\n for (i = 0, length = name.length; i < length; i++) {\n data[name[i]] = undefined;\n }\n } else if (getType(name) === 'RegExp') {\n for (key in data) {\n if (name.test(key)) {\n data[key] = undefined;\n }\n }\n } else if (typeof name === 'object') {\n for (key in name) {\n if (hasOwn.call(name, key)) {\n URI.removeQuery(data, key, name[key]);\n }\n }\n } else if (typeof name === 'string') {\n if (value !== undefined) {\n if (getType(value) === 'RegExp') {\n if (!isArray(data[name]) && value.test(data[name])) {\n data[name] = undefined;\n } else {\n data[name] = filterArrayValues(data[name], value);\n }\n } else if (data[name] === String(value) && (!isArray(value) || value.length === 1)) {\n data[name] = undefined;\n } else if (isArray(data[name])) {\n data[name] = filterArrayValues(data[name], value);\n }\n } else {\n data[name] = undefined;\n }\n } else {\n throw new TypeError('URI.removeQuery() accepts an object, string, RegExp as the first parameter');\n }\n };\n URI.hasQuery = function(data, name, value, withinArray) {\n switch (getType(name)) {\n case 'String':\n // Nothing to do here\n break;\n\n case 'RegExp':\n for (var key in data) {\n if (hasOwn.call(data, key)) {\n if (name.test(key) && (value === undefined || URI.hasQuery(data, key, value))) {\n return true;\n }\n }\n }\n\n return false;\n\n case 'Object':\n for (var _key in name) {\n if (hasOwn.call(name, _key)) {\n if (!URI.hasQuery(data, _key, name[_key])) {\n return false;\n }\n }\n }\n\n return true;\n\n default:\n throw new TypeError('URI.hasQuery() accepts a string, regular expression or object as the name parameter');\n }\n\n switch (getType(value)) {\n case 'Undefined':\n // true if exists (but may be empty)\n return name in data; // data[name] !== undefined;\n\n case 'Boolean':\n // true if exists and non-empty\n var _booly = Boolean(isArray(data[name]) ? data[name].length : data[name]);\n return value === _booly;\n\n case 'Function':\n // allow complex comparison\n return !!value(data[name], name, data);\n\n case 'Array':\n if (!isArray(data[name])) {\n return false;\n }\n\n var op = withinArray ? arrayContains : arraysEqual;\n return op(data[name], value);\n\n case 'RegExp':\n if (!isArray(data[name])) {\n return Boolean(data[name] && data[name].match(value));\n }\n\n if (!withinArray) {\n return false;\n }\n\n return arrayContains(data[name], value);\n\n case 'Number':\n value = String(value);\n /* falls through */\n case 'String':\n if (!isArray(data[name])) {\n return data[name] === value;\n }\n\n if (!withinArray) {\n return false;\n }\n\n return arrayContains(data[name], value);\n\n default:\n throw new TypeError('URI.hasQuery() accepts undefined, boolean, string, number, RegExp, Function as the value parameter');\n }\n };\n\n\n URI.joinPaths = function() {\n var input = [];\n var segments = [];\n var nonEmptySegments = 0;\n\n for (var i = 0; i < arguments.length; i++) {\n var url = new URI(arguments[i]);\n input.push(url);\n var _segments = url.segment();\n for (var s = 0; s < _segments.length; s++) {\n if (typeof _segments[s] === 'string') {\n segments.push(_segments[s]);\n }\n\n if (_segments[s]) {\n nonEmptySegments++;\n }\n }\n }\n\n if (!segments.length || !nonEmptySegments) {\n return new URI('');\n }\n\n var uri = new URI('').segment(segments);\n\n if (input[0].path() === '' || input[0].path().slice(0, 1) === '/') {\n uri.path('/' + uri.path());\n }\n\n return uri.normalize();\n };\n\n URI.commonPath = function(one, two) {\n var length = Math.min(one.length, two.length);\n var pos;\n\n // find first non-matching character\n for (pos = 0; pos < length; pos++) {\n if (one.charAt(pos) !== two.charAt(pos)) {\n pos--;\n break;\n }\n }\n\n if (pos < 1) {\n return one.charAt(0) === two.charAt(0) && one.charAt(0) === '/' ? '/' : '';\n }\n\n // revert to last /\n if (one.charAt(pos) !== '/' || two.charAt(pos) !== '/') {\n pos = one.substring(0, pos).lastIndexOf('/');\n }\n\n return one.substring(0, pos + 1);\n };\n\n URI.withinString = function(string, callback, options) {\n options || (options = {});\n var _start = options.start || URI.findUri.start;\n var _end = options.end || URI.findUri.end;\n var _trim = options.trim || URI.findUri.trim;\n var _attributeOpen = /[a-z0-9-]=[\"']?$/i;\n\n _start.lastIndex = 0;\n while (true) {\n var match = _start.exec(string);\n if (!match) {\n break;\n }\n\n var start = match.index;\n if (options.ignoreHtml) {\n // attribut(e=[\"']?$)\n var attributeOpen = string.slice(Math.max(start - 3, 0), start);\n if (attributeOpen && _attributeOpen.test(attributeOpen)) {\n continue;\n }\n }\n\n var end = start + string.slice(start).search(_end);\n var slice = string.slice(start, end).replace(_trim, '');\n if (options.ignore && options.ignore.test(slice)) {\n continue;\n }\n\n end = start + slice.length;\n var result = callback(slice, start, end, string);\n string = string.slice(0, start) + result + string.slice(end);\n _start.lastIndex = start + result.length;\n }\n\n _start.lastIndex = 0;\n return string;\n };\n\n URI.ensureValidHostname = function(v) {\n // Theoretically URIs allow percent-encoding in Hostnames (according to RFC 3986)\n // they are not part of DNS and therefore ignored by URI.js\n\n if (v.match(URI.invalid_hostname_characters)) {\n // test punycode\n if (!punycode) {\n throw new TypeError('Hostname \"' + v + '\" contains characters other than [A-Z0-9.-] and Punycode.js is not available');\n }\n\n if (punycode.toASCII(v).match(URI.invalid_hostname_characters)) {\n throw new TypeError('Hostname \"' + v + '\" contains characters other than [A-Z0-9.-]');\n }\n }\n };\n\n // noConflict\n URI.noConflict = function(removeAll) {\n if (removeAll) {\n var unconflicted = {\n URI: this.noConflict()\n };\n\n if (root.URITemplate && typeof root.URITemplate.noConflict === 'function') {\n unconflicted.URITemplate = root.URITemplate.noConflict();\n }\n\n if (root.IPv6 && typeof root.IPv6.noConflict === 'function') {\n unconflicted.IPv6 = root.IPv6.noConflict();\n }\n\n if (root.SecondLevelDomains && typeof root.SecondLevelDomains.noConflict === 'function') {\n unconflicted.SecondLevelDomains = root.SecondLevelDomains.noConflict();\n }\n\n return unconflicted;\n } else if (root.URI === this) {\n root.URI = _URI;\n }\n\n return this;\n };\n\n p.build = function(deferBuild) {\n if (deferBuild === true) {\n this._deferred_build = true;\n } else if (deferBuild === undefined || this._deferred_build) {\n this._string = URI.build(this._parts);\n this._deferred_build = false;\n }\n\n return this;\n };\n\n p.clone = function() {\n return new URI(this);\n };\n\n p.valueOf = p.toString = function() {\n return this.build(false)._string;\n };\n\n\n function generateSimpleAccessor(_part){\n return function(v, build) {\n if (v === undefined) {\n return this._parts[_part] || '';\n } else {\n this._parts[_part] = v || null;\n this.build(!build);\n return this;\n }\n };\n }\n\n function generatePrefixAccessor(_part, _key){\n return function(v, build) {\n if (v === undefined) {\n return this._parts[_part] || '';\n } else {\n if (v !== null) {\n v = v + '';\n if (v.charAt(0) === _key) {\n v = v.substring(1);\n }\n }\n\n this._parts[_part] = v;\n this.build(!build);\n return this;\n }\n };\n }\n\n p.protocol = generateSimpleAccessor('protocol');\n p.username = generateSimpleAccessor('username');\n p.password = generateSimpleAccessor('password');\n p.hostname = generateSimpleAccessor('hostname');\n p.port = generateSimpleAccessor('port');\n p.query = generatePrefixAccessor('query', '?');\n p.fragment = generatePrefixAccessor('fragment', '#');\n\n p.search = function(v, build) {\n var t = this.query(v, build);\n return typeof t === 'string' && t.length ? ('?' + t) : t;\n };\n p.hash = function(v, build) {\n var t = this.fragment(v, build);\n return typeof t === 'string' && t.length ? ('#' + t) : t;\n };\n\n p.pathname = function(v, build) {\n if (v === undefined || v === true) {\n var res = this._parts.path || (this._parts.hostname ? '/' : '');\n return v ? (this._parts.urn ? URI.decodeUrnPath : URI.decodePath)(res) : res;\n } else {\n if (this._parts.urn) {\n this._parts.path = v ? URI.recodeUrnPath(v) : '';\n } else {\n this._parts.path = v ? URI.recodePath(v) : '/';\n }\n this.build(!build);\n return this;\n }\n };\n p.path = p.pathname;\n p.href = function(href, build) {\n var key;\n\n if (href === undefined) {\n return this.toString();\n }\n\n this._string = '';\n this._parts = URI._parts();\n\n var _URI = href instanceof URI;\n var _object = typeof href === 'object' && (href.hostname || href.path || href.pathname);\n if (href.nodeName) {\n var attribute = URI.getDomAttribute(href);\n href = href[attribute] || '';\n _object = false;\n }\n\n // window.location is reported to be an object, but it's not the sort\n // of object we're looking for:\n // * location.protocol ends with a colon\n // * location.query != object.search\n // * location.hash != object.fragment\n // simply serializing the unknown object should do the trick\n // (for location, not for everything...)\n if (!_URI && _object && href.pathname !== undefined) {\n href = href.toString();\n }\n\n if (typeof href === 'string' || href instanceof String) {\n this._parts = URI.parse(String(href), this._parts);\n } else if (_URI || _object) {\n var src = _URI ? href._parts : href;\n for (key in src) {\n if (hasOwn.call(this._parts, key)) {\n this._parts[key] = src[key];\n }\n }\n } else {\n throw new TypeError('invalid input');\n }\n\n this.build(!build);\n return this;\n };\n\n // identification accessors\n p.is = function(what) {\n var ip = false;\n var ip4 = false;\n var ip6 = false;\n var name = false;\n var sld = false;\n var idn = false;\n var punycode = false;\n var relative = !this._parts.urn;\n\n if (this._parts.hostname) {\n relative = false;\n ip4 = URI.ip4_expression.test(this._parts.hostname);\n ip6 = URI.ip6_expression.test(this._parts.hostname);\n ip = ip4 || ip6;\n name = !ip;\n sld = name && SLD && SLD.has(this._parts.hostname);\n idn = name && URI.idn_expression.test(this._parts.hostname);\n punycode = name && URI.punycode_expression.test(this._parts.hostname);\n }\n\n switch (what.toLowerCase()) {\n case 'relative':\n return relative;\n\n case 'absolute':\n return !relative;\n\n // hostname identification\n case 'domain':\n case 'name':\n return name;\n\n case 'sld':\n return sld;\n\n case 'ip':\n return ip;\n\n case 'ip4':\n case 'ipv4':\n case 'inet4':\n return ip4;\n\n case 'ip6':\n case 'ipv6':\n case 'inet6':\n return ip6;\n\n case 'idn':\n return idn;\n\n case 'url':\n return !this._parts.urn;\n\n case 'urn':\n return !!this._parts.urn;\n\n case 'punycode':\n return punycode;\n }\n\n return null;\n };\n\n // component specific input validation\n var _protocol = p.protocol;\n var _port = p.port;\n var _hostname = p.hostname;\n\n p.protocol = function(v, build) {\n if (v !== undefined) {\n if (v) {\n // accept trailing ://\n v = v.replace(/:(\\/\\/)?$/, '');\n\n if (!v.match(URI.protocol_expression)) {\n throw new TypeError('Protocol \"' + v + '\" contains characters other than [A-Z0-9.+-] or doesn\\'t start with [A-Z]');\n }\n }\n }\n return _protocol.call(this, v, build);\n };\n p.scheme = p.protocol;\n p.port = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v !== undefined) {\n if (v === 0) {\n v = null;\n }\n\n if (v) {\n v += '';\n if (v.charAt(0) === ':') {\n v = v.substring(1);\n }\n\n if (v.match(/[^0-9]/)) {\n throw new TypeError('Port \"' + v + '\" contains characters other than [0-9]');\n }\n }\n }\n return _port.call(this, v, build);\n };\n p.hostname = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v !== undefined) {\n var x = {};\n var res = URI.parseHost(v, x);\n if (res !== '/') {\n throw new TypeError('Hostname \"' + v + '\" contains characters other than [A-Z0-9.-]');\n }\n\n v = x.hostname;\n }\n return _hostname.call(this, v, build);\n };\n\n // compound accessors\n p.origin = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v === undefined) {\n var protocol = this.protocol();\n var authority = this.authority();\n if (!authority) {\n return '';\n }\n\n return (protocol ? protocol + '://' : '') + this.authority();\n } else {\n var origin = URI(v);\n this\n .protocol(origin.protocol())\n .authority(origin.authority())\n .build(!build);\n return this;\n }\n };\n p.host = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v === undefined) {\n return this._parts.hostname ? URI.buildHost(this._parts) : '';\n } else {\n var res = URI.parseHost(v, this._parts);\n if (res !== '/') {\n throw new TypeError('Hostname \"' + v + '\" contains characters other than [A-Z0-9.-]');\n }\n\n this.build(!build);\n return this;\n }\n };\n p.authority = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v === undefined) {\n return this._parts.hostname ? URI.buildAuthority(this._parts) : '';\n } else {\n var res = URI.parseAuthority(v, this._parts);\n if (res !== '/') {\n throw new TypeError('Hostname \"' + v + '\" contains characters other than [A-Z0-9.-]');\n }\n\n this.build(!build);\n return this;\n }\n };\n p.userinfo = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v === undefined) {\n var t = URI.buildUserinfo(this._parts);\n return t ? t.substring(0, t.length -1) : t;\n } else {\n if (v[v.length-1] !== '@') {\n v += '@';\n }\n\n URI.parseUserinfo(v, this._parts);\n this.build(!build);\n return this;\n }\n };\n p.resource = function(v, build) {\n var parts;\n\n if (v === undefined) {\n return this.path() + this.search() + this.hash();\n }\n\n parts = URI.parse(v);\n this._parts.path = parts.path;\n this._parts.query = parts.query;\n this._parts.fragment = parts.fragment;\n this.build(!build);\n return this;\n };\n\n // fraction accessors\n p.subdomain = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n // convenience, return \"www\" from \"www.example.org\"\n if (v === undefined) {\n if (!this._parts.hostname || this.is('IP')) {\n return '';\n }\n\n // grab domain and add another segment\n var end = this._parts.hostname.length - this.domain().length - 1;\n return this._parts.hostname.substring(0, end) || '';\n } else {\n var e = this._parts.hostname.length - this.domain().length;\n var sub = this._parts.hostname.substring(0, e);\n var replace = new RegExp('^' + escapeRegEx(sub));\n\n if (v && v.charAt(v.length - 1) !== '.') {\n v += '.';\n }\n\n if (v) {\n URI.ensureValidHostname(v);\n }\n\n this._parts.hostname = this._parts.hostname.replace(replace, v);\n this.build(!build);\n return this;\n }\n };\n p.domain = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (typeof v === 'boolean') {\n build = v;\n v = undefined;\n }\n\n // convenience, return \"example.org\" from \"www.example.org\"\n if (v === undefined) {\n if (!this._parts.hostname || this.is('IP')) {\n return '';\n }\n\n // if hostname consists of 1 or 2 segments, it must be the domain\n var t = this._parts.hostname.match(/\\./g);\n if (t && t.length < 2) {\n return this._parts.hostname;\n }\n\n // grab tld and add another segment\n var end = this._parts.hostname.length - this.tld(build).length - 1;\n end = this._parts.hostname.lastIndexOf('.', end -1) + 1;\n return this._parts.hostname.substring(end) || '';\n } else {\n if (!v) {\n throw new TypeError('cannot set domain empty');\n }\n\n URI.ensureValidHostname(v);\n\n if (!this._parts.hostname || this.is('IP')) {\n this._parts.hostname = v;\n } else {\n var replace = new RegExp(escapeRegEx(this.domain()) + '$');\n this._parts.hostname = this._parts.hostname.replace(replace, v);\n }\n\n this.build(!build);\n return this;\n }\n };\n p.tld = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (typeof v === 'boolean') {\n build = v;\n v = undefined;\n }\n\n // return \"org\" from \"www.example.org\"\n if (v === undefined) {\n if (!this._parts.hostname || this.is('IP')) {\n return '';\n }\n\n var pos = this._parts.hostname.lastIndexOf('.');\n var tld = this._parts.hostname.substring(pos + 1);\n\n if (build !== true && SLD && SLD.list[tld.toLowerCase()]) {\n return SLD.get(this._parts.hostname) || tld;\n }\n\n return tld;\n } else {\n var replace;\n\n if (!v) {\n throw new TypeError('cannot set TLD empty');\n } else if (v.match(/[^a-zA-Z0-9-]/)) {\n if (SLD && SLD.is(v)) {\n replace = new RegExp(escapeRegEx(this.tld()) + '$');\n this._parts.hostname = this._parts.hostname.replace(replace, v);\n } else {\n throw new TypeError('TLD \"' + v + '\" contains characters other than [A-Z0-9]');\n }\n } else if (!this._parts.hostname || this.is('IP')) {\n throw new ReferenceError('cannot set TLD on non-domain host');\n } else {\n replace = new RegExp(escapeRegEx(this.tld()) + '$');\n this._parts.hostname = this._parts.hostname.replace(replace, v);\n }\n\n this.build(!build);\n return this;\n }\n };\n p.directory = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v === undefined || v === true) {\n if (!this._parts.path && !this._parts.hostname) {\n return '';\n }\n\n if (this._parts.path === '/') {\n return '/';\n }\n\n var end = this._parts.path.length - this.filename().length - 1;\n var res = this._parts.path.substring(0, end) || (this._parts.hostname ? '/' : '');\n\n return v ? URI.decodePath(res) : res;\n\n } else {\n var e = this._parts.path.length - this.filename().length;\n var directory = this._parts.path.substring(0, e);\n var replace = new RegExp('^' + escapeRegEx(directory));\n\n // fully qualifier directories begin with a slash\n if (!this.is('relative')) {\n if (!v) {\n v = '/';\n }\n\n if (v.charAt(0) !== '/') {\n v = '/' + v;\n }\n }\n\n // directories always end with a slash\n if (v && v.charAt(v.length - 1) !== '/') {\n v += '/';\n }\n\n v = URI.recodePath(v);\n this._parts.path = this._parts.path.replace(replace, v);\n this.build(!build);\n return this;\n }\n };\n p.filename = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v === undefined || v === true) {\n if (!this._parts.path || this._parts.path === '/') {\n return '';\n }\n\n var pos = this._parts.path.lastIndexOf('/');\n var res = this._parts.path.substring(pos+1);\n\n return v ? URI.decodePathSegment(res) : res;\n } else {\n var mutatedDirectory = false;\n\n if (v.charAt(0) === '/') {\n v = v.substring(1);\n }\n\n if (v.match(/\\.?\\//)) {\n mutatedDirectory = true;\n }\n\n var replace = new RegExp(escapeRegEx(this.filename()) + '$');\n v = URI.recodePath(v);\n this._parts.path = this._parts.path.replace(replace, v);\n\n if (mutatedDirectory) {\n this.normalizePath(build);\n } else {\n this.build(!build);\n }\n\n return this;\n }\n };\n p.suffix = function(v, build) {\n if (this._parts.urn) {\n return v === undefined ? '' : this;\n }\n\n if (v === undefined || v === true) {\n if (!this._parts.path || this._parts.path === '/') {\n return '';\n }\n\n var filename = this.filename();\n var pos = filename.lastIndexOf('.');\n var s, res;\n\n if (pos === -1) {\n return '';\n }\n\n // suffix may only contain alnum characters (yup, I made this up.)\n s = filename.substring(pos+1);\n res = (/^[a-z0-9%]+$/i).test(s) ? s : '';\n return v ? URI.decodePathSegment(res) : res;\n } else {\n if (v.charAt(0) === '.') {\n v = v.substring(1);\n }\n\n var suffix = this.suffix();\n var replace;\n\n if (!suffix) {\n if (!v) {\n return this;\n }\n\n this._parts.path += '.' + URI.recodePath(v);\n } else if (!v) {\n replace = new RegExp(escapeRegEx('.' + suffix) + '$');\n } else {\n replace = new RegExp(escapeRegEx(suffix) + '$');\n }\n\n if (replace) {\n v = URI.recodePath(v);\n this._parts.path = this._parts.path.replace(replace, v);\n }\n\n this.build(!build);\n return this;\n }\n };\n p.segment = function(segment, v, build) {\n var separator = this._parts.urn ? ':' : '/';\n var path = this.path();\n var absolute = path.substring(0, 1) === '/';\n var segments = path.split(separator);\n\n if (segment !== undefined && typeof segment !== 'number') {\n build = v;\n v = segment;\n segment = undefined;\n }\n\n if (segment !== undefined && typeof segment !== 'number') {\n throw new Error('Bad segment \"' + segment + '\", must be 0-based integer');\n }\n\n if (absolute) {\n segments.shift();\n }\n\n if (segment < 0) {\n // allow negative indexes to address from the end\n segment = Math.max(segments.length + segment, 0);\n }\n\n if (v === undefined) {\n /*jshint laxbreak: true */\n return segment === undefined\n ? segments\n : segments[segment];\n /*jshint laxbreak: false */\n } else if (segment === null || segments[segment] === undefined) {\n if (isArray(v)) {\n segments = [];\n // collapse empty elements within array\n for (var i=0, l=v.length; i < l; i++) {\n if (!v[i].length && (!segments.length || !segments[segments.length -1].length)) {\n continue;\n }\n\n if (segments.length && !segments[segments.length -1].length) {\n segments.pop();\n }\n\n segments.push(trimSlashes(v[i]));\n }\n } else if (v || typeof v === 'string') {\n v = trimSlashes(v);\n if (segments[segments.length -1] === '') {\n // empty trailing elements have to be overwritten\n // to prevent results such as /foo//bar\n segments[segments.length -1] = v;\n } else {\n segments.push(v);\n }\n }\n } else {\n if (v) {\n segments[segment] = trimSlashes(v);\n } else {\n segments.splice(segment, 1);\n }\n }\n\n if (absolute) {\n segments.unshift('');\n }\n\n return this.path(segments.join(separator), build);\n };\n p.segmentCoded = function(segment, v, build) {\n var segments, i, l;\n\n if (typeof segment !== 'number') {\n build = v;\n v = segment;\n segment = undefined;\n }\n\n if (v === undefined) {\n segments = this.segment(segment, v, build);\n if (!isArray(segments)) {\n segments = segments !== undefined ? URI.decode(segments) : undefined;\n } else {\n for (i = 0, l = segments.length; i < l; i++) {\n segments[i] = URI.decode(segments[i]);\n }\n }\n\n return segments;\n }\n\n if (!isArray(v)) {\n v = (typeof v === 'string' || v instanceof String) ? URI.encode(v) : v;\n } else {\n for (i = 0, l = v.length; i < l; i++) {\n v[i] = URI.encode(v[i]);\n }\n }\n\n return this.segment(segment, v, build);\n };\n\n // mutating query string\n var q = p.query;\n p.query = function(v, build) {\n if (v === true) {\n return URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);\n } else if (typeof v === 'function') {\n var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);\n var result = v.call(this, data);\n this._parts.query = URI.buildQuery(result || data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);\n this.build(!build);\n return this;\n } else if (v !== undefined && typeof v !== 'string') {\n this._parts.query = URI.buildQuery(v, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);\n this.build(!build);\n return this;\n } else {\n return q.call(this, v, build);\n }\n };\n p.setQuery = function(name, value, build) {\n var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);\n\n if (typeof name === 'string' || name instanceof String) {\n data[name] = value !== undefined ? value : null;\n } else if (typeof name === 'object') {\n for (var key in name) {\n if (hasOwn.call(name, key)) {\n data[key] = name[key];\n }\n }\n } else {\n throw new TypeError('URI.addQuery() accepts an object, string as the name parameter');\n }\n\n this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);\n if (typeof name !== 'string') {\n build = value;\n }\n\n this.build(!build);\n return this;\n };\n p.addQuery = function(name, value, build) {\n var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);\n URI.addQuery(data, name, value === undefined ? null : value);\n this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);\n if (typeof name !== 'string') {\n build = value;\n }\n\n this.build(!build);\n return this;\n };\n p.removeQuery = function(name, value, build) {\n var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);\n URI.removeQuery(data, name, value);\n this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);\n if (typeof name !== 'string') {\n build = value;\n }\n\n this.build(!build);\n return this;\n };\n p.hasQuery = function(name, value, withinArray) {\n var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);\n return URI.hasQuery(data, name, value, withinArray);\n };\n p.setSearch = p.setQuery;\n p.addSearch = p.addQuery;\n p.removeSearch = p.removeQuery;\n p.hasSearch = p.hasQuery;\n\n // sanitizing URLs\n p.normalize = function() {\n if (this._parts.urn) {\n return this\n .normalizeProtocol(false)\n .normalizePath(false)\n .normalizeQuery(false)\n .normalizeFragment(false)\n .build();\n }\n\n return this\n .normalizeProtocol(false)\n .normalizeHostname(false)\n .normalizePort(false)\n .normalizePath(false)\n .normalizeQuery(false)\n .normalizeFragment(false)\n .build();\n };\n p.normalizeProtocol = function(build) {\n if (typeof this._parts.protocol === 'string') {\n this._parts.protocol = this._parts.protocol.toLowerCase();\n this.build(!build);\n }\n\n return this;\n };\n p.normalizeHostname = function(build) {\n if (this._parts.hostname) {\n if (this.is('IDN') && punycode) {\n this._parts.hostname = punycode.toASCII(this._parts.hostname);\n } else if (this.is('IPv6') && IPv6) {\n this._parts.hostname = IPv6.best(this._parts.hostname);\n }\n\n this._parts.hostname = this._parts.hostname.toLowerCase();\n this.build(!build);\n }\n\n return this;\n };\n p.normalizePort = function(build) {\n // remove port of it's the protocol's default\n if (typeof this._parts.protocol === 'string' && this._parts.port === URI.defaultPorts[this._parts.protocol]) {\n this._parts.port = null;\n this.build(!build);\n }\n\n return this;\n };\n p.normalizePath = function(build) {\n var _path = this._parts.path;\n if (!_path) {\n return this;\n }\n\n if (this._parts.urn) {\n this._parts.path = URI.recodeUrnPath(this._parts.path);\n this.build(!build);\n return this;\n }\n\n if (this._parts.path === '/') {\n return this;\n }\n\n _path = URI.recodePath(_path);\n\n var _was_relative;\n var _leadingParents = '';\n var _parent, _pos;\n\n // handle relative paths\n if (_path.charAt(0) !== '/') {\n _was_relative = true;\n _path = '/' + _path;\n }\n\n // handle relative files (as opposed to directories)\n if (_path.slice(-3) === '/..' || _path.slice(-2) === '/.') {\n _path += '/';\n }\n\n // resolve simples\n _path = _path\n .replace(/(\\/(\\.\\/)+)|(\\/\\.$)/g, '/')\n .replace(/\\/{2,}/g, '/');\n\n // remember leading parents\n if (_was_relative) {\n _leadingParents = _path.substring(1).match(/^(\\.\\.\\/)+/) || '';\n if (_leadingParents) {\n _leadingParents = _leadingParents[0];\n }\n }\n\n // resolve parents\n while (true) {\n _parent = _path.search(/\\/\\.\\.(\\/|$)/);\n if (_parent === -1) {\n // no more ../ to resolve\n break;\n } else if (_parent === 0) {\n // top level cannot be relative, skip it\n _path = _path.substring(3);\n continue;\n }\n\n _pos = _path.substring(0, _parent).lastIndexOf('/');\n if (_pos === -1) {\n _pos = _parent;\n }\n _path = _path.substring(0, _pos) + _path.substring(_parent + 3);\n }\n\n // revert to relative\n if (_was_relative && this.is('relative')) {\n _path = _leadingParents + _path.substring(1);\n }\n\n this._parts.path = _path;\n this.build(!build);\n return this;\n };\n p.normalizePathname = p.normalizePath;\n p.normalizeQuery = function(build) {\n if (typeof this._parts.query === 'string') {\n if (!this._parts.query.length) {\n this._parts.query = null;\n } else {\n this.query(URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace));\n }\n\n this.build(!build);\n }\n\n return this;\n };\n p.normalizeFragment = function(build) {\n if (!this._parts.fragment) {\n this._parts.fragment = null;\n this.build(!build);\n }\n\n return this;\n };\n p.normalizeSearch = p.normalizeQuery;\n p.normalizeHash = p.normalizeFragment;\n\n p.iso8859 = function() {\n // expect unicode input, iso8859 output\n var e = URI.encode;\n var d = URI.decode;\n\n URI.encode = escape;\n URI.decode = decodeURIComponent;\n try {\n this.normalize();\n } finally {\n URI.encode = e;\n URI.decode = d;\n }\n return this;\n };\n\n p.unicode = function() {\n // expect iso8859 input, unicode output\n var e = URI.encode;\n var d = URI.decode;\n\n URI.encode = strictEncodeURIComponent;\n URI.decode = unescape;\n try {\n this.normalize();\n } finally {\n URI.encode = e;\n URI.decode = d;\n }\n return this;\n };\n\n p.readable = function() {\n var uri = this.clone();\n // removing username, password, because they shouldn't be displayed according to RFC 3986\n uri.username('').password('').normalize();\n var t = '';\n if (uri._parts.protocol) {\n t += uri._parts.protocol + '://';\n }\n\n if (uri._parts.hostname) {\n if (uri.is('punycode') && punycode) {\n t += punycode.toUnicode(uri._parts.hostname);\n if (uri._parts.port) {\n t += ':' + uri._parts.port;\n }\n } else {\n t += uri.host();\n }\n }\n\n if (uri._parts.hostname && uri._parts.path && uri._parts.path.charAt(0) !== '/') {\n t += '/';\n }\n\n t += uri.path(true);\n if (uri._parts.query) {\n var q = '';\n for (var i = 0, qp = uri._parts.query.split('&'), l = qp.length; i < l; i++) {\n var kv = (qp[i] || '').split('=');\n q += '&' + URI.decodeQuery(kv[0], this._parts.escapeQuerySpace)\n .replace(/&/g, '%26');\n\n if (kv[1] !== undefined) {\n q += '=' + URI.decodeQuery(kv[1], this._parts.escapeQuerySpace)\n .replace(/&/g, '%26');\n }\n }\n t += '?' + q.substring(1);\n }\n\n t += URI.decodeQuery(uri.hash(), true);\n return t;\n };\n\n // resolving relative and absolute URLs\n p.absoluteTo = function(base) {\n var resolved = this.clone();\n var properties = ['protocol', 'username', 'password', 'hostname', 'port'];\n var basedir, i, p;\n\n if (this._parts.urn) {\n throw new Error('URNs do not have any generally defined hierarchical components');\n }\n\n if (!(base instanceof URI)) {\n base = new URI(base);\n }\n\n if (!resolved._parts.protocol) {\n resolved._parts.protocol = base._parts.protocol;\n }\n\n if (this._parts.hostname) {\n return resolved;\n }\n\n for (i = 0; (p = properties[i]); i++) {\n resolved._parts[p] = base._parts[p];\n }\n\n if (!resolved._parts.path) {\n resolved._parts.path = base._parts.path;\n if (!resolved._parts.query) {\n resolved._parts.query = base._parts.query;\n }\n } else if (resolved._parts.path.substring(-2) === '..') {\n resolved._parts.path += '/';\n }\n\n if (resolved.path().charAt(0) !== '/') {\n basedir = base.directory();\n basedir = basedir ? basedir : base.path().indexOf('/') === 0 ? '/' : '';\n resolved._parts.path = (basedir ? (basedir + '/') : '') + resolved._parts.path;\n resolved.normalizePath();\n }\n\n resolved.build();\n return resolved;\n };\n p.relativeTo = function(base) {\n var relative = this.clone().normalize();\n var relativeParts, baseParts, common, relativePath, basePath;\n\n if (relative._parts.urn) {\n throw new Error('URNs do not have any generally defined hierarchical components');\n }\n\n base = new URI(base).normalize();\n relativeParts = relative._parts;\n baseParts = base._parts;\n relativePath = relative.path();\n basePath = base.path();\n\n if (relativePath.charAt(0) !== '/') {\n throw new Error('URI is already relative');\n }\n\n if (basePath.charAt(0) !== '/') {\n throw new Error('Cannot calculate a URI relative to another relative URI');\n }\n\n if (relativeParts.protocol === baseParts.protocol) {\n relativeParts.protocol = null;\n }\n\n if (relativeParts.username !== baseParts.username || relativeParts.password !== baseParts.password) {\n return relative.build();\n }\n\n if (relativeParts.protocol !== null || relativeParts.username !== null || relativeParts.password !== null) {\n return relative.build();\n }\n\n if (relativeParts.hostname === baseParts.hostname && relativeParts.port === baseParts.port) {\n relativeParts.hostname = null;\n relativeParts.port = null;\n } else {\n return relative.build();\n }\n\n if (relativePath === basePath) {\n relativeParts.path = '';\n return relative.build();\n }\n\n // determine common sub path\n common = URI.commonPath(relativePath, basePath);\n\n // If the paths have nothing in common, return a relative URL with the absolute path.\n if (!common) {\n return relative.build();\n }\n\n var parents = baseParts.path\n .substring(common.length)\n .replace(/[^\\/]*$/, '')\n .replace(/.*?\\//g, '../');\n\n relativeParts.path = (parents + relativeParts.path.substring(common.length)) || './';\n\n return relative.build();\n };\n\n // comparing URIs\n p.equals = function(uri) {\n var one = this.clone();\n var two = new URI(uri);\n var one_map = {};\n var two_map = {};\n var checked = {};\n var one_query, two_query, key;\n\n one.normalize();\n two.normalize();\n\n // exact match\n if (one.toString() === two.toString()) {\n return true;\n }\n\n // extract query string\n one_query = one.query();\n two_query = two.query();\n one.query('');\n two.query('');\n\n // definitely not equal if not even non-query parts match\n if (one.toString() !== two.toString()) {\n return false;\n }\n\n // query parameters have the same length, even if they're permuted\n if (one_query.length !== two_query.length) {\n return false;\n }\n\n one_map = URI.parseQuery(one_query, this._parts.escapeQuerySpace);\n two_map = URI.parseQuery(two_query, this._parts.escapeQuerySpace);\n\n for (key in one_map) {\n if (hasOwn.call(one_map, key)) {\n if (!isArray(one_map[key])) {\n if (one_map[key] !== two_map[key]) {\n return false;\n }\n } else if (!arraysEqual(one_map[key], two_map[key])) {\n return false;\n }\n\n checked[key] = true;\n }\n }\n\n for (key in two_map) {\n if (hasOwn.call(two_map, key)) {\n if (!checked[key]) {\n // two contains a parameter not present in one\n return false;\n }\n }\n }\n\n return true;\n };\n\n // state\n p.duplicateQueryParameters = function(v) {\n this._parts.duplicateQueryParameters = !!v;\n return this;\n };\n\n p.escapeQuerySpace = function(v) {\n this._parts.escapeQuerySpace = !!v;\n return this;\n };\n\n return URI;\n}));\n","var RSVP = require('rsvp');\nvar URI = require('urijs');\nvar core = require('./core');\nvar Spine = require('./spine');\nvar Locations = require('./locations');\nvar Parser = require('./parser');\nvar Navigation = require('./navigation');\nvar Rendition = require('./rendition');\nvar Unarchive = require('./unarchive');\nvar request = require('./request');\nvar EpubCFI = require('./epubcfi');\n\nfunction Book(_url, options){\n\n\tthis.settings = core.extend(this.settings || {}, {\n\t\trequestMethod: this.requestMethod\n\t});\n\n\tcore.extend(this.settings, options);\n\n\n\t// Promises\n\tthis.opening = new RSVP.defer();\n\tthis.opened = this.opening.promise;\n\tthis.isOpen = false;\n\n\tthis.url = undefined;\n\n\tthis.loading = {\n\t\tmanifest: new RSVP.defer(),\n\t\tspine: new RSVP.defer(),\n\t\tmetadata: new RSVP.defer(),\n\t\tcover: new RSVP.defer(),\n\t\tnavigation: new RSVP.defer(),\n\t\tpageList: new RSVP.defer()\n\t};\n\n\tthis.loaded = {\n\t\tmanifest: this.loading.manifest.promise,\n\t\tspine: this.loading.spine.promise,\n\t\tmetadata: this.loading.metadata.promise,\n\t\tcover: this.loading.cover.promise,\n\t\tnavigation: this.loading.navigation.promise,\n\t\tpageList: this.loading.pageList.promise\n\t};\n\n\tthis.ready = RSVP.hash(this.loaded);\n\n\t// Queue for methods used before opening\n\tthis.isRendered = false;\n\t// this._q = core.queue(this);\n\n\tthis.request = this.settings.requestMethod.bind(this);\n\n\tthis.spine = new Spine(this.request);\n\tthis.locations = new Locations(this.spine, this.request);\n\n\tif(_url) {\n\t\tthis.open(_url).catch(function (error) {\n\t\t\tvar err = new Error(\"Cannot load book at \"+ _url );\n\t\t\tconsole.error(err);\n\n\t\t\tthis.trigger(\"loadFailed\", error);\n\t\t}.bind(this));\n\t}\n};\n\nBook.prototype.open = function(_url, options){\n\tvar uri;\n\tvar parse = new Parser();\n\tvar epubPackage;\n\tvar epubContainer;\n\tvar book = this;\n\tvar containerPath = \"META-INF/container.xml\";\n\tvar location;\n\tvar absoluteUri;\n\tvar isArrayBuffer = false;\n\tvar isBase64 = options && options.base64;\n\n\tif(!_url) {\n\t\tthis.opening.resolve(this);\n\t\treturn this.opened;\n\t}\n\n\t// Reuse parsed url or create a new uri object\n\t// if(typeof(_url) === \"object\") {\n\t// uri = _url;\n\t// } else {\n\t// uri = core.uri(_url);\n\t// }\n\tif (_url instanceof ArrayBuffer || isBase64) {\n\t\tisArrayBuffer = true;\n\t\tthis.url = '/';\n\t} else {\n\t\turi = URI(_url);\n\t}\n\n\tif (window && window.location && uri) {\n\t\tabsoluteUri = uri.absoluteTo(window.location.href);\n\t\tthis.url = absoluteUri.toString();\n\t} else if (window && window.location) {\n\t\tthis.url = window.location.href;\n\t} else {\n\t\tthis.url = _url;\n\t}\n\n\t// Find path to the Container\n\tif(uri && uri.suffix() === \"opf\") {\n\t\t// Direct link to package, no container\n\t\tthis.packageUrl = _url;\n\t\tthis.containerUrl = '';\n\n\t\tif(uri.origin()) {\n\t\t\tthis.baseUrl = uri.origin() + \"/\" + uri.directory() + \"/\";\n\t\t} else if(absoluteUri){\n\t\t\tthis.baseUrl = absoluteUri.origin();\n\t\t\tthis.baseUrl += absoluteUri.directory() + \"/\";\n\t\t} else {\n\t\t\tthis.baseUrl = uri.directory() + \"/\";\n\t\t}\n\n\t\tepubPackage = this.request(this.packageUrl)\n\t\t\t.catch(function(error) {\n\t\t\t\tbook.opening.reject(error);\n\t\t\t});\n\n\t} else if(isArrayBuffer || isBase64 || this.isArchivedUrl(uri)) {\n\t\t// Book is archived\n\t\tthis.url = '/';\n\t\tthis.containerUrl = URI(containerPath).absoluteTo(this.url).toString();\n\n\t\tepubContainer = this.unarchive(_url, isBase64).\n\t\t\tthen(function() {\n\t\t\t\treturn this.request(this.containerUrl);\n\t\t\t}.bind(this))\n\t\t\t.catch(function(error) {\n\t\t\t\tbook.opening.reject(error);\n\t\t\t});\n\t}\n\t// Find the path to the Package from the container\n\telse if (!uri.suffix()) {\n\n\t\tthis.containerUrl = this.url + containerPath;\n\n\t\tepubContainer = this.request(this.containerUrl)\n\t\t\t.catch(function(error) {\n\t\t\t\t// handle errors in loading container\n\t\t\t\tbook.opening.reject(error);\n\t\t\t});\n\t}\n\n\tif (epubContainer) {\n\t\tepubPackage = epubContainer.\n\t\t\tthen(function(containerXml){\n\t\t\t\treturn parse.container(containerXml); // Container has path to content\n\t\t\t}).\n\t\t\tthen(function(paths){\n\t\t\t\tvar packageUri = URI(paths.packagePath);\n\t\t\t\tvar absPackageUri = packageUri.absoluteTo(book.url);\n\t\t\t\tvar absWindowUri;\n\n\t\t\t\tbook.packageUrl = absPackageUri.toString();\n\t\t\t\tbook.encoding = paths.encoding;\n\n\t\t\t\t// Set Url relative to the content\n\t\t\t\tif(absPackageUri.origin()) {\n\t\t\t\t\tbook.baseUrl = absPackageUri.origin() + absPackageUri.directory() + \"/\";\n\t\t\t\t} else {\n\t\t\t\t\tif(packageUri.directory()) {\n\t\t\t\t\t\tbook.baseUrl = \"/\" + packageUri.directory() + \"/\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbook.baseUrl = \"/\"\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn book.request(book.packageUrl);\n\t\t\t}).catch(function(error) {\n\t\t\t\t// handle errors in either of the two requests\n\t\t\t\tbook.opening.reject(error);\n\t\t\t});\n\t}\n\n\tepubPackage.then(function(packageXml) {\n\n\t\tif (!packageXml) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Get package information from epub opf\n\t\tbook.unpack(packageXml);\n\n\t\t// Resolve promises\n\t\tbook.loading.manifest.resolve(book.package.manifest);\n\t\tbook.loading.metadata.resolve(book.package.metadata);\n\t\tbook.loading.spine.resolve(book.spine);\n\t\tbook.loading.cover.resolve(book.cover);\n\n\t\tbook.isOpen = true;\n\n\t\t// Clear queue of any waiting book request\n\n\t\t// Resolve book opened promise\n\t\tbook.opening.resolve(book);\n\n\t}).catch(function(error) {\n\t\t// handle errors in parsing the book\n\t\t// console.error(error.message, error.stack);\n\t\tbook.opening.reject(error);\n\t});\n\n\treturn this.opened;\n};\n\nBook.prototype.unpack = function(packageXml){\n\tvar book = this,\n\t\t\tparse = new Parser();\n\n\tbook.package = parse.packageContents(packageXml); // Extract info from contents\n\tif(!book.package) {\n\t\treturn;\n\t}\n\n\tbook.package.baseUrl = book.baseUrl; // Provides a url base for resolving paths\n\n\tthis.spine.load(book.package);\n\n\tbook.navigation = new Navigation(book.package, this.request);\n\tbook.navigation.load().then(function(toc){\n\t\tbook.toc = toc;\n\t\tbook.loading.navigation.resolve(book.toc);\n\t});\n\n\t// //-- Set Global Layout setting based on metadata\n\t// MOVE TO RENDER\n\t// book.globalLayoutProperties = book.parseLayoutProperties(book.package.metadata);\n\n\tbook.cover = URI(book.package.coverPath).absoluteTo(book.baseUrl).toString();\n};\n\n// Alias for book.spine.get\nBook.prototype.section = function(target) {\n\treturn this.spine.get(target);\n};\n\n// Sugar to render a book\nBook.prototype.renderTo = function(element, options) {\n\t// var renderMethod = (options && options.method) ?\n\t// options.method :\n\t// \"single\";\n\n\tthis.rendition = new Rendition(this, options);\n\tthis.rendition.attachTo(element);\n\n\treturn this.rendition;\n};\n\nBook.prototype.requestMethod = function(_url) {\n\t// Switch request methods\n\tif(this.unarchived) {\n\t\treturn this.unarchived.request(_url);\n\t} else {\n\t\treturn request(_url, null, this.requestCredentials, this.requestHeaders);\n\t}\n\n};\n\nBook.prototype.setRequestCredentials = function(_credentials) {\n\tthis.requestCredentials = _credentials;\n};\n\nBook.prototype.setRequestHeaders = function(_headers) {\n\tthis.requestHeaders = _headers;\n};\n\nBook.prototype.unarchive = function(bookUrl, isBase64){\n\tthis.unarchived = new Unarchive();\n\treturn this.unarchived.open(bookUrl, isBase64);\n};\n\n//-- Checks if url has a .epub or .zip extension, or is ArrayBuffer (of zip/epub)\nBook.prototype.isArchivedUrl = function(bookUrl){\n\tvar uri;\n\tvar extension;\n\n\tif (bookUrl instanceof ArrayBuffer) {\n\t\treturn true;\n\t}\n\n\t// Reuse parsed url or create a new uri object\n\t// if(typeof(bookUrl) === \"object\") {\n\t// uri = bookUrl;\n\t// } else {\n\t// uri = core.uri(bookUrl);\n\t// }\n\turi = URI(bookUrl);\n\textension = uri.suffix();\n\n\tif(extension && (extension == \"epub\" || extension == \"zip\")){\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\n//-- Returns the cover\nBook.prototype.coverUrl = function(){\n\tvar retrieved = this.loaded.cover.\n\t\tthen(function(url) {\n\t\t\tif(this.unarchived) {\n\t\t\t\treturn this.unarchived.createUrl(this.cover);\n\t\t\t}else{\n\t\t\t\treturn this.cover;\n\t\t\t}\n\t\t}.bind(this));\n\n\n\n\treturn retrieved;\n};\n\nBook.prototype.range = function(cfiRange) {\n\tvar cfi = new EpubCFI(cfiRange);\n\tvar item = this.spine.get(cfi.spinePos);\n\n\treturn item.load().then(function (contents) {\n\t\tvar range = cfi.toRange(item.document);\n\t\treturn range;\n\t})\n};\n\nmodule.exports = Book;\n\n//-- Enable binding events to book\nRSVP.EventTarget.mixin(Book.prototype);\n\n//-- Handle RSVP Errors\nRSVP.on('error', function(event) {\n\tconsole.error(event);\n});\n\nRSVP.configure('instrument', false); //-- true | will logging out all RSVP rejections\n// RSVP.on('created', listener);\n// RSVP.on('chained', listener);\n// RSVP.on('fulfilled', listener);\nRSVP.on('rejected', function(event){\n\tconsole.error(event.detail.message, event.detail.stack);\n});\n","var RSVP = require('rsvp');\nvar core = require('./core');\nvar EpubCFI = require('./epubcfi');\nvar Mapping = require('./mapping');\n\n\nfunction Contents(doc, content, cfiBase) {\n\t// Blank Cfi for Parsing\n\tthis.epubcfi = new EpubCFI();\n\n\tthis.document = doc;\n\tthis.documentElement = this.document.documentElement;\n\tthis.content = content || this.document.body;\n\tthis.window = this.document.defaultView;\n\t// Dom events to listen for\n\tthis.listenedEvents = [\"keydown\", \"keyup\", \"keypressed\", \"mouseup\", \"mousedown\", \"click\", \"touchend\", \"touchstart\"];\n\n\tthis._size = {\n\t\twidth: 0,\n\t\theight: 0\n\t}\n\n\tthis.cfiBase = cfiBase || \"\";\n\n\tthis.listeners();\n};\n\nContents.prototype.width = function(w) {\n\t// var frame = this.documentElement;\n\tvar frame = this.content;\n\n\tif (w && core.isNumber(w)) {\n\t\tw = w + \"px\";\n\t}\n\n\tif (w) {\n\t\tframe.style.width = w;\n\t\t// this.content.style.width = w;\n\t}\n\n\treturn this.window.getComputedStyle(frame)['width'];\n\n\n};\n\nContents.prototype.height = function(h) {\n\t// var frame = this.documentElement;\n\tvar frame = this.content;\n\n\tif (h && core.isNumber(h)) {\n\t\th = h + \"px\";\n\t}\n\n\tif (h) {\n\t\tframe.style.height = h;\n\t\t// this.content.style.height = h;\n\t}\n\n\treturn this.window.getComputedStyle(frame)['height'];\n\n};\n\nContents.prototype.contentWidth = function(w) {\n\n\tvar content = this.content || this.document.body;\n\n\tif (w && core.isNumber(w)) {\n\t\tw = w + \"px\";\n\t}\n\n\tif (w) {\n\t\tcontent.style.width = w;\n\t}\n\n\treturn this.window.getComputedStyle(content)['width'];\n\n\n};\n\nContents.prototype.contentHeight = function(h) {\n\n\tvar content = this.content || this.document.body;\n\n\tif (h && core.isNumber(h)) {\n\t\th = h + \"px\";\n\t}\n\n\tif (h) {\n\t\tcontent.style.height = h;\n\t}\n\n\treturn this.window.getComputedStyle(content)['height'];\n\n};\n\nContents.prototype.textWidth = function() {\n\tvar width;\n\tvar range = this.document.createRange();\n\tvar content = this.content || this.document.body;\n\n\t// Select the contents of frame\n\trange.selectNodeContents(content);\n\n\t// get the width of the text content\n\twidth = range.getBoundingClientRect().width;\n\n\treturn width;\n\n};\n\nContents.prototype.textHeight = function() {\n\tvar height;\n\tvar range = this.document.createRange();\n\tvar content = this.content || this.document.body;\n\n\trange.selectNodeContents(content);\n\n\theight = range.getBoundingClientRect().height;\n\n\treturn height;\n};\n\nContents.prototype.scrollWidth = function() {\n\tvar width = this.documentElement.scrollWidth;\n\n\treturn width;\n};\n\nContents.prototype.scrollHeight = function() {\n\tvar height = this.documentElement.scrollHeight;\n\n\treturn height;\n};\n\nContents.prototype.overflow = function(overflow) {\n\n\tif (overflow) {\n\t\tthis.documentElement.style.overflow = overflow;\n\t}\n\n\treturn this.window.getComputedStyle(this.documentElement)['overflow'];\n};\n\nContents.prototype.overflowX = function(overflow) {\n\n\tif (overflow) {\n\t\tthis.documentElement.style.overflowX = overflow;\n\t}\n\n\treturn this.window.getComputedStyle(this.documentElement)['overflowX'];\n};\n\nContents.prototype.overflowY = function(overflow) {\n\n\tif (overflow) {\n\t\tthis.documentElement.style.overflowY = overflow;\n\t}\n\n\treturn this.window.getComputedStyle(this.documentElement)['overflowY'];\n};\n\nContents.prototype.css = function(property, value) {\n\tvar content = this.content || this.document.body;\n\n\tif (value) {\n\t\tcontent.style[property] = value;\n\t}\n\n\treturn this.window.getComputedStyle(content)[property];\n};\n\nContents.prototype.viewport = function(options) {\n\tvar width, height, scale, scalable;\n\tvar $viewport = this.document.querySelector(\"meta[name='viewport']\");\n\tvar newContent = '';\n\n\t/**\n\t* check for the viewport size\n\t* \n\t*/\n\tif($viewport && $viewport.hasAttribute(\"content\")) {\n\t\tcontent = $viewport.getAttribute(\"content\");\n\t\tcontents = content.split(/\\s*,\\s*/);\n\t\tif(contents[0]){\n\t\t\twidth = contents[0].replace(\"width=\", '').trim();\n\t\t}\n\t\tif(contents[1]){\n\t\t\theight = contents[1].replace(\"height=\", '').trim();\n\t\t}\n\t\tif(contents[2]){\n\t\t\tscale = contents[2].replace(\"initial-scale=\", '').trim();\n\t\t}\n\t\tif(contents[3]){\n\t\t\tscalable = contents[3].replace(\"user-scalable=\", '').trim();\n\t\t}\n\t}\n\n\tif (options) {\n\n\t\tnewContent += \"width=\" + (options.width || width);\n\t\tnewContent += \", height=\" + (options.height || height);\n\t\tif (options.scale || scale) {\n\t\t\tnewContent += \", initial-scale=\" + (options.scale || scale);\n\t\t}\n\t\tif (options.scalable || scalable) {\n\t\t\tnewContent += \", user-scalable=\" + (options.scalable || scalable);\n\t\t}\n\n\t\tif (!$viewport) {\n\t\t\t$viewport = this.document.createElement(\"meta\");\n\t\t\t$viewport.setAttribute(\"name\", \"viewport\");\n\t\t\tthis.document.querySelector('head').appendChild($viewport);\n\t\t}\n\n\t\t$viewport.setAttribute(\"content\", newContent);\n\t}\n\n\n\treturn {\n\t\twidth: parseInt(width),\n\t\theight: parseInt(height)\n\t};\n};\n\n\n// Contents.prototype.layout = function(layoutFunc) {\n//\n// this.iframe.style.display = \"inline-block\";\n//\n// // Reset Body Styles\n// this.content.style.margin = \"0\";\n// //this.document.body.style.display = \"inline-block\";\n// //this.document.documentElement.style.width = \"auto\";\n//\n// if(layoutFunc){\n// layoutFunc(this);\n// }\n//\n// this.onLayout(this);\n//\n// };\n//\n// Contents.prototype.onLayout = function(view) {\n// // stub\n// };\n\nContents.prototype.expand = function() {\n\tthis.trigger(\"expand\");\n};\n\nContents.prototype.listeners = function() {\n\n\tthis.imageLoadListeners();\n\n\tthis.mediaQueryListeners();\n\n\t// this.fontLoadListeners();\n\n\tthis.addEventListeners();\n\n\tthis.addSelectionListeners();\n\n\tthis.resizeListeners();\n\n};\n\nContents.prototype.removeListeners = function() {\n\n\tthis.removeEventListeners();\n\n\tthis.removeSelectionListeners();\n};\n\nContents.prototype.resizeListeners = function() {\n\tvar width, height;\n\t// Test size again\n\tclearTimeout(this.expanding);\n\n\twidth = this.scrollWidth();\n\theight = this.scrollHeight();\n\n\tif (width != this._size.width || height != this._size.height) {\n\n\t\tthis._size = {\n\t\t\twidth: width,\n\t\t\theight: height\n\t\t}\n\n\t\tthis.trigger(\"resize\", this._size);\n\t}\n\n\tthis.expanding = setTimeout(this.resizeListeners.bind(this), 350);\n};\n\n//https://github.com/tylergaw/media-query-events/blob/master/js/mq-events.js\nContents.prototype.mediaQueryListeners = function() {\n\t\tvar sheets = this.document.styleSheets;\n\t\tvar mediaChangeHandler = function(m){\n\t\t\tif(m.matches && !this._expanding) {\n\t\t\t\tsetTimeout(this.expand.bind(this), 1);\n\t\t\t\t// this.expand();\n\t\t\t}\n\t\t}.bind(this);\n\n\t\tfor (var i = 0; i < sheets.length; i += 1) {\n\t\t\t\tvar rules = sheets[i].cssRules;\n\t\t\t\tif(!rules) return; // Stylesheets changed\n\t\t\t\tfor (var j = 0; j < rules.length; j += 1) {\n\t\t\t\t\t\t//if (rules[j].constructor === CSSMediaRule) {\n\t\t\t\t\t\tif(rules[j].media){\n\t\t\t\t\t\t\t\tvar mql = this.window.matchMedia(rules[j].media.mediaText);\n\t\t\t\t\t\t\t\tmql.addListener(mediaChangeHandler);\n\t\t\t\t\t\t\t\t//mql.onchange = mediaChangeHandler;\n\t\t\t\t\t\t}\n\t\t\t\t}\n\t\t}\n};\n\nContents.prototype.observe = function(target) {\n\tvar renderer = this;\n\n\t// create an observer instance\n\tvar observer = new MutationObserver(function(mutations) {\n\t\tif(renderer._expanding) {\n\t\t\trenderer.expand();\n\t\t}\n\t\t// mutations.forEach(function(mutation) {\n\t\t// console.log(mutation);\n\t\t// });\n\t});\n\n\t// configuration of the observer:\n\tvar config = { attributes: true, childList: true, characterData: true, subtree: true };\n\n\t// pass in the target node, as well as the observer options\n\tobserver.observe(target, config);\n\n\treturn observer;\n};\n\nContents.prototype.imageLoadListeners = function(target) {\n\tvar images = this.document.querySelectorAll(\"img\");\n\tvar img;\n\tfor (var i = 0; i < images.length; i++) {\n\t\timg = images[i];\n\n\t\tif (typeof img.naturalWidth !== \"undefined\" &&\n\t\t\t\timg.naturalWidth === 0) {\n\t\t\timg.onload = this.expand.bind(this);\n\t\t}\n\t}\n};\n\nContents.prototype.fontLoadListeners = function(target) {\n\tif (!this.document || !this.document.fonts) {\n\t\treturn;\n\t}\n\n\tthis.document.fonts.ready.then(function () {\n\t\tthis.expand();\n\t}.bind(this));\n\n};\n\nContents.prototype.root = function() {\n\tif(!this.document) return null;\n\treturn this.document.documentElement;\n};\n\nContents.prototype.locationOf = function(target, ignoreClass) {\n\tvar position;\n\tvar targetPos = {\"left\": 0, \"top\": 0};\n\n\tif(!this.document) return;\n\n\tif(this.epubcfi.isCfiString(target)) {\n\t\trange = new EpubCFI(target).toRange(this.document, ignoreClass);\n\n\t\tif(range) {\n\t\t\tif (range.startContainer.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\tposition = range.startContainer.getBoundingClientRect();\n\t\t\t\ttargetPos.left = position.left;\n\t\t\t\ttargetPos.top = position.top;\n\t\t\t} else {\n\t\t\t\tposition = range.getBoundingClientRect();\n\t\t\t\ttargetPos.left = position.left;\n\t\t\t\ttargetPos.top = position.top;\n\t\t\t}\n\t\t}\n\n\t} else if(typeof target === \"string\" &&\n\t\ttarget.indexOf(\"#\") > -1) {\n\n\t\tid = target.substring(target.indexOf(\"#\")+1);\n\t\tel = this.document.getElementById(id);\n\n\t\tif(el) {\n\t\t\tposition = el.getBoundingClientRect();\n\t\t\ttargetPos.left = position.left;\n\t\t\ttargetPos.top = position.top;\n\t\t}\n\t}\n\n\treturn targetPos;\n};\n\nContents.prototype.addStylesheet = function(src) {\n\treturn new RSVP.Promise(function(resolve, reject){\n\t\tvar $stylesheet;\n\t\tvar ready = false;\n\n\t\tif(!this.document) {\n\t\t\tresolve(false);\n\t\t\treturn;\n\t\t}\n\n\t\t$stylesheet = this.document.createElement('link');\n\t\t$stylesheet.type = 'text/css';\n\t\t$stylesheet.rel = \"stylesheet\";\n\t\t$stylesheet.href = src;\n\t\t$stylesheet.onload = $stylesheet.onreadystatechange = function() {\n\t\t\tif ( !ready && (!this.readyState || this.readyState == 'complete') ) {\n\t\t\t\tready = true;\n\t\t\t\t// Let apply\n\t\t\t\tsetTimeout(function(){\n\t\t\t\t\tresolve(true);\n\t\t\t\t}, 1);\n\t\t\t}\n\t\t};\n\n\t\tthis.document.head.appendChild($stylesheet);\n\n\t}.bind(this));\n};\n\n// https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule\nContents.prototype.addStylesheetRules = function(rules) {\n\tvar styleEl;\n\tvar styleSheet;\n\n\tif(!this.document) return;\n\n\tstyleEl = this.document.createElement('style');\n\n\t// Append style element to head\n\tthis.document.head.appendChild(styleEl);\n\n\t// Grab style sheet\n\tstyleSheet = styleEl.sheet;\n\n\tfor (var i = 0, rl = rules.length; i < rl; i++) {\n\t\tvar j = 1, rule = rules[i], selector = rules[i][0], propStr = '';\n\t\t// If the second argument of a rule is an array of arrays, correct our variables.\n\t\tif (Object.prototype.toString.call(rule[1][0]) === '[object Array]') {\n\t\t\trule = rule[1];\n\t\t\tj = 0;\n\t\t}\n\n\t\tfor (var pl = rule.length; j < pl; j++) {\n\t\t\tvar prop = rule[j];\n\t\t\tpropStr += prop[0] + ':' + prop[1] + (prop[2] ? ' !important' : '') + ';\\n';\n\t\t}\n\n\t\t// Insert CSS Rule\n\t\tstyleSheet.insertRule(selector + '{' + propStr + '}', styleSheet.cssRules.length);\n\t}\n};\n\nContents.prototype.addScript = function(src) {\n\n\treturn new RSVP.Promise(function(resolve, reject){\n\t\tvar $script;\n\t\tvar ready = false;\n\n\t\tif(!this.document) {\n\t\t\tresolve(false);\n\t\t\treturn;\n\t\t}\n\n\t\t$script = this.document.createElement('script');\n\t\t$script.type = 'text/javascript';\n\t\t$script.async = true;\n\t\t$script.src = src;\n\t\t$script.onload = $script.onreadystatechange = function() {\n\t\t\tif ( !ready && (!this.readyState || this.readyState == 'complete') ) {\n\t\t\t\tready = true;\n\t\t\t\tsetTimeout(function(){\n\t\t\t\t\tresolve(true);\n\t\t\t\t}, 1);\n\t\t\t}\n\t\t};\n\n\t\tthis.document.head.appendChild($script);\n\n\t}.bind(this));\n};\n\nContents.prototype.addEventListeners = function(){\n\tif(!this.document) {\n\t\treturn;\n\t}\n\tthis.listenedEvents.forEach(function(eventName){\n\t\tthis.document.addEventListener(eventName, this.triggerEvent.bind(this), false);\n\t}, this);\n\n};\n\nContents.prototype.removeEventListeners = function(){\n\tif(!this.document) {\n\t\treturn;\n\t}\n\tthis.listenedEvents.forEach(function(eventName){\n\t\tthis.document.removeEventListener(eventName, this.triggerEvent, false);\n\t}, this);\n\n};\n\n// Pass browser events\nContents.prototype.triggerEvent = function(e){\n\tthis.trigger(e.type, e);\n};\n\nContents.prototype.addSelectionListeners = function(){\n\tif(!this.document) {\n\t\treturn;\n\t}\n\tthis.document.addEventListener(\"selectionchange\", this.onSelectionChange.bind(this), false);\n};\n\nContents.prototype.removeSelectionListeners = function(){\n\tif(!this.document) {\n\t\treturn;\n\t}\n\tthis.document.removeEventListener(\"selectionchange\", this.onSelectionChange, false);\n};\n\nContents.prototype.onSelectionChange = function(e){\n\tif (this.selectionEndTimeout) {\n\t\tclearTimeout(this.selectionEndTimeout);\n\t}\n\tthis.selectionEndTimeout = setTimeout(function() {\n\t\tvar selection = this.window.getSelection();\n\t\tthis.triggerSelectedEvent(selection);\n\t}.bind(this), 500);\n};\n\nContents.prototype.triggerSelectedEvent = function(selection){\n\tvar range, cfirange;\n\n\tif (selection && selection.rangeCount > 0) {\n\t\trange = selection.getRangeAt(0);\n\t\tif(!range.collapsed) {\n\t\t\t// cfirange = this.section.cfiFromRange(range);\n\t\t\tcfirange = new EpubCFI(range, this.cfiBase).toString();\n\t\t\tthis.trigger(\"selected\", cfirange);\n\t\t\tthis.trigger(\"selectedRange\", range);\n\t\t}\n\t}\n};\n\nContents.prototype.range = function(_cfi, ignoreClass){\n\tvar cfi = new EpubCFI(_cfi);\n\treturn cfi.toRange(this.document, ignoreClass);\n};\n\nContents.prototype.map = function(layout){\n\tvar map = new Mapping(layout);\n\treturn map.section();\n};\n\nContents.prototype.size = function(width, height){\n\n\tif (width >= 0) {\n\t\tthis.width(width);\n\t}\n\n\tif (height >= 0) {\n\t\tthis.height(height);\n\t}\n\n\tthis.css(\"margin\", \"0\");\n\tthis.css(\"boxSizing\", \"border-box\");\n\n};\n\nContents.prototype.columns = function(width, height, columnWidth, gap){\n\tvar COLUMN_AXIS = core.prefixed('columnAxis');\n\tvar COLUMN_GAP = core.prefixed('columnGap');\n\tvar COLUMN_WIDTH = core.prefixed('columnWidth');\n\tvar COLUMN_FILL = core.prefixed('columnFill');\n\tvar textWidth;\n\n\tthis.width(width);\n\tthis.height(height);\n\n\t// Deal with Mobile trying to scale to viewport\n\tthis.viewport({ width: width, height: height, scale: 1.0 });\n\n\t// this.overflowY(\"hidden\");\n\tthis.css(\"overflowY\", \"hidden\");\n\tthis.css(\"margin\", \"0\");\n\tthis.css(\"boxSizing\", \"border-box\");\n\tthis.css(\"maxWidth\", \"inherit\");\n\n\tthis.css(COLUMN_AXIS, \"horizontal\");\n\tthis.css(COLUMN_FILL, \"auto\");\n\n\tthis.css(COLUMN_GAP, gap+\"px\");\n\tthis.css(COLUMN_WIDTH, columnWidth+\"px\");\n};\n\nContents.prototype.scale = function(scale, offsetX, offsetY){\n\tvar scale = \"scale(\" + scale + \")\";\n\tvar translate = '';\n\t// this.css(\"position\", \"absolute\"));\n\tthis.css(\"transformOrigin\", \"top left\");\n\n\tif (offsetX >= 0 || offsetY >= 0) {\n\t\ttranslate = \" translate(\" + (offsetX || 0 )+ \"px, \" + (offsetY || 0 )+ \"px )\";\n\t}\n\n\tthis.css(\"transform\", scale + translate);\n};\n\nContents.prototype.fit = function(width, height){\n\tvar viewport = this.viewport();\n\tvar widthScale = width / viewport.width;\n\tvar heightScale = height / viewport.height;\n\tvar scale = widthScale < heightScale ? widthScale : heightScale;\n\n\tvar offsetY = (height - (viewport.height * scale)) / 2;\n\n\tthis.width(width);\n\tthis.height(height);\n\tthis.overflow(\"hidden\");\n\n\t// Deal with Mobile trying to scale to viewport\n\tthis.viewport({ scale: 1.0 });\n\n\t// Scale to the correct size\n\tthis.scale(scale, 0, offsetY);\n\n\tthis.css(\"backgroundColor\", \"transparent\");\n};\n\nContents.prototype.mapPage = function(cfiBase, start, end) {\n\tvar mapping = new Mapping();\n\n\treturn mapping.page(this, cfiBase, start, end);\n};\n\nContents.prototype.destroy = function() {\n\t// Stop observing\n\tif(this.observer) {\n\t\tthis.observer.disconnect();\n\t}\n\n\tthis.removeListeners();\n\n};\n\nRSVP.EventTarget.mixin(Contents.prototype);\n\nmodule.exports = Contents;\n","var RSVP = require('rsvp');\nvar base64 = require('base64-js');\n\nvar requestAnimationFrame = (typeof window != 'undefined') ? (window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame) : false;\n/*\n//-- Parse the different parts of a url, returning a object\nfunction uri(url){\n\tvar uri = {\n\t\t\t\tprotocol : '',\n\t\t\t\thost : '',\n\t\t\t\tpath : '',\n\t\t\t\torigin : '',\n\t\t\t\tdirectory : '',\n\t\t\t\tbase : '',\n\t\t\t\tfilename : '',\n\t\t\t\textension : '',\n\t\t\t\tfragment : '',\n\t\t\t\thref : url\n\t\t\t},\n\t\t\tdoubleSlash = url.indexOf('://'),\n\t\t\tsearch = url.indexOf('?'),\n\t\t\tfragment = url.indexOf(\"#\"),\n\t\t\twithoutProtocol,\n\t\t\tdot,\n\t\t\tfirstSlash;\n\n\tif(fragment != -1) {\n\t\turi.fragment = url.slice(fragment + 1);\n\t\turl = url.slice(0, fragment);\n\t}\n\n\tif(search != -1) {\n\t\turi.search = url.slice(search + 1);\n\t\turl = url.slice(0, search);\n\t\thref = url;\n\t}\n\n\tif(doubleSlash != -1) {\n\t\turi.protocol = url.slice(0, doubleSlash);\n\t\twithoutProtocol = url.slice(doubleSlash+3);\n\t\tfirstSlash = withoutProtocol.indexOf('/');\n\n\t\tif(firstSlash === -1) {\n\t\t\turi.host = uri.path;\n\t\t\turi.path = \"\";\n\t\t} else {\n\t\t\turi.host = withoutProtocol.slice(0, firstSlash);\n\t\t\turi.path = withoutProtocol.slice(firstSlash);\n\t\t}\n\n\n\t\turi.origin = uri.protocol + \"://\" + uri.host;\n\n\t\turi.directory = folder(uri.path);\n\n\t\turi.base = uri.origin + uri.directory;\n\t\t// return origin;\n\t} else {\n\t\turi.path = url;\n\t\turi.directory = folder(url);\n\t\turi.base = uri.directory;\n\t}\n\n\t//-- Filename\n\turi.filename = url.replace(uri.base, '');\n\tdot = uri.filename.lastIndexOf('.');\n\tif(dot != -1) {\n\t\turi.extension = uri.filename.slice(dot+1);\n\t}\n\treturn uri;\n};\n\n//-- Parse out the folder, will return everything before the last slash\nfunction folder(url){\n\n\tvar lastSlash = url.lastIndexOf('/');\n\n\tif(lastSlash == -1) var folder = '';\n\n\tfolder = url.slice(0, lastSlash + 1);\n\n\treturn folder;\n\n};\n*/\nfunction isElement(obj) {\n\t\treturn !!(obj && obj.nodeType == 1);\n};\n\n// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript\nfunction uuid() {\n\tvar d = new Date().getTime();\n\tvar uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {\n\t\t\tvar r = (d + Math.random()*16)%16 | 0;\n\t\t\td = Math.floor(d/16);\n\t\t\treturn (c=='x' ? r : (r&0x7|0x8)).toString(16);\n\t});\n\treturn uuid;\n};\n\n// From Lodash\nfunction values(object) {\n\tvar index = -1,\n\t\t\tprops = Object.keys(object),\n\t\t\tlength = props.length,\n\t\t\tresult = Array(length);\n\n\twhile (++index < length) {\n\t\tresult[index] = object[props[index]];\n\t}\n\treturn result;\n};\n\nfunction resolveUrl(base, path) {\n\tvar url = [],\n\t\tsegments = [],\n\t\tbaseUri = uri(base),\n\t\tpathUri = uri(path),\n\t\tbaseDirectory = baseUri.directory,\n\t\tpathDirectory = pathUri.directory,\n\t\tdirectories = [],\n\t\t// folders = base.split(\"/\"),\n\t\tpaths;\n\n\t// if(uri.host) {\n\t// return path;\n\t// }\n\n\tif(baseDirectory[0] === \"/\") {\n\t\tbaseDirectory = baseDirectory.substring(1);\n\t}\n\n\tif(pathDirectory[pathDirectory.length-1] === \"/\") {\n\t\tbaseDirectory = baseDirectory.substring(0, baseDirectory.length-1);\n\t}\n\n\tif(pathDirectory[0] === \"/\") {\n\t\tpathDirectory = pathDirectory.substring(1);\n\t}\n\n\tif(pathDirectory[pathDirectory.length-1] === \"/\") {\n\t\tpathDirectory = pathDirectory.substring(0, pathDirectory.length-1);\n\t}\n\n\tif(baseDirectory) {\n\t\tdirectories = baseDirectory.split(\"/\");\n\t}\n\n\tpaths = pathDirectory.split(\"/\");\n\n\tpaths.reverse().forEach(function(part, index){\n\t\tif(part === \"..\"){\n\t\t\tdirectories.pop();\n\t\t} else if(part === directories[directories.length-1]) {\n\t\t\tdirectories.pop();\n\t\t\tsegments.unshift(part);\n\t\t} else {\n\t\t\tsegments.unshift(part);\n\t\t}\n\t});\n\n\turl = [baseUri.origin];\n\n\tif(directories.length) {\n\t\turl = url.concat(directories);\n\t}\n\n\tif(segments) {\n\t\turl = url.concat(segments);\n\t}\n\n\turl = url.concat(pathUri.filename);\n\n\treturn url.join(\"/\");\n};\n\nfunction documentHeight() {\n\treturn Math.max(\n\t\t\tdocument.documentElement.clientHeight,\n\t\t\tdocument.body.scrollHeight,\n\t\t\tdocument.documentElement.scrollHeight,\n\t\t\tdocument.body.offsetHeight,\n\t\t\tdocument.documentElement.offsetHeight\n\t);\n};\n\nfunction isNumber(n) {\n\treturn !isNaN(parseFloat(n)) && isFinite(n);\n};\n\nfunction prefixed(unprefixed) {\n\tvar vendors = [\"Webkit\", \"Moz\", \"O\", \"ms\" ],\n\t\tprefixes = ['-Webkit-', '-moz-', '-o-', '-ms-'],\n\t\tupper = unprefixed[0].toUpperCase() + unprefixed.slice(1),\n\t\tlength = vendors.length;\n\n\tif (typeof(document) === 'undefined' || typeof(document.body.style[unprefixed]) != 'undefined') {\n\t\treturn unprefixed;\n\t}\n\n\tfor ( var i=0; i < length; i++ ) {\n\t\tif (typeof(document.body.style[vendors[i] + upper]) != 'undefined') {\n\t\t\treturn vendors[i] + upper;\n\t\t}\n\t}\n\n\treturn unprefixed;\n};\n\nfunction defaults(obj) {\n\tfor (var i = 1, length = arguments.length; i < length; i++) {\n\t\tvar source = arguments[i];\n\t\tfor (var prop in source) {\n\t\t\tif (obj[prop] === void 0) obj[prop] = source[prop];\n\t\t}\n\t}\n\treturn obj;\n};\n\nfunction extend(target) {\n\t\tvar sources = [].slice.call(arguments, 1);\n\t\tsources.forEach(function (source) {\n\t\t\tif(!source) return;\n\t\t\tObject.getOwnPropertyNames(source).forEach(function(propName) {\n\t\t\t\tObject.defineProperty(target, propName, Object.getOwnPropertyDescriptor(source, propName));\n\t\t\t});\n\t\t});\n\t\treturn target;\n};\n\n// Fast quicksort insert for sorted array -- based on:\n// http://stackoverflow.com/questions/1344500/efficient-way-to-insert-a-number-into-a-sorted-array-of-numbers\nfunction insert(item, array, compareFunction) {\n\tvar location = locationOf(item, array, compareFunction);\n\tarray.splice(location, 0, item);\n\n\treturn location;\n};\n// Returns where something would fit in\nfunction locationOf(item, array, compareFunction, _start, _end) {\n\tvar start = _start || 0;\n\tvar end = _end || array.length;\n\tvar pivot = parseInt(start + (end - start) / 2);\n\tvar compared;\n\tif(!compareFunction){\n\t\tcompareFunction = function(a, b) {\n\t\t\tif(a > b) return 1;\n\t\t\tif(a < b) return -1;\n\t\t\tif(a = b) return 0;\n\t\t};\n\t}\n\tif(end-start <= 0) {\n\t\treturn pivot;\n\t}\n\n\tcompared = compareFunction(array[pivot], item);\n\tif(end-start === 1) {\n\t\treturn compared > 0 ? pivot : pivot + 1;\n\t}\n\n\tif(compared === 0) {\n\t\treturn pivot;\n\t}\n\tif(compared === -1) {\n\t\treturn locationOf(item, array, compareFunction, pivot, end);\n\t} else{\n\t\treturn locationOf(item, array, compareFunction, start, pivot);\n\t}\n};\n// Returns -1 of mpt found\nfunction indexOfSorted(item, array, compareFunction, _start, _end) {\n\tvar start = _start || 0;\n\tvar end = _end || array.length;\n\tvar pivot = parseInt(start + (end - start) / 2);\n\tvar compared;\n\tif(!compareFunction){\n\t\tcompareFunction = function(a, b) {\n\t\t\tif(a > b) return 1;\n\t\t\tif(a < b) return -1;\n\t\t\tif(a = b) return 0;\n\t\t};\n\t}\n\tif(end-start <= 0) {\n\t\treturn -1; // Not found\n\t}\n\n\tcompared = compareFunction(array[pivot], item);\n\tif(end-start === 1) {\n\t\treturn compared === 0 ? pivot : -1;\n\t}\n\tif(compared === 0) {\n\t\treturn pivot; // Found\n\t}\n\tif(compared === -1) {\n\t\treturn indexOfSorted(item, array, compareFunction, pivot, end);\n\t} else{\n\t\treturn indexOfSorted(item, array, compareFunction, start, pivot);\n\t}\n};\n\nfunction bounds(el) {\n\n\tvar style = window.getComputedStyle(el);\n\tvar widthProps = [\"width\", \"paddingRight\", \"paddingLeft\", \"marginRight\", \"marginLeft\", \"borderRightWidth\", \"borderLeftWidth\"];\n\tvar heightProps = [\"height\", \"paddingTop\", \"paddingBottom\", \"marginTop\", \"marginBottom\", \"borderTopWidth\", \"borderBottomWidth\"];\n\n\tvar width = 0;\n\tvar height = 0;\n\n\twidthProps.forEach(function(prop){\n\t\twidth += parseFloat(style[prop]) || 0;\n\t});\n\n\theightProps.forEach(function(prop){\n\t\theight += parseFloat(style[prop]) || 0;\n\t});\n\n\treturn {\n\t\theight: height,\n\t\twidth: width\n\t};\n\n};\n\nfunction borders(el) {\n\n\tvar style = window.getComputedStyle(el);\n\tvar widthProps = [\"paddingRight\", \"paddingLeft\", \"marginRight\", \"marginLeft\", \"borderRightWidth\", \"borderLeftWidth\"];\n\tvar heightProps = [\"paddingTop\", \"paddingBottom\", \"marginTop\", \"marginBottom\", \"borderTopWidth\", \"borderBottomWidth\"];\n\n\tvar width = 0;\n\tvar height = 0;\n\n\twidthProps.forEach(function(prop){\n\t\twidth += parseFloat(style[prop]) || 0;\n\t});\n\n\theightProps.forEach(function(prop){\n\t\theight += parseFloat(style[prop]) || 0;\n\t});\n\n\treturn {\n\t\theight: height,\n\t\twidth: width\n\t};\n\n};\n\nfunction windowBounds() {\n\n\tvar width = window.innerWidth;\n\tvar height = window.innerHeight;\n\n\treturn {\n\t\ttop: 0,\n\t\tleft: 0,\n\t\tright: width,\n\t\tbottom: height,\n\t\twidth: width,\n\t\theight: height\n\t};\n\n};\n\n//https://stackoverflow.com/questions/13482352/xquery-looking-for-text-with-single-quote/13483496#13483496\nfunction cleanStringForXpath(str) {\n\t\tvar parts = str.match(/[^'\"]+|['\"]/g);\n\t\tparts = parts.map(function(part){\n\t\t\t\tif (part === \"'\") {\n\t\t\t\t\t\treturn '\\\"\\'\\\"'; // output \"'\"\n\t\t\t\t}\n\n\t\t\t\tif (part === '\"') {\n\t\t\t\t\t\treturn \"\\'\\\"\\'\"; // output '\"'\n\t\t\t\t}\n\t\t\t\treturn \"\\'\" + part + \"\\'\";\n\t\t});\n\t\treturn \"concat(\\'\\',\" + parts.join(\",\") + \")\";\n};\n\nfunction indexOfTextNode(textNode){\n\tvar parent = textNode.parentNode;\n\tvar children = parent.childNodes;\n\tvar sib;\n\tvar index = -1;\n\tfor (var i = 0; i < children.length; i++) {\n\t\tsib = children[i];\n\t\tif(sib.nodeType === Node.TEXT_NODE){\n\t\t\tindex++;\n\t\t}\n\t\tif(sib == textNode) break;\n\t}\n\n\treturn index;\n};\n\nfunction isXml(ext) {\n\treturn ['xml', 'opf', 'ncx'].indexOf(ext) > -1;\n}\n\nfunction createBlob(content, mime){\n\tvar blob = new Blob([content], {type : mime });\n\n\treturn blob;\n};\n\nfunction createBlobUrl(content, mime){\n\tvar _URL = window.URL || window.webkitURL || window.mozURL;\n\tvar tempUrl;\n\tvar blob = this.createBlob(content, mime);\n\n\ttempUrl = _URL.createObjectURL(blob);\n\n\treturn tempUrl;\n};\n\nfunction createBase64Url(content, mime){\n\tvar string;\n\tvar data;\n\tvar datauri;\n\n\tif (typeof(content) !== \"string\") {\n\t\t// Only handles strings\n\t\treturn;\n\t}\n\n\tdata = btoa(content);\n\n\tdatauri = \"data:\" + mime + \";base64,\" + data;\n\n\treturn datauri;\n};\n\nfunction type(obj){\n\treturn Object.prototype.toString.call(obj).slice(8, -1);\n}\n\nfunction parse(markup, mime) {\n\tvar doc;\n\t// console.log(\"parse\", markup);\n\n\tif (typeof DOMParser === \"undefined\") {\n\t\tDOMParser = require('xmldom').DOMParser;\n\t}\n\n\n\tdoc = new DOMParser().parseFromString(markup, mime);\n\n\treturn doc;\n}\n\nfunction qs(el, sel) {\n\tvar elements;\n\n\tif (typeof el.querySelector != \"undefined\") {\n\t\treturn el.querySelector(sel);\n\t} else {\n\t\telements = el.getElementsByTagName(sel);\n\t\tif (elements.length) {\n\t\t\treturn elements[0];\n\t\t}\n\t}\n}\n\nfunction qsa(el, sel) {\n\n\tif (typeof el.querySelector != \"undefined\") {\n\t\treturn el.querySelectorAll(sel);\n\t} else {\n\t\treturn el.getElementsByTagName(sel);\n\t}\n}\n\nfunction qsp(el, sel, props) {\n\tvar q, filtered;\n\tif (typeof el.querySelector != \"undefined\") {\n\t\tsel += '[';\n\t\tfor (var prop in props) {\n\t\t\tsel += prop + \"='\" + props[prop] + \"'\";\n\t\t}\n\t\tsel += ']';\n\t\treturn el.querySelector(sel);\n\t} else {\n\t\tq = el.getElementsByTagName(sel);\n\t\tfiltered = Array.prototype.slice.call(q, 0).filter(function(el) {\n\t\t\tfor (var prop in props) {\n\t\t\t\tif(el.getAttribute(prop) === props[prop]){\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\n\t\tif (filtered) {\n\t\t\treturn filtered[0];\n\t\t}\n\t}\n}\n\nfunction blob2base64(blob, cb) {\n\tvar reader = new FileReader();\n\treader.readAsDataURL(blob);\n\treader.onloadend = function() {\n\t\tcb(reader.result);\n\t}\n}\n\nmodule.exports = {\n\t// 'uri': uri,\n\t// 'folder': folder,\n\t'isElement': isElement,\n\t'uuid': uuid,\n\t'values': values,\n\t'resolveUrl': resolveUrl,\n\t'indexOfSorted': indexOfSorted,\n\t'documentHeight': documentHeight,\n\t'isNumber': isNumber,\n\t'prefixed': prefixed,\n\t'defaults': defaults,\n\t'extend': extend,\n\t'insert': insert,\n\t'locationOf': locationOf,\n\t'indexOfSorted': indexOfSorted,\n\t'requestAnimationFrame': requestAnimationFrame,\n\t'bounds': bounds,\n\t'borders': borders,\n\t'windowBounds': windowBounds,\n\t'cleanStringForXpath': cleanStringForXpath,\n\t'indexOfTextNode': indexOfTextNode,\n\t'isXml': isXml,\n\t'createBlob': createBlob,\n\t'createBlobUrl': createBlobUrl,\n\t'type': type,\n\t'parse' : parse,\n\t'qs' : qs,\n\t'qsa' : qsa,\n\t'qsp' : qsp,\n\t'blob2base64' : blob2base64,\n\t'createBase64Url': createBase64Url\n};\n","var URI = require('urijs');\nvar core = require('./core');\n\n/**\n\tEPUB CFI spec: http://www.idpf.org/epub/linking/cfi/epub-cfi.html\n\n\tImplements:\n\t- Character Offset: epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)\n\t- Simple Ranges : epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)\n\n\tDoes Not Implement:\n\t- Temporal Offset (~)\n\t- Spatial Offset (@)\n\t- Temporal-Spatial Offset (~ + @)\n\t- Text Location Assertion ([)\n*/\n\nfunction EpubCFI(cfiFrom, base, ignoreClass){\n\tvar type;\n\n\tthis.str = '';\n\n\tthis.base = {};\n\tthis.spinePos = 0; // For compatibility\n\n\tthis.range = false; // true || false;\n\n\tthis.path = {};\n\tthis.start = null;\n\tthis.end = null;\n\n\t// Allow instantiation without the 'new' keyword\n\tif (!(this instanceof EpubCFI)) {\n\t\treturn new EpubCFI(cfiFrom, base, ignoreClass);\n\t}\n\n\tif(typeof base === 'string') {\n\t\tthis.base = this.parseComponent(base);\n\t} else if(typeof base === 'object' && base.steps) {\n\t\tthis.base = base;\n\t}\n\n\ttype = this.checkType(cfiFrom);\n\n\n\tif(type === 'string') {\n\t\tthis.str = cfiFrom;\n\t\treturn core.extend(this, this.parse(cfiFrom));\n\t} else if (type === 'range') {\n\t\treturn core.extend(this, this.fromRange(cfiFrom, this.base, ignoreClass));\n\t} else if (type === 'node') {\n\t\treturn core.extend(this, this.fromNode(cfiFrom, this.base, ignoreClass));\n\t} else if (type === 'EpubCFI' && cfiFrom.path) {\n\t\treturn cfiFrom;\n\t} else if (!cfiFrom) {\n\t\treturn this;\n\t} else {\n\t\tthrow new TypeError('not a valid argument for EpubCFI');\n\t}\n\n};\n\nEpubCFI.prototype.checkType = function(cfi) {\n\n\tif (this.isCfiString(cfi)) {\n\t\treturn 'string';\n\t// Is a range object\n\t} else if (typeof cfi === 'object' && core.type(cfi) === \"Range\"){\n\t\treturn 'range';\n\t} else if (typeof cfi === 'object' && typeof(cfi.nodeType) != \"undefined\" ){ // || typeof cfi === 'function'\n\t\treturn 'node';\n\t} else if (typeof cfi === 'object' && cfi instanceof EpubCFI){\n\t\treturn 'EpubCFI';\n\t} else {\n\t\treturn false;\n\t}\n};\n\nEpubCFI.prototype.parse = function(cfiStr) {\n\tvar cfi = {\n\t\t\tspinePos: -1,\n\t\t\trange: false,\n\t\t\tbase: {},\n\t\t\tpath: {},\n\t\t\tstart: null,\n\t\t\tend: null\n\t\t};\n\tvar baseComponent, pathComponent, range;\n\n\tif(typeof cfiStr !== \"string\") {\n\t\treturn {spinePos: -1};\n\t}\n\n\tif(cfiStr.indexOf(\"epubcfi(\") === 0 && cfiStr[cfiStr.length-1] === \")\") {\n\t\t// Remove intial epubcfi( and ending )\n\t\tcfiStr = cfiStr.slice(8, cfiStr.length-1);\n\t}\n\n\tbaseComponent = this.getChapterComponent(cfiStr);\n\n\t// Make sure this is a valid cfi or return\n\tif(!baseComponent) {\n\t\treturn {spinePos: -1};\n\t}\n\n\tcfi.base = this.parseComponent(baseComponent);\n\n\tpathComponent = this.getPathComponent(cfiStr);\n\tcfi.path = this.parseComponent(pathComponent);\n\n\trange = this.getRange(cfiStr);\n\n\tif(range) {\n\t\tcfi.range = true;\n\t\tcfi.start = this.parseComponent(range[0]);\n\t\tcfi.end = this.parseComponent(range[1]);\n\t}\n\n\t// Get spine node position\n\t// cfi.spineSegment = cfi.base.steps[1];\n\n\t// Chapter segment is always the second step\n\tcfi.spinePos = cfi.base.steps[1].index;\n\n\treturn cfi;\n};\n\nEpubCFI.prototype.parseComponent = function(componentStr){\n\tvar component = {\n\t\tsteps: [],\n\t\tterminal: {\n\t\t\toffset: null,\n\t\t\tassertion: null\n\t\t}\n\t};\n\tvar parts = componentStr.split(':');\n\tvar steps = parts[0].split('/');\n\tvar terminal;\n\n\tif(parts.length > 1) {\n\t\tterminal = parts[1];\n\t\tcomponent.terminal = this.parseTerminal(terminal);\n\t}\n\n\tif (steps[0] === '') {\n\t\tsteps.shift(); // Ignore the first slash\n\t}\n\n\tcomponent.steps = steps.map(function(step){\n\t\treturn this.parseStep(step);\n\t}.bind(this));\n\n\treturn component;\n};\n\nEpubCFI.prototype.parseStep = function(stepStr){\n\tvar type, num, index, has_brackets, id;\n\n\thas_brackets = stepStr.match(/\\[(.*)\\]/);\n\tif(has_brackets && has_brackets[1]){\n\t\tid = has_brackets[1];\n\t}\n\n\t//-- Check if step is a text node or element\n\tnum = parseInt(stepStr);\n\n\tif(isNaN(num)) {\n\t\treturn;\n\t}\n\n\tif(num % 2 === 0) { // Even = is an element\n\t\ttype = \"element\";\n\t\tindex = num / 2 - 1;\n\t} else {\n\t\ttype = \"text\";\n\t\tindex = (num - 1 ) / 2;\n\t}\n\n\treturn {\n\t\t\"type\" : type,\n\t\t'index' : index,\n\t\t'id' : id || null\n\t};\n};\n\nEpubCFI.prototype.parseTerminal = function(termialStr){\n\tvar characterOffset, textLocationAssertion;\n\tvar assertion = termialStr.match(/\\[(.*)\\]/);\n\n\tif(assertion && assertion[1]){\n\t\tcharacterOffset = parseInt(termialStr.split('[')[0]) || null;\n\t\ttextLocationAssertion = assertion[1];\n\t} else {\n\t\tcharacterOffset = parseInt(termialStr) || null;\n\t}\n\n\treturn {\n\t\t'offset': characterOffset,\n\t\t'assertion': textLocationAssertion\n\t};\n\n};\n\nEpubCFI.prototype.getChapterComponent = function(cfiStr) {\n\n\tvar indirection = cfiStr.split(\"!\");\n\n\treturn indirection[0];\n};\n\nEpubCFI.prototype.getPathComponent = function(cfiStr) {\n\n\tvar indirection = cfiStr.split(\"!\");\n\n\tif(indirection[1]) {\n\t\tranges = indirection[1].split(',');\n\t\treturn ranges[0];\n\t}\n\n};\n\nEpubCFI.prototype.getRange = function(cfiStr) {\n\n\tvar ranges = cfiStr.split(\",\");\n\n\tif(ranges.length === 3){\n\t\treturn [\n\t\t\tranges[1],\n\t\t\tranges[2]\n\t\t];\n\t}\n\n\treturn false;\n};\n\nEpubCFI.prototype.getCharecterOffsetComponent = function(cfiStr) {\n\tvar splitStr = cfiStr.split(\":\");\n\treturn splitStr[1] || '';\n};\n\nEpubCFI.prototype.joinSteps = function(steps) {\n\tif(!steps) {\n\t\treturn \"\";\n\t}\n\n\treturn steps.map(function(part){\n\t\tvar segment = '';\n\n\t\tif(part.type === 'element') {\n\t\t\tsegment += (part.index + 1) * 2;\n\t\t}\n\n\t\tif(part.type === 'text') {\n\t\t\tsegment += 1 + (2 * part.index); // TODO: double check that this is odd\n\t\t}\n\n\t\tif(part.id) {\n\t\t\tsegment += \"[\" + part.id + \"]\";\n\t\t}\n\n\t\treturn segment;\n\n\t}).join('/');\n\n};\n\nEpubCFI.prototype.segmentString = function(segment) {\n\tvar segmentString = '/';\n\n\tsegmentString += this.joinSteps(segment.steps);\n\n\tif(segment.terminal && segment.terminal.offset != null){\n\t\tsegmentString += ':' + segment.terminal.offset;\n\t}\n\n\tif(segment.terminal && segment.terminal.assertion != null){\n\t\tsegmentString += '[' + segment.terminal.assertion + ']';\n\t}\n\n\treturn segmentString;\n};\n\nEpubCFI.prototype.toString = function() {\n\tvar cfiString = 'epubcfi(';\n\n\tcfiString += this.segmentString(this.base);\n\n\tcfiString += '!';\n\tcfiString += this.segmentString(this.path);\n\n\t// Add Range, if present\n\tif(this.start) {\n\t\tcfiString += ',';\n\t\tcfiString += this.segmentString(this.start);\n\t}\n\n\tif(this.end) {\n\t\tcfiString += ',';\n\t\tcfiString += this.segmentString(this.end);\n\t}\n\n\tcfiString += \")\";\n\n\treturn cfiString;\n};\n\nEpubCFI.prototype.compare = function(cfiOne, cfiTwo) {\n\tif(typeof cfiOne === 'string') {\n\t\tcfiOne = new EpubCFI(cfiOne);\n\t}\n\tif(typeof cfiTwo === 'string') {\n\t\tcfiTwo = new EpubCFI(cfiTwo);\n\t}\n\t// Compare Spine Positions\n\tif(cfiOne.spinePos > cfiTwo.spinePos) {\n\t\treturn 1;\n\t}\n\tif(cfiOne.spinePos < cfiTwo.spinePos) {\n\t\treturn -1;\n\t}\n\n\n\t// Compare Each Step in the First item\n\tfor (var i = 0; i < cfiOne.path.steps.length; i++) {\n\t\tif(!cfiTwo.path.steps[i]) {\n\t\t\treturn 1;\n\t\t}\n\t\tif(cfiOne.path.steps[i].index > cfiTwo.path.steps[i].index) {\n\t\t\treturn 1;\n\t\t}\n\t\tif(cfiOne.path.steps[i].index < cfiTwo.path.steps[i].index) {\n\t\t\treturn -1;\n\t\t}\n\t\t// Otherwise continue checking\n\t}\n\n\t// All steps in First equal to Second and First is Less Specific\n\tif(cfiOne.path.steps.length < cfiTwo.path.steps.length) {\n\t\treturn 1;\n\t}\n\n\t// Compare the charecter offset of the text node\n\tif(cfiOne.path.terminal.offset > cfiTwo.path.terminal.offset) {\n\t\treturn 1;\n\t}\n\tif(cfiOne.path.terminal.offset < cfiTwo.path.terminal.offset) {\n\t\treturn -1;\n\t}\n\n\t// TODO: compare ranges\n\n\t// CFI's are equal\n\treturn 0;\n};\n\nEpubCFI.prototype.step = function(node) {\n\tvar nodeType = (node.nodeType === Node.TEXT_NODE) ? 'text' : 'element';\n\n\treturn {\n\t\t'id' : node.id,\n\t\t'tagName' : node.tagName,\n\t\t'type' : nodeType,\n\t\t'index' : this.position(node)\n\t};\n};\n\nEpubCFI.prototype.filteredStep = function(node, ignoreClass) {\n\tvar filteredNode = this.filter(node, ignoreClass);\n\tvar nodeType;\n\n\t// Node filtered, so ignore\n\tif (!filteredNode) {\n\t\treturn;\n\t}\n\n\t// Otherwise add the filter node in\n\tnodeType = (filteredNode.nodeType === Node.TEXT_NODE) ? 'text' : 'element';\n\n\treturn {\n\t\t'id' : filteredNode.id,\n\t\t'tagName' : filteredNode.tagName,\n\t\t'type' : nodeType,\n\t\t'index' : this.filteredPosition(filteredNode, ignoreClass)\n\t};\n};\n\nEpubCFI.prototype.pathTo = function(node, offset, ignoreClass) {\n\tvar segment = {\n\t\tsteps: [],\n\t\tterminal: {\n\t\t\toffset: null,\n\t\t\tassertion: null\n\t\t}\n\t};\n\tvar currentNode = node;\n\tvar step;\n\n\twhile(currentNode && currentNode.parentNode &&\n\t\t\t\tcurrentNode.parentNode.nodeType != Node.DOCUMENT_NODE) {\n\n\t\tif (ignoreClass) {\n\t\t\tstep = this.filteredStep(currentNode, ignoreClass);\n\t\t} else {\n\t\t\tstep = this.step(currentNode);\n\t\t}\n\n\t\tif (step) {\n\t\t\tsegment.steps.unshift(step);\n\t\t}\n\n\t\tcurrentNode = currentNode.parentNode;\n\n\t}\n\n\tif (offset != null && offset >= 0) {\n\n\t\tsegment.terminal.offset = offset;\n\n\t\t// Make sure we are getting to a textNode if there is an offset\n\t\tif(segment.steps[segment.steps.length-1].type != \"text\") {\n\t\t\tsegment.steps.push({\n\t\t\t\t'type' : \"text\",\n\t\t\t\t'index' : 0\n\t\t\t});\n\t\t}\n\n\t}\n\n\n\treturn segment;\n}\n\nEpubCFI.prototype.equalStep = function(stepA, stepB) {\n\tif (!stepA || !stepB) {\n\t\treturn false;\n\t}\n\n\tif(stepA.index === stepB.index &&\n\t\t stepA.id === stepB.id &&\n\t\t stepA.type === stepB.type) {\n\t\treturn true;\n\t}\n\n\treturn false;\n};\nEpubCFI.prototype.fromRange = function(range, base, ignoreClass) {\n\tvar cfi = {\n\t\t\trange: false,\n\t\t\tbase: {},\n\t\t\tpath: {},\n\t\t\tstart: null,\n\t\t\tend: null\n\t\t};\n\n\tvar start = range.startContainer;\n\tvar end = range.endContainer;\n\n\tvar startOffset = range.startOffset;\n\tvar endOffset = range.endOffset;\n\n\tvar needsIgnoring = false;\n\n\tif (ignoreClass) {\n\t\t// Tell pathTo if / what to ignore\n\t\tneedsIgnoring = (start.ownerDocument.querySelector('.' + ignoreClass) != null);\n\t}\n\n\n\tif (typeof base === 'string') {\n\t\tcfi.base = this.parseComponent(base);\n\t\tcfi.spinePos = cfi.base.steps[1].index;\n\t} else if (typeof base === 'object') {\n\t\tcfi.base = base;\n\t}\n\n\tif (range.collapsed) {\n\t\tif (needsIgnoring) {\n\t\t\tstartOffset = this.patchOffset(start, startOffset, ignoreClass);\n\t\t}\n\t\tcfi.path = this.pathTo(start, startOffset, ignoreClass);\n\t} else {\n\t\tcfi.range = true;\n\n\t\tif (needsIgnoring) {\n\t\t\tstartOffset = this.patchOffset(start, startOffset, ignoreClass);\n\t\t}\n\n\t\tcfi.start = this.pathTo(start, startOffset, ignoreClass);\n\n\t\tif (needsIgnoring) {\n\t\t\tendOffset = this.patchOffset(end, endOffset, ignoreClass);\n\t\t}\n\n\t\tcfi.end = this.pathTo(end, endOffset, ignoreClass);\n\n\t\t// Create a new empty path\n\t\tcfi.path = {\n\t\t\tsteps: [],\n\t\t\tterminal: null\n\t\t};\n\n\t\t// Push steps that are shared between start and end to the common path\n\t\tvar len = cfi.start.steps.length;\n\t\tvar i;\n\n\t\tfor (i = 0; i < len; i++) {\n\t\t\tif (this.equalStep(cfi.start.steps[i], cfi.end.steps[i])) {\n\t\t\t\tif(i == len-1) {\n\t\t\t\t\t// Last step is equal, check terminals\n\t\t\t\t\tif(cfi.start.terminal === cfi.end.terminal) {\n\t\t\t\t\t\t// CFI's are equal\n\t\t\t\t\t\tcfi.path.steps.push(cfi.start.steps[i]);\n\t\t\t\t\t\t// Not a range\n\t\t\t\t\t\tcfi.range = false;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tcfi.path.steps.push(cfi.start.steps[i]);\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t};\n\n\t\tcfi.start.steps = cfi.start.steps.slice(cfi.path.steps.length);\n\t\tcfi.end.steps = cfi.end.steps.slice(cfi.path.steps.length);\n\n\t\t// TODO: Add Sanity check to make sure that the end if greater than the start\n\t}\n\n\treturn cfi;\n}\n\nEpubCFI.prototype.fromNode = function(anchor, base, ignoreClass) {\n\tvar cfi = {\n\t\t\trange: false,\n\t\t\tbase: {},\n\t\t\tpath: {},\n\t\t\tstart: null,\n\t\t\tend: null\n\t\t};\n\n\tvar needsIgnoring = false;\n\n\tif (ignoreClass) {\n\t\t// Tell pathTo if / what to ignore\n\t\tneedsIgnoring = (anchor.ownerDocument.querySelector('.' + ignoreClass) != null);\n\t}\n\n\tif (typeof base === 'string') {\n\t\tcfi.base = this.parseComponent(base);\n\t\tcfi.spinePos = cfi.base.steps[1].index;\n\t} else if (typeof base === 'object') {\n\t\tcfi.base = base;\n\t}\n\n\tcfi.path = this.pathTo(anchor, null, ignoreClass);\n\n\treturn cfi;\n};\n\n\nEpubCFI.prototype.filter = function(anchor, ignoreClass) {\n\tvar needsIgnoring;\n\tvar sibling; // to join with\n\tvar parent, prevSibling, nextSibling;\n\tvar isText = false;\n\n\tif (anchor.nodeType === Node.TEXT_NODE) {\n\t\tisText = true;\n\t\tparent = anchor.parentNode;\n\t\tneedsIgnoring = anchor.parentNode.classList.contains(ignoreClass);\n\t} else {\n\t\tisText = false;\n\t\tneedsIgnoring = anchor.classList.contains(ignoreClass);\n\t}\n\n\tif (needsIgnoring && isText) {\n\t\tpreviousSibling = parent.previousSibling;\n\t\tnextSibling = parent.nextSibling;\n\n\t\t// If the sibling is a text node, join the nodes\n\t\tif (previousSibling && previousSibling.nodeType === Node.TEXT_NODE) {\n\t\t\tsibling = previousSibling;\n\t\t} else if (nextSibling && nextSibling.nodeType === Node.TEXT_NODE) {\n\t\t\tsibling = nextSibling;\n\t\t}\n\n\t\tif (sibling) {\n\t\t\treturn sibling;\n\t\t} else {\n\t\t\t// Parent will be ignored on next step\n\t\t\treturn anchor;\n\t\t}\n\n\t} else if (needsIgnoring && !isText) {\n\t\t// Otherwise just skip the element node\n\t\treturn false;\n\t} else {\n\t\t// No need to filter\n\t\treturn anchor;\n\t}\n\n};\n\nEpubCFI.prototype.patchOffset = function(anchor, offset, ignoreClass) {\n\tvar needsIgnoring;\n\tvar sibling;\n\n\tif (anchor.nodeType != Node.TEXT_NODE) {\n\t\tconsole.error(\"Anchor must be a text node\");\n\t\treturn;\n\t}\n\n\tvar curr = anchor;\n\tvar totalOffset = offset;\n\n\t// If the parent is a ignored node, get offset from it's start\n\tif (anchor.parentNode.classList.contains(ignoreClass)) {\n\t\tcurr = anchor.parentNode;\n\t}\n\n\twhile (curr.previousSibling) {\n\t\tif(curr.previousSibling.nodeType === Node.ELEMENT_NODE) {\n\t\t\t// Originally a text node, so join\n\t\t\tif(curr.previousSibling.classList.contains(ignoreClass)){\n\t\t\t\ttotalOffset += curr.previousSibling.textContent.length;\n\t\t\t} else {\n\t\t\t\tbreak; // Normal node, dont join\n\t\t\t}\n\t\t} else {\n\t\t\t// If the previous sibling is a text node, join the nodes\n\t\t\ttotalOffset += curr.previousSibling.textContent.length;\n\t\t}\n\n\t\tcurr = curr.previousSibling;\n\t}\n\n\treturn totalOffset;\n\n};\n\nEpubCFI.prototype.normalizedMap = function(children, nodeType, ignoreClass) {\n\tvar output = {};\n\tvar prevIndex = -1;\n\tvar i, len = children.length;\n\tvar currNodeType;\n\tvar prevNodeType;\n\n\tfor (i = 0; i < len; i++) {\n\n\t\tcurrNodeType = children[i].nodeType;\n\n\t\t// Check if needs ignoring\n\t\tif (currNodeType === Node.ELEMENT_NODE &&\n\t\t\t\tchildren[i].classList.contains(ignoreClass)) {\n\t\t\tcurrNodeType = Node.TEXT_NODE;\n\t\t}\n\n\t\tif (i > 0 &&\n\t\t\t\tcurrNodeType === Node.TEXT_NODE &&\n\t\t\t\tprevNodeType === Node.TEXT_NODE) {\n\t\t\t// join text nodes\n\t\t\toutput[i] = prevIndex;\n\t\t} else if (nodeType === currNodeType){\n\t\t\tprevIndex = prevIndex + 1;\n\t\t\toutput[i] = prevIndex;\n\t\t}\n\n\t\tprevNodeType = currNodeType;\n\n\t}\n\n\treturn output;\n};\n\nEpubCFI.prototype.position = function(anchor) {\n\tvar children, index, map;\n\n\tif (anchor.nodeType === Node.ELEMENT_NODE) {\n\t\tchildren = anchor.parentNode.children;\n\t\tindex = Array.prototype.indexOf.call(children, anchor);\n\t} else {\n\t\tchildren = this.textNodes(anchor.parentNode);\n\t\tindex = children.indexOf(anchor);\n\t}\n\n\treturn index;\n};\n\nEpubCFI.prototype.filteredPosition = function(anchor, ignoreClass) {\n\tvar children, index, map;\n\n\tif (anchor.nodeType === Node.ELEMENT_NODE) {\n\t\tchildren = anchor.parentNode.children;\n\t\tmap = this.normalizedMap(children, Node.ELEMENT_NODE, ignoreClass);\n\t} else {\n\t\tchildren = anchor.parentNode.childNodes;\n\t\t// Inside an ignored node\n\t\tif(anchor.parentNode.classList.contains(ignoreClass)) {\n\t\t\tanchor = anchor.parentNode;\n\t\t\tchildren = anchor.parentNode.childNodes;\n\t\t}\n\t\tmap = this.normalizedMap(children, Node.TEXT_NODE, ignoreClass);\n\t}\n\n\n\tindex = Array.prototype.indexOf.call(children, anchor);\n\n\treturn map[index];\n};\n\nEpubCFI.prototype.stepsToXpath = function(steps) {\n\tvar xpath = [\".\", \"*\"];\n\n\tsteps.forEach(function(step){\n\t\tvar position = step.index + 1;\n\n\t\tif(step.id){\n\t\t\txpath.push(\"*[position()=\" + position + \" and @id='\" + step.id + \"']\");\n\t\t} else if(step.type === \"text\") {\n\t\t\txpath.push(\"text()[\" + position + \"]\");\n\t\t} else {\n\t\t\txpath.push(\"*[\" + position + \"]\");\n\t\t}\n\t});\n\n\treturn xpath.join(\"/\");\n};\n\n\n/*\n\nTo get the last step if needed:\n\n// Get the terminal step\nlastStep = steps[steps.length-1];\n// Get the query string\nquery = this.stepsToQuery(steps);\n// Find the containing element\nstartContainerParent = doc.querySelector(query);\n// Find the text node within that element\nif(startContainerParent && lastStep.type == \"text\") {\n\tcontainer = startContainerParent.childNodes[lastStep.index];\n}\n*/\nEpubCFI.prototype.stepsToQuerySelector = function(steps) {\n\tvar query = [\"html\"];\n\n\tsteps.forEach(function(step){\n\t\tvar position = step.index + 1;\n\n\t\tif(step.id){\n\t\t\tquery.push(\"#\" + step.id);\n\t\t} else if(step.type === \"text\") {\n\t\t\t// unsupported in querySelector\n\t\t\t// query.push(\"text()[\" + position + \"]\");\n\t\t} else {\n\t\t\tquery.push(\"*:nth-child(\" + position + \")\");\n\t\t}\n\t});\n\n\treturn query.join(\">\");\n\n};\n\nEpubCFI.prototype.textNodes = function(container, ignoreClass) {\n\treturn Array.prototype.slice.call(container.childNodes).\n\t\tfilter(function (node) {\n\t\t\tif (node.nodeType === Node.TEXT_NODE) {\n\t\t\t\treturn true;\n\t\t\t} else if (ignoreClass && node.classList.contains(ignoreClass)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n};\n\nEpubCFI.prototype.walkToNode = function(steps, _doc, ignoreClass) {\n\tvar doc = _doc || document;\n\tvar container = doc.documentElement;\n\tvar step;\n\tvar len = steps.length;\n\tvar i;\n\n\tfor (i = 0; i < len; i++) {\n\t\tstep = steps[i];\n\n\t\tif(step.type === \"element\") {\n\t\t\tcontainer = container.children[step.index];\n\t\t} else if(step.type === \"text\"){\n\t\t\tcontainer = this.textNodes(container, ignoreClass)[step.index];\n\t\t}\n\n\t};\n\n\treturn container;\n};\n\nEpubCFI.prototype.findNode = function(steps, _doc, ignoreClass) {\n\tvar doc = _doc || document;\n\tvar container;\n\tvar xpath;\n\n\tif(!ignoreClass && typeof doc.evaluate != 'undefined') {\n\t\txpath = this.stepsToXpath(steps);\n\t\tcontainer = doc.evaluate(xpath, doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;\n\t} else if(ignoreClass) {\n\t\tcontainer = this.walkToNode(steps, doc, ignoreClass);\n\t} else {\n\t\tcontainer = this.walkToNode(steps, doc);\n\t}\n\n\treturn container;\n};\n\nEpubCFI.prototype.fixMiss = function(steps, offset, _doc, ignoreClass) {\n\tvar container = this.findNode(steps.slice(0,-1), _doc, ignoreClass);\n\tvar children = container.childNodes;\n\tvar map = this.normalizedMap(children, Node.TEXT_NODE, ignoreClass);\n\tvar i;\n\tvar child;\n\tvar len;\n\tvar childIndex;\n\tvar lastStepIndex = steps[steps.length-1].index;\n\n\tfor (var childIndex in map) {\n\t\tif (!map.hasOwnProperty(childIndex)) return;\n\n\t\tif(map[childIndex] === lastStepIndex) {\n\t\t\tchild = children[childIndex];\n\t\t\tlen = child.textContent.length;\n\t\t\tif(offset > len) {\n\t\t\t\toffset = offset - len;\n\t\t\t} else {\n\t\t\t\tif (child.nodeType === Node.ELEMENT_NODE) {\n\t\t\t\t\tcontainer = child.childNodes[0];\n\t\t\t\t} else {\n\t\t\t\t\tcontainer = child;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tcontainer: container,\n\t\toffset: offset\n\t};\n\n};\n\nEpubCFI.prototype.toRange = function(_doc, ignoreClass) {\n\tvar doc = _doc || document;\n\tvar range = doc.createRange();\n\tvar start, end, startContainer, endContainer;\n\tvar cfi = this;\n\tvar startSteps, endSteps;\n\tvar needsIgnoring = ignoreClass ? (doc.querySelector('.' + ignoreClass) != null) : false;\n\tvar missed;\n\n\tif (cfi.range) {\n\t\tstart = cfi.start;\n\t\tstartSteps = cfi.path.steps.concat(start.steps);\n\t\tstartContainer = this.findNode(startSteps, doc, needsIgnoring ? ignoreClass : null);\n\t\tend = cfi.end;\n\t\tendSteps = cfi.path.steps.concat(end.steps);\n\t\tendContainer = this.findNode(endSteps, doc, needsIgnoring ? ignoreClass : null);\n\t} else {\n\t\tstart = cfi.path;\n\t\tstartSteps = cfi.path.steps;\n\t\tstartContainer = this.findNode(cfi.path.steps, doc, needsIgnoring ? ignoreClass : null);\n\t}\n\n\tif(startContainer) {\n\t\ttry {\n\n\t\t\tif(start.terminal.offset != null) {\n\t\t\t\trange.setStart(startContainer, start.terminal.offset);\n\t\t\t} else {\n\t\t\t\trange.setStart(startContainer, 0);\n\t\t\t}\n\n\t\t} catch (e) {\n\t\t\tmissed = this.fixMiss(startSteps, start.terminal.offset, doc, needsIgnoring ? ignoreClass : null);\n\t\t\trange.setStart(missed.container, missed.offset);\n\t\t}\n\t} else {\n\t\t// No start found\n\t\treturn null;\n\t}\n\n\tif (endContainer) {\n\t\ttry {\n\n\t\t\tif(end.terminal.offset != null) {\n\t\t\t\trange.setEnd(endContainer, end.terminal.offset);\n\t\t\t} else {\n\t\t\t\trange.setEnd(endContainer, 0);\n\t\t\t}\n\n\t\t} catch (e) {\n\t\t\tmissed = this.fixMiss(endSteps, cfi.end.terminal.offset, doc, needsIgnoring ? ignoreClass : null);\n\t\t\trange.setEnd(missed.container, missed.offset);\n\t\t}\n\t}\n\n\n\t// doc.defaultView.getSelection().addRange(range);\n\treturn range;\n};\n\n// is a cfi string, should be wrapped with \"epubcfi()\"\nEpubCFI.prototype.isCfiString = function(str) {\n\tif(typeof str === 'string' &&\n\t\t\tstr.indexOf(\"epubcfi(\") === 0 &&\n\t\t\tstr[str.length-1] === \")\") {\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\nEpubCFI.prototype.generateChapterComponent = function(_spineNodeIndex, _pos, id) {\n\tvar pos = parseInt(_pos),\n\t\tspineNodeIndex = _spineNodeIndex + 1,\n\t\tcfi = '/'+spineNodeIndex+'/';\n\n\tcfi += (pos + 1) * 2;\n\n\tif(id) {\n\t\tcfi += \"[\" + id + \"]\";\n\t}\n\n\treturn cfi;\n};\n\nmodule.exports = EpubCFI;\n","var RSVP = require('rsvp');\n\n//-- Hooks allow for injecting functions that must all complete in order before finishing\n// They will execute in parallel but all must finish before continuing\n// Functions may return a promise if they are asycn.\n\n// this.content = new EPUBJS.Hook();\n// this.content.register(function(){});\n// this.content.trigger(args).then(function(){});\n\nfunction Hook(context){\n\tthis.context = context || this;\n\tthis.hooks = [];\n};\n\n// Adds a function to be run before a hook completes\nHook.prototype.register = function(){\n\tfor(var i = 0; i < arguments.length; ++i) {\n\t\tif (typeof arguments[i] === \"function\") {\n\t\t\tthis.hooks.push(arguments[i]);\n\t\t} else {\n\t\t\t// unpack array\n\t\t\tfor(var j = 0; j < arguments[i].length; ++j) {\n\t\t\t\tthis.hooks.push(arguments[i][j]);\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Triggers a hook to run all functions\nHook.prototype.trigger = function(){\n\tvar args = arguments;\n\tvar context = this.context;\n\tvar promises = [];\n\n\tthis.hooks.forEach(function(task, i) {\n\t\tvar executing = task.apply(context, args);\n\n\t\tif(executing && typeof executing[\"then\"] === \"function\") {\n\t\t\t// Task is a function that returns a promise\n\t\t\tpromises.push(executing);\n\t\t}\n\t\t// Otherwise Task resolves immediately, continue\n\t});\n\n\n\treturn RSVP.all(promises);\n};\n\n// Adds a function to be run before a hook completes\nHook.prototype.list = function(){\n\treturn this.hooks;\n};\n\nHook.prototype.clear = function(){\n\treturn this.hooks = [];\n};\n\nmodule.exports = Hook;\n","var core = require('./core');\nvar RSVP = require('rsvp');\n\nfunction Layout(settings){\n\tthis.name = settings.layout || \"reflowable\";\n\tthis._spread = (settings.spread === \"none\") ? false : true;\n\tthis._minSpreadWidth = settings.spread || 800;\n\tthis._evenSpreads = settings.evenSpreads || false;\n\n\tif (settings.flow === \"scrolled-continuous\" ||\n\t\t\tsettings.flow === \"scrolled-doc\") {\n\t\tthis._flow = \"scrolled\";\n\t} else {\n\t\tthis._flow = \"paginated\";\n\t}\n\n\n\tthis.width = 0;\n\tthis.height = 0;\n\tthis.spreadWidth = 0;\n\tthis.delta = 0;\n\n\tthis.columnWidth = 0;\n\tthis.gap = 0;\n\tthis.divisor = 1;\n};\n\n// paginated | scrolled\nLayout.prototype.flow = function(flow) {\n\tthis._flow = (flow === \"paginated\") ? \"paginated\" : \"scrolled\";\n}\n\n// true | false\nLayout.prototype.spread = function(spread, min) {\n\n\tthis._spread = (spread === \"none\") ? false : true;\n\n\tif (min >= 0) {\n\t\tthis._minSpreadWidth = min;\n\t}\n}\n\nLayout.prototype.calculate = function(_width, _height, _gap){\n\n\tvar divisor = 1;\n\tvar gap = _gap || 0;\n\n\t//-- Check the width and create even width columns\n\tvar fullWidth = Math.floor(_width);\n\tvar width = _width;\n\n\tvar section = Math.floor(width / 8);\n\n\tvar colWidth;\n\tvar spreadWidth;\n\tvar delta;\n\n\tif (this._spread && width >= this._minSpreadWidth) {\n\t\tdivisor = 2;\n\t} else {\n\t\tdivisor = 1;\n\t}\n\n\tif (this.name === \"reflowable\" && this._flow === \"paginated\" && !(_gap >= 0)) {\n\t\tgap = ((section % 2 === 0) ? section : section - 1);\n\t}\n\n\tif (this.name === \"pre-paginated\" ) {\n\t\tgap = 0;\n\t}\n\n\t//-- Double Page\n\tif(divisor > 1) {\n\t\tcolWidth = Math.floor((width - gap) / divisor);\n\t} else {\n\t\tcolWidth = width;\n\t}\n\n\tif (this.name === \"pre-paginated\" && divisor > 1) {\n\t\twidth = colWidth;\n\t}\n\n\tspreadWidth = colWidth * divisor;\n\n\tdelta = (colWidth + gap) * divisor;\n\n\tthis.width = width;\n\tthis.height = _height;\n\tthis.spreadWidth = spreadWidth;\n\tthis.delta = delta;\n\n\tthis.columnWidth = colWidth;\n\tthis.gap = gap;\n\tthis.divisor = divisor;\n};\n\nLayout.prototype.format = function(contents){\n\tvar formating;\n\n\tif (this.name === \"pre-paginated\") {\n\t\tformating = contents.fit(this.columnWidth, this.height);\n\t} else if (this._flow === \"paginated\") {\n\t\tformating = contents.columns(this.width, this.height, this.columnWidth, this.gap);\n\t} else { // scrolled\n\t\tformating = contents.size(this.width, null);\n\t}\n\n\treturn formating; // might be a promise in some View Managers\n};\n\nLayout.prototype.count = function(totalWidth) {\n\t// var totalWidth = contents.scrollWidth();\n\tvar spreads = Math.ceil( totalWidth / this.spreadWidth);\n\n\treturn {\n\t\tspreads : spreads,\n\t\tpages : spreads * this.divisor\n\t};\n};\n\nmodule.exports = Layout;\n","var core = require('./core');\nvar Queue = require('./queue');\nvar EpubCFI = require('./epubcfi');\nvar RSVP = require('rsvp');\n\nfunction Locations(spine, request) {\n\tthis.spine = spine;\n\tthis.request = request;\n\n\tthis.q = new Queue(this);\n\tthis.epubcfi = new EpubCFI();\n\n\tthis._locations = [];\n\tthis.total = 0;\n\n\tthis.break = 150;\n\n\tthis._current = 0;\n\n};\n\n// Load all of sections in the book\nLocations.prototype.generate = function(chars) {\n\n\tif (chars) {\n\t\tthis.break = chars;\n\t}\n\n\tthis.q.pause();\n\n\tthis.spine.each(function(section) {\n\n\t\tthis.q.enqueue(this.process, section);\n\n\t}.bind(this));\n\n\treturn this.q.run().then(function() {\n\t\tthis.total = this._locations.length-1;\n\n\t\tif (this._currentCfi) {\n\t\t\tthis.currentLocation = this._currentCfi;\n\t\t}\n\n\t\treturn this._locations;\n\t\t// console.log(this.precentage(this.book.rendition.location.start), this.precentage(this.book.rendition.location.end));\n\t}.bind(this));\n\n};\n\nLocations.prototype.process = function(section) {\n\n\treturn section.load(this.request)\n\t\t.then(function(contents) {\n\n\t\t\tvar range;\n\t\t\tvar doc = contents.ownerDocument;\n\t\t\tvar counter = 0;\n\n\t\t\tthis.sprint(contents, function(node) {\n\t\t\t\tvar len = node.length;\n\t\t\t\tvar dist;\n\t\t\t\tvar pos = 0;\n\n\t\t\t\t// Start range\n\t\t\t\tif (counter == 0) {\n\t\t\t\t\trange = doc.createRange();\n\t\t\t\t\trange.setStart(node, 0);\n\t\t\t\t}\n\n\t\t\t\tdist = this.break - counter;\n\n\t\t\t\t// Node is smaller than a break\n\t\t\t\tif(dist > len){\n\t\t\t\t\tcounter += len;\n\t\t\t\t\tpos = len;\n\t\t\t\t}\n\n\t\t\t\twhile (pos < len) {\n\t\t\t\t\tcounter = this.break;\n\t\t\t\t\tpos += this.break;\n\n\t\t\t\t\t// Gone over\n\t\t\t\t\tif(pos >= len){\n\t\t\t\t\t\t// Continue counter for next node\n\t\t\t\t\t\tcounter = len - (pos - this.break);\n\n\t\t\t\t\t// At End\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// End the previous range\n\t\t\t\t\t\trange.setEnd(node, pos);\n\t\t\t\t\t\tcfi = section.cfiFromRange(range);\n\t\t\t\t\t\tthis._locations.push(cfi);\n\t\t\t\t\t\tcounter = 0;\n\n\t\t\t\t\t\t// Start new range\n\t\t\t\t\t\tpos += 1;\n\t\t\t\t\t\trange = doc.createRange();\n\t\t\t\t\t\trange.setStart(node, pos);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\n\n\t\t\t}.bind(this));\n\n\t\t\t// Close remaining\n\t\t\tif (range) {\n\t\t\t\trange.setEnd(prev, prev.length);\n\t\t\t\tcfi = section.cfiFromRange(range);\n\t\t\t\tthis._locations.push(cfi)\n\t\t\t\tcounter = 0;\n\t\t\t}\n\n\t\t}.bind(this));\n\n};\n\nLocations.prototype.sprint = function(root, func) {\n\tvar treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);\n\n\twhile ((node = treeWalker.nextNode())) {\n\t\tfunc(node);\n\t}\n\n};\n\nLocations.prototype.locationFromCfi = function(cfi){\n\t// Check if the location has not been set yet\n\tif(this._locations.length === 0) {\n\t\treturn -1;\n\t}\n\n\treturn core.locationOf(cfi, this._locations, this.epubcfi.compare);\n};\n\nLocations.prototype.precentageFromCfi = function(cfi) {\n\t// Find closest cfi\n\tvar loc = this.locationFromCfi(cfi);\n\t// Get percentage in total\n\treturn this.precentageFromLocation(loc);\n};\n\nLocations.prototype.percentageFromLocation = function(loc) {\n\tif (!loc || !this.total) {\n\t\treturn 0;\n\t}\n\treturn (loc / this.total);\n};\n\nLocations.prototype.cfiFromLocation = function(loc){\n\tvar cfi = -1;\n\t// check that pg is an int\n\tif(typeof loc != \"number\"){\n\t\tloc = parseInt(pg);\n\t}\n\n\tif(loc >= 0 && loc < this._locations.length) {\n\t\tcfi = this._locations[loc];\n\t}\n\n\treturn cfi;\n};\n\nLocations.prototype.cfiFromPercentage = function(value){\n\tvar percentage = (value > 1) ? value / 100 : value; // Normalize value to 0-1\n\tvar loc = Math.ceil(this.total * percentage);\n\n\treturn this.cfiFromLocation(loc);\n};\n\nLocations.prototype.load = function(locations){\n\tthis._locations = JSON.parse(locations);\n\tthis.total = this._locations.length-1;\n\treturn this._locations;\n};\n\nLocations.prototype.save = function(json){\n\treturn JSON.stringify(this._locations);\n};\n\nLocations.prototype.getCurrent = function(json){\n\treturn this._current;\n};\n\nLocations.prototype.setCurrent = function(curr){\n\tvar loc;\n\n\tif(typeof curr == \"string\"){\n\t\tthis._currentCfi = curr;\n\t} else if (typeof curr == \"number\") {\n\t\tthis._current = curr;\n\t} else {\n\t\treturn;\n\t}\n\n\tif(this._locations.length === 0) {\n\t\treturn;\n\t}\n\n\tif(typeof curr == \"string\"){\n\t\tloc = this.locationFromCfi(curr);\n\t\tthis._current = loc;\n\t} else {\n\t\tloc = curr;\n\t}\n\n\tthis.trigger(\"changed\", {\n\t\tpercentage: this.precentageFromLocation(loc)\n\t});\n};\n\nObject.defineProperty(Locations.prototype, 'currentLocation', {\n\tget: function () {\n\t\treturn this._current;\n\t},\n\tset: function (curr) {\n\t\tthis.setCurrent(curr);\n\t}\n});\n\nRSVP.EventTarget.mixin(Locations.prototype);\n\nmodule.exports = Locations;\n","var RSVP = require('rsvp');\nvar core = require('../core');\nvar SingleViewManager = require('./single');\n\nfunction ContinuousViewManager(options) {\n\n\tSingleViewManager.apply(this, arguments); // call super constructor.\n\n\tthis.name = \"continuous\";\n\n\tthis.settings = core.extend(this.settings || {}, {\n\t\tinfinite: true,\n\t\toverflow: \"auto\",\n\t\taxis: \"vertical\",\n\t\toffset: 500,\n\t\toffsetDelta: 250,\n\t\twidth: undefined,\n\t\theight: undefined\n\t});\n\n\tcore.extend(this.settings, options.settings || {});\n\n\t// Gap can be 0, byt defaults doesn't handle that\n\tif (options.settings.gap != \"undefined\" && options.settings.gap === 0) {\n\t\tthis.settings.gap = options.settings.gap;\n\t}\n\n\t// this.viewSettings.axis = this.settings.axis;\n\tthis.viewSettings = {\n\t\tignoreClass: this.settings.ignoreClass,\n\t\taxis: this.settings.axis,\n\t\tlayout: this.layout,\n\t\twidth: 0,\n\t\theight: 0\n\t};\n\n\tthis.scrollTop = 0;\n\tthis.scrollLeft = 0;\n};\n\n// subclass extends superclass\nContinuousViewManager.prototype = Object.create(SingleViewManager.prototype);\nContinuousViewManager.prototype.constructor = ContinuousViewManager;\n\nContinuousViewManager.prototype.display = function(section, target){\n\treturn SingleViewManager.prototype.display.call(this, section, target)\n\t\t.then(function () {\n\t\t\treturn this.fill();\n\t\t}.bind(this));\n};\n\nContinuousViewManager.prototype.fill = function(_full){\n\tvar full = _full || new RSVP.defer();\n\n\tthis.check().then(function(result) {\n\t\tif (result) {\n\t\t\tthis.fill(full);\n\t\t} else {\n\t\t\tfull.resolve();\n\t\t}\n\t}.bind(this));\n\n\treturn full.promise;\n}\n\nContinuousViewManager.prototype.moveTo = function(offset){\n\t// var bounds = this.stage.bounds();\n\t// var dist = Math.floor(offset.top / bounds.height) * bounds.height;\n\tvar distX = 0,\n\t\t\tdistY = 0;\n\n\tvar offsetX = 0,\n\t\t\toffsetY = 0;\n\n\tif(this.settings.axis === \"vertical\") {\n\t\tdistY = offset.top;\n\t\toffsetY = offset.top+this.settings.offset;\n\t} else {\n\t\tdistX = Math.floor(offset.left / this.layout.delta) * this.layout.delta;\n\t\toffsetX = distX+this.settings.offset;\n\t}\n\n\treturn this.check(offsetX, offsetY)\n\t\t.then(function(){\n\t\t\tthis.scrollBy(distX, distY);\n\t\t}.bind(this));\n};\n\n/*\nContinuousViewManager.prototype.afterDisplayed = function(currView){\n\tvar next = currView.section.next();\n\tvar prev = currView.section.prev();\n\tvar index = this.views.indexOf(currView);\n\tvar prevView, nextView;\n\n\tif(index + 1 === this.views.length && next) {\n\t\tnextView = this.createView(next);\n\t\tthis.q.enqueue(this.append.bind(this), nextView);\n\t}\n\n\tif(index === 0 && prev) {\n\t\tprevView = this.createView(prev, this.viewSettings);\n\t\tthis.q.enqueue(this.prepend.bind(this), prevView);\n\t}\n\n\t// this.removeShownListeners(currView);\n\t// currView.onShown = this.afterDisplayed.bind(this);\n\tthis.trigger(\"added\", currView.section);\n\n};\n*/\n\nContinuousViewManager.prototype.resize = function(width, height){\n\n\t// Clear the queue\n\tthis.q.clear();\n\n\tthis._stageSize = this.stage.size(width, height);\n\tthis._bounds = this.bounds();\n\n\t// Update for new views\n\tthis.viewSettings.width = this._stageSize.width;\n\tthis.viewSettings.height = this._stageSize.height;\n\n\t// Update for existing views\n\tthis.views.each(function(view) {\n\t\tview.size(this._stageSize.width, this._stageSize.height);\n\t}.bind(this));\n\n\tthis.updateLayout();\n\n\t// if(this.location) {\n\t// this.rendition.display(this.location.start);\n\t// }\n\n\tthis.trigger(\"resized\", {\n\t\twidth: this.stage.width,\n\t\theight: this.stage.height\n\t});\n\n};\n\nContinuousViewManager.prototype.onResized = function(e) {\n\n\t// this.views.clear();\n\n\tclearTimeout(this.resizeTimeout);\n\tthis.resizeTimeout = setTimeout(function(){\n\t\tthis.resize();\n\t}.bind(this), 150);\n};\n\nContinuousViewManager.prototype.afterResized = function(view){\n\tthis.trigger(\"resize\", view.section);\n};\n\n// Remove Previous Listeners if present\nContinuousViewManager.prototype.removeShownListeners = function(view){\n\n\t// view.off(\"shown\", this.afterDisplayed);\n\t// view.off(\"shown\", this.afterDisplayedAbove);\n\tview.onDisplayed = function(){};\n\n};\n\n\n// ContinuousViewManager.prototype.append = function(section){\n// \treturn this.q.enqueue(function() {\n//\n// \t\tthis._append(section);\n//\n//\n// \t}.bind(this));\n// };\n//\n// ContinuousViewManager.prototype.prepend = function(section){\n// \treturn this.q.enqueue(function() {\n//\n// \t\tthis._prepend(section);\n//\n// \t}.bind(this));\n//\n// };\n\nContinuousViewManager.prototype.append = function(section){\n\tvar view = this.createView(section);\n\tthis.views.append(view);\n\treturn view;\n};\n\nContinuousViewManager.prototype.prepend = function(section){\n\tvar view = this.createView(section);\n\n\tview.on(\"resized\", this.counter.bind(this));\n\n\tthis.views.prepend(view);\n\treturn view;\n};\n\nContinuousViewManager.prototype.counter = function(bounds){\n\n\tif(this.settings.axis === \"vertical\") {\n\t\tthis.scrollBy(0, bounds.heightDelta, true);\n\t} else {\n\t\tthis.scrollBy(bounds.widthDelta, 0, true);\n\t}\n\n};\n\nContinuousViewManager.prototype.update = function(_offset){\n\tvar container = this.bounds();\n\tvar views = this.views.all();\n\tvar viewsLength = views.length;\n\tvar visible = [];\n\tvar offset = typeof _offset != \"undefined\" ? _offset : (this.settings.offset || 0);\n\tvar isVisible;\n\tvar view;\n\n\tvar updating = new RSVP.defer();\n\tvar promises = [];\n\n\tfor (var i = 0; i < viewsLength; i++) {\n\t\tview = views[i];\n\n\t\tisVisible = this.isVisible(view, offset, offset, container);\n\n\t\tif(isVisible === true) {\n\t\t\tif (!view.displayed) {\n\t\t\t\tpromises.push(view.display(this.request).then(function (view) {\n\t\t\t\t\tview.show();\n\t\t\t\t}));\n\t\t\t}\n\t\t\tvisible.push(view);\n\t\t} else {\n\t\t\tthis.q.enqueue(view.destroy.bind(view));\n\n\t\t\tclearTimeout(this.trimTimeout);\n\t\t\tthis.trimTimeout = setTimeout(function(){\n\t\t\t\tthis.q.enqueue(this.trim.bind(this));\n\t\t\t}.bind(this), 250);\n\t\t}\n\n\t}\n\n\tif(promises.length){\n\t\treturn RSVP.all(promises);\n\t} else {\n\t\tupdating.resolve();\n\t\treturn updating.promise;\n\t}\n\n};\n\nContinuousViewManager.prototype.check = function(_offsetLeft, _offsetTop){\n\tvar last, first, next, prev;\n\n\tvar checking = new RSVP.defer();\n\tvar newViews = [];\n\n\tvar horizontal = (this.settings.axis === \"horizontal\");\n\tvar delta = this.settings.offset || 0;\n\n\tif (_offsetLeft && horizontal) {\n\t\tdelta = _offsetLeft;\n\t}\n\n\tif (_offsetTop && !horizontal) {\n\t\tdelta = _offsetTop;\n\t}\n\n\tvar bounds = this._bounds; // bounds saved this until resize\n\n\tvar offset = horizontal ? this.scrollLeft : this.scrollTop;\n\tvar visibleLength = horizontal ? bounds.width : bounds.height;\n\tvar contentLength = horizontal ? this.container.scrollWidth : this.container.scrollHeight;\n\n\tif (offset + visibleLength + delta >= contentLength) {\n\t\tlast = this.views.last();\n\t\tnext = last && last.section.next();\n\t\tif(next) {\n\t\t\tnewViews.push(this.append(next));\n\t\t}\n\t}\n\n\tif (offset - delta < 0 ) {\n\t\tfirst = this.views.first();\n\t\tprev = first && first.section.prev();\n\t\tif(prev) {\n\t\t\tnewViews.push(this.prepend(prev));\n\t\t}\n\t}\n\n\tif(newViews.length){\n\t\t// RSVP.all(promises)\n\t\t\t// .then(function() {\n\t\t\t\t// Check to see if anything new is on screen after rendering\n\t\t\t\treturn this.q.enqueue(function(){\n\t\t\t\t\treturn this.update(delta);\n\t\t\t\t}.bind(this));\n\n\n\t\t\t// }.bind(this));\n\n\t} else {\n\t\tchecking.resolve(false);\n\t\treturn checking.promise;\n\t}\n\n\n};\n\nContinuousViewManager.prototype.trim = function(){\n\tvar task = new RSVP.defer();\n\tvar displayed = this.views.displayed();\n\tvar first = displayed[0];\n\tvar last = displayed[displayed.length-1];\n\tvar firstIndex = this.views.indexOf(first);\n\tvar lastIndex = this.views.indexOf(last);\n\tvar above = this.views.slice(0, firstIndex);\n\tvar below = this.views.slice(lastIndex+1);\n\n\t// Erase all but last above\n\tfor (var i = 0; i < above.length-1; i++) {\n\t\tthis.erase(above[i], above);\n\t}\n\n\t// Erase all except first below\n\tfor (var j = 1; j < below.length; j++) {\n\t\tthis.erase(below[j]);\n\t}\n\n\ttask.resolve();\n\treturn task.promise;\n};\n\nContinuousViewManager.prototype.erase = function(view, above){ //Trim\n\n\tvar prevTop;\n\tvar prevLeft;\n\n\tif(this.settings.height) {\n\t\tprevTop = this.container.scrollTop;\n\t\tprevLeft = this.container.scrollLeft;\n\t} else {\n\t\tprevTop = window.scrollY;\n\t\tprevLeft = window.scrollX;\n\t}\n\n\tvar bounds = view.bounds();\n\n\tthis.views.remove(view);\n\n\tif(above) {\n\n\t\tif(this.settings.axis === \"vertical\") {\n\t\t\tthis.scrollTo(0, prevTop - bounds.height, true);\n\t\t} else {\n\t\t\tthis.scrollTo(prevLeft - bounds.width, 0, true);\n\t\t}\n\t}\n\n};\n\nContinuousViewManager.prototype.addEventListeners = function(stage){\n\n\twindow.addEventListener('unload', function(e){\n\t\tthis.ignore = true;\n\t\t// this.scrollTo(0,0);\n\t\tthis.destroy();\n\t}.bind(this));\n\n\tthis.addScrollListeners();\n};\n\nContinuousViewManager.prototype.addScrollListeners = function() {\n\tvar scroller;\n\n\tthis.tick = core.requestAnimationFrame;\n\n\tif(this.settings.height) {\n\t\tthis.prevScrollTop = this.container.scrollTop;\n\t\tthis.prevScrollLeft = this.container.scrollLeft;\n\t} else {\n\t\tthis.prevScrollTop = window.scrollY;\n\t\tthis.prevScrollLeft = window.scrollX;\n\t}\n\n\tthis.scrollDeltaVert = 0;\n\tthis.scrollDeltaHorz = 0;\n\n\tif(this.settings.height) {\n\t\tscroller = this.container;\n\t\tthis.scrollTop = this.container.scrollTop;\n\t\tthis.scrollLeft = this.container.scrollLeft;\n\t} else {\n\t\tscroller = window;\n\t\tthis.scrollTop = window.scrollY;\n\t\tthis.scrollLeft = window.scrollX;\n\t}\n\n\tscroller.addEventListener(\"scroll\", this.onScroll.bind(this));\n\n\t// this.tick.call(window, this.onScroll.bind(this));\n\n\tthis.scrolled = false;\n\n};\n\nContinuousViewManager.prototype.onScroll = function(){\n\n\t// if(!this.ignore) {\n\n\t\tif(this.settings.height) {\n\t\t\tscrollTop = this.container.scrollTop;\n\t\t\tscrollLeft = this.container.scrollLeft;\n\t\t} else {\n\t\t\tscrollTop = window.scrollY;\n\t\t\tscrollLeft = window.scrollX;\n\t\t}\n\n\t\tthis.scrollTop = scrollTop;\n\t\tthis.scrollLeft = scrollLeft;\n\n\t\tif(!this.ignore) {\n\n\t\t\tif((this.scrollDeltaVert === 0 &&\n\t\t\t\t this.scrollDeltaHorz === 0) ||\n\t\t\t\t this.scrollDeltaVert > this.settings.offsetDelta ||\n\t\t\t\t this.scrollDeltaHorz > this.settings.offsetDelta) {\n\n\t\t\t\tthis.q.enqueue(function() {\n\t\t\t\t\tthis.check();\n\t\t\t\t}.bind(this));\n\t\t\t\t// this.check();\n\n\t\t\t\tthis.scrollDeltaVert = 0;\n\t\t\t\tthis.scrollDeltaHorz = 0;\n\n\t\t\t\tthis.trigger(\"scroll\", {\n\t\t\t\t\ttop: scrollTop,\n\t\t\t\t\tleft: scrollLeft\n\t\t\t\t});\n\n\t\t\t\tclearTimeout(this.afterScrolled);\n\t\t\t\tthis.afterScrolled = setTimeout(function () {\n\t\t\t\t\tthis.trigger(\"scrolled\", {\n\t\t\t\t\t\ttop: this.scrollTop,\n\t\t\t\t\t\tleft: this.scrollLeft\n\t\t\t\t\t});\n\t\t\t\t}.bind(this));\n\n\t\t\t}\n\n\t\t} else {\n\t\t\tthis.ignore = false;\n\t\t}\n\n\t\tthis.scrollDeltaVert += Math.abs(scrollTop-this.prevScrollTop);\n\t\tthis.scrollDeltaHorz += Math.abs(scrollLeft-this.prevScrollLeft);\n\n\t\tthis.prevScrollTop = scrollTop;\n\t\tthis.prevScrollLeft = scrollLeft;\n\n\t\tclearTimeout(this.scrollTimeout);\n\t\tthis.scrollTimeout = setTimeout(function(){\n\t\t\tthis.scrollDeltaVert = 0;\n\t\t\tthis.scrollDeltaHorz = 0;\n\t\t}.bind(this), 150);\n\n\n\t\tthis.scrolled = false;\n\t// }\n\n\t// this.tick.call(window, this.onScroll.bind(this));\n\n};\n\n\n// ContinuousViewManager.prototype.resizeView = function(view) {\n//\n// \tif(this.settings.axis === \"horizontal\") {\n// \t\tview.lock(\"height\", this.stage.width, this.stage.height);\n// \t} else {\n// \t\tview.lock(\"width\", this.stage.width, this.stage.height);\n// \t}\n//\n// };\n\nContinuousViewManager.prototype.currentLocation = function(){\n\n\tif (this.settings.axis === \"vertical\") {\n\t\tthis.location = this.scrolledLocation();\n\t} else {\n\t\tthis.location = this.paginatedLocation();\n\t}\n\n\treturn this.location;\n};\n\nContinuousViewManager.prototype.scrolledLocation = function(){\n\n\tvar visible = this.visible();\n\tvar startPage, endPage;\n\n\tvar container = this.container.getBoundingClientRect();\n\n\tif(visible.length === 1) {\n\t\treturn this.mapping.page(visible[0].contents, visible[0].section.cfiBase);\n\t}\n\n\tif(visible.length > 1) {\n\n\t\tstartPage = this.mapping.page(visible[0].contents, visible[0].section.cfiBase);\n\t\tendPage = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase);\n\n\t\treturn {\n\t\t\tstart: startPage.start,\n\t\t\tend: endPage.end\n\t\t};\n\t}\n\n};\n\nContinuousViewManager.prototype.paginatedLocation = function(){\n\tvar visible = this.visible();\n\tvar startA, startB, endA, endB;\n\tvar pageLeft, pageRight;\n\tvar container = this.container.getBoundingClientRect();\n\n\tif(visible.length === 1) {\n\t\tstartA = container.left - visible[0].position().left;\n\t\tendA = startA + this.layout.spreadWidth;\n\n\t\treturn this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA);\n\t}\n\n\tif(visible.length > 1) {\n\n\t\t// Left Col\n\t\tstartA = container.left - visible[0].position().left;\n\t\tendA = startA + this.layout.columnWidth;\n\n\t\t// Right Col\n\t\tstartB = container.left + this.layout.spreadWidth - visible[visible.length-1].position().left;\n\t\tendB = startB + this.layout.columnWidth;\n\n\t\tpageLeft = this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA);\n\t\tpageRight = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase, startB, endB);\n\n\t\treturn {\n\t\t\tstart: pageLeft.start,\n\t\t\tend: pageRight.end\n\t\t};\n\t}\n};\n\n/*\nContinuous.prototype.current = function(what){\n\tvar view, top;\n\tvar container = this.container.getBoundingClientRect();\n\tvar length = this.views.length - 1;\n\n\tif(this.settings.axis === \"horizontal\") {\n\n\t\tfor (var i = length; i >= 0; i--) {\n\t\t\tview = this.views[i];\n\t\t\tleft = view.position().left;\n\n\t\t\tif(left < container.right) {\n\n\t\t\t\tif(this._current == view) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tthis._current = view;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t} else {\n\n\t\tfor (var i = length; i >= 0; i--) {\n\t\t\tview = this.views[i];\n\t\t\ttop = view.bounds().top;\n\t\t\tif(top < container.bottom) {\n\n\t\t\t\tif(this._current == view) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tthis._current = view;\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t}\n\n\treturn this._current;\n};\n*/\n\nContinuousViewManager.prototype.updateLayout = function() {\n\n\tif (!this.stage) {\n\t\treturn;\n\t}\n\n\tif(this.settings.axis === \"vertical\") {\n\t\tthis.layout.calculate(this._stageSize.width, this._stageSize.height);\n\t} else {\n\t\tthis.layout.calculate(\n\t\t\tthis._stageSize.width,\n\t\t\tthis._stageSize.height,\n\t\t\tthis.settings.gap\n\t\t);\n\n\t\t// Set the look ahead offset for what is visible\n\t\tthis.settings.offset = this.layout.delta;\n\n\t\tthis.stage.addStyleRules(\"iframe\", [{\"margin-right\" : this.layout.gap + \"px\"}]);\n\n\t}\n\n\t// Set the dimensions for views\n\tthis.viewSettings.width = this.layout.width;\n\tthis.viewSettings.height = this.layout.height;\n\n\tthis.setLayout(this.layout);\n\n};\n\nContinuousViewManager.prototype.next = function(){\n\n\tif(this.settings.axis === \"horizontal\") {\n\n\t\tthis.scrollLeft = this.container.scrollLeft;\n\n\t\tif(this.container.scrollLeft +\n\t\t\t this.container.offsetWidth +\n\t\t\t this.layout.delta < this.container.scrollWidth) {\n\t\t\tthis.scrollBy(this.layout.delta, 0);\n\t\t} else {\n\t\t\tthis.scrollTo(this.container.scrollWidth - this.layout.delta, 0);\n\t\t}\n\n\t} else {\n\t\tthis.scrollBy(0, this.layout.height);\n\t}\n};\n\nContinuousViewManager.prototype.prev = function(){\n\tif(this.settings.axis === \"horizontal\") {\n\t\tthis.scrollBy(-this.layout.delta, 0);\n\t} else {\n\t\tthis.scrollBy(0, -this.layout.height);\n\t}\n};\n\nContinuousViewManager.prototype.updateFlow = function(flow){\n\tvar axis = (flow === \"paginated\") ? \"horizontal\" : \"vertical\";\n\n\tthis.settings.axis = axis;\n\n\tthis.viewSettings.axis = axis;\n\n\tthis.settings.overflow = (flow === \"paginated\") ? \"hidden\" : \"auto\";\n\n\t// this.views.each(function(view){\n\t// \tview.setAxis(axis);\n\t// });\n\n\tif (this.settings.axis === \"vertical\") {\n\t\tthis.settings.infinite = true;\n\t} else {\n\t\tthis.settings.infinite = false;\n\t}\n\n};\nmodule.exports = ContinuousViewManager;\n","var RSVP = require('rsvp');\nvar core = require('../core');\nvar Stage = require('../stage');\nvar Views = require('../views');\nvar EpubCFI = require('../epubcfi');\n// var Layout = require('../layout');\nvar Mapping = require('../mapping');\nvar Queue = require('../queue');\n\nfunction SingleViewManager(options) {\n\n\tthis.name = \"single\";\n\tthis.View = options.view;\n\tthis.request = options.request;\n\tthis.renditionQueue = options.queue;\n\tthis.q = new Queue(this);\n\n\tthis.settings = core.extend(this.settings || {}, {\n\t\tinfinite: true,\n\t\thidden: false,\n\t\twidth: undefined,\n\t\theight: undefined,\n\t\t// globalLayoutProperties : { layout: 'reflowable', spread: 'auto', orientation: 'auto'},\n\t\t// layout: null,\n\t\taxis: \"vertical\",\n\t\tignoreClass: ''\n\t});\n\n\tcore.extend(this.settings, options.settings || {});\n\n\tthis.viewSettings = {\n\t\tignoreClass: this.settings.ignoreClass,\n\t\taxis: this.settings.axis,\n\t\tlayout: this.layout,\n\t\twidth: 0,\n\t\theight: 0\n\t};\n\n}\n\nSingleViewManager.prototype.render = function(element, size){\n\n\t// Save the stage\n\tthis.stage = new Stage({\n\t\twidth: size.width,\n\t\theight: size.height,\n\t\toverflow: this.settings.overflow,\n\t\thidden: this.settings.hidden,\n\t\taxis: this.settings.axis\n\t});\n\n\tthis.stage.attachTo(element);\n\n\t// Get this stage container div\n\tthis.container = this.stage.getContainer();\n\n\t// Views array methods\n\tthis.views = new Views(this.container);\n\n\t// Calculate Stage Size\n\tthis._bounds = this.bounds();\n\tthis._stageSize = this.stage.size();\n\n\t// Set the dimensions for views\n\tthis.viewSettings.width = this._stageSize.width;\n\tthis.viewSettings.height = this._stageSize.height;\n\n\t// Function to handle a resize event.\n\t// Will only attach if width and height are both fixed.\n\tthis.stage.onResize(this.onResized.bind(this));\n\n\t// Add Event Listeners\n\tthis.addEventListeners();\n\n\t// Add Layout method\n\t// this.applyLayoutMethod();\n\tif (this.layout) {\n\t\tthis.updateLayout();\n\t}\n};\n\nSingleViewManager.prototype.addEventListeners = function(){\n\twindow.addEventListener('unload', function(e){\n\t\tthis.destroy();\n\t}.bind(this));\n};\n\nSingleViewManager.prototype.destroy = function(){\n\t// this.views.each(function(view){\n\t// \tview.destroy();\n\t// });\n};\n\nSingleViewManager.prototype.onResized = function(e) {\n\tclearTimeout(this.resizeTimeout);\n\tthis.resizeTimeout = setTimeout(function(){\n\t\tthis.resize();\n\t}.bind(this), 150);\n};\n\nSingleViewManager.prototype.resize = function(width, height){\n\n\t// Clear the queue\n\tthis.q.clear();\n\n\tthis._stageSize = this.stage.size(width, height);\n\tthis._bounds = this.bounds();\n\n\t// Update for new views\n\tthis.viewSettings.width = this._stageSize.width;\n\tthis.viewSettings.height = this._stageSize.height;\n\n\t// Update for existing views\n\tthis.views.each(function(view) {\n\t\tview.size(this._stageSize.width, this._stageSize.height);\n\t}.bind(this));\n\n\tthis.updateLayout();\n\n\tthis.trigger(\"resized\", {\n\t\twidth: this.stage.width,\n\t\theight: this.stage.height\n\t});\n\n};\n\nSingleViewManager.prototype.createView = function(section) {\n\treturn new this.View(section, this.viewSettings);\n};\n\nSingleViewManager.prototype.display = function(section, target){\n\n\tvar displaying = new RSVP.defer();\n\tvar displayed = displaying.promise;\n\n\t// Check to make sure the section we want isn't already shown\n\tvar visible = this.views.find(section);\n\n\t// View is already shown, just move to correct location\n\tif(visible && target) {\n\t\toffset = visible.locationOf(target);\n\t\tthis.moveTo(offset);\n\t\tdisplaying.resolve();\n\t\treturn displayed;\n\t}\n\n\t// Hide all current views\n\tthis.views.hide();\n\n\tthis.views.clear();\n\n\tthis.add(section)\n\t\t.then(function(){\n\t\t\tvar next;\n\t\t\tif (this.layout.name === \"pre-paginated\" &&\n\t\t\t\t\tthis.layout.divisor > 1) {\n\t\t\t\tnext = section.next();\n\t\t\t\tif (next) {\n\t\t\t\t\treturn this.add(next);\n\t\t\t\t}\n\t\t\t}\n\t\t}.bind(this))\n\t\t.then(function(view){\n\n\t\t\t// Move to correct place within the section, if needed\n\t\t\tif(target) {\n\t\t\t\toffset = view.locationOf(target);\n\t\t\t\tthis.moveTo(offset);\n\t\t\t}\n\n\t\t\tthis.views.show();\n\n\t\t\tdisplaying.resolve();\n\n\t\t}.bind(this))\n\t\t// .then(function(){\n\t\t// \treturn this.hooks.display.trigger(view);\n\t\t// }.bind(this))\n\t\t// .then(function(){\n\t\t// \tthis.views.show();\n\t\t// }.bind(this));\n\t\treturn displayed;\n};\n\nSingleViewManager.prototype.afterDisplayed = function(view){\n\tthis.trigger(\"added\", view);\n};\n\nSingleViewManager.prototype.afterResized = function(view){\n\tthis.trigger(\"resize\", view.section);\n};\n\n// SingleViewManager.prototype.moveTo = function(offset){\n// \tthis.scrollTo(offset.left, offset.top);\n// };\n\nSingleViewManager.prototype.moveTo = function(offset){\n\tvar distX = 0,\n\t\t\tdistY = 0;\n\n\tif(this.settings.axis === \"vertical\") {\n\t\tdistY = offset.top;\n\t} else {\n\t\tdistX = Math.floor(offset.left / this.layout.delta) * this.layout.delta;\n\n\t\tif (distX + this.layout.delta > this.container.scrollWidth) {\n\t\t\tdistX = this.container.scrollWidth - this.layout.delta;\n\t\t}\n\t}\n\n\tthis.scrollTo(distX, distY);\n};\n\nSingleViewManager.prototype.add = function(section){\n\tvar view = this.createView(section);\n\n\tthis.views.append(view);\n\n\t// view.on(\"shown\", this.afterDisplayed.bind(this));\n\tview.onDisplayed = this.afterDisplayed.bind(this);\n\tview.onResize = this.afterResized.bind(this);\n\n\treturn view.display(this.request);\n\n};\n\nSingleViewManager.prototype.append = function(section){\n\tvar view = this.createView(section);\n\tthis.views.append(view);\n\treturn view.display(this.request);\n};\n\nSingleViewManager.prototype.prepend = function(section){\n\tvar view = this.createView(section);\n\n\tthis.views.prepend(view);\n\treturn view.display(this.request);\n};\n// SingleViewManager.prototype.resizeView = function(view) {\n//\n// \tif(this.settings.globalLayoutProperties.layout === \"pre-paginated\") {\n// \t\tview.lock(\"both\", this.bounds.width, this.bounds.height);\n// \t} else {\n// \t\tview.lock(\"width\", this.bounds.width, this.bounds.height);\n// \t}\n//\n// };\n\nSingleViewManager.prototype.next = function(){\n\tvar next;\n\tvar view;\n\tvar left;\n\n\tif(!this.views.length) return;\n\n\tif(this.settings.axis === \"horizontal\") {\n\n\t\tthis.scrollLeft = this.container.scrollLeft;\n\n\t\tleft = this.container.scrollLeft + this.container.offsetWidth + this.layout.delta;\n\n\t\tif(left < this.container.scrollWidth) {\n\t\t\tthis.scrollBy(this.layout.delta, 0);\n\t\t} else if (left - this.layout.columnWidth === this.container.scrollWidth) {\n\t\t\tthis.scrollTo(this.container.scrollWidth - this.layout.delta, 0);\n\t\t} else {\n\t\t\tnext = this.views.last().section.next();\n\t\t}\n\n\n\t} else {\n\n\t\tnext = this.views.last().section.next();\n\n\t}\n\n\tif(next) {\n\t\tthis.views.clear();\n\n\t\treturn this.append(next)\n\t\t\t.then(function(){\n\t\t\t\tvar right;\n\t\t\t\tif (this.layout.name && this.layout.divisor > 1) {\n\t\t\t\t\tright = next.next();\n\t\t\t\t\tif (right) {\n\t\t\t\t\t\treturn this.append(right);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}.bind(this))\n\t\t\t.then(function(){\n\t\t\t\tthis.views.show();\n\t\t\t}.bind(this));\n\t}\n\n\n};\n\nSingleViewManager.prototype.prev = function(){\n\tvar prev;\n\tvar view;\n\tvar left;\n\n\tif(!this.views.length) return;\n\n\tif(this.settings.axis === \"horizontal\") {\n\n\t\tthis.scrollLeft = this.container.scrollLeft;\n\n\t\tleft = this.container.scrollLeft;\n\n\t\tif(left > 0) {\n\t\t\tthis.scrollBy(-this.layout.delta, 0);\n\t\t} else {\n\t\t\tprev = this.views.first().section.prev();\n\t\t}\n\n\n\t} else {\n\n\t\tprev = this.views.first().section.prev();\n\n\t}\n\n\tif(prev) {\n\t\tthis.views.clear();\n\n\t\treturn this.prepend(prev)\n\t\t\t.then(function(){\n\t\t\t\tvar left;\n\t\t\t\tif (this.layout.name && this.layout.divisor > 1) {\n\t\t\t\t\tleft = prev.prev();\n\t\t\t\t\tif (left) {\n\t\t\t\t\t\treturn this.prepend(left);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}.bind(this))\n\t\t\t.then(function(){\n\t\t\t\tif(this.settings.axis === \"horizontal\") {\n\t\t\t\t\tthis.scrollTo(this.container.scrollWidth - this.layout.delta, 0);\n\t\t\t\t}\n\t\t\t\tthis.views.show();\n\t\t\t}.bind(this));\n\t}\n};\n\nSingleViewManager.prototype.current = function(){\n\tvar visible = this.visible();\n\tif(visible.length){\n\t\t// Current is the last visible view\n\t\treturn visible[visible.length-1];\n\t}\n\treturn null;\n};\n\nSingleViewManager.prototype.currentLocation = function(){\n\tvar view;\n\tvar start, end;\n\n\tif(this.views.length) {\n\t\tview = this.views.first();\n\t\tstart = container.left - view.position().left;\n\t\tend = start + this.layout.spread;\n\n\t\treturn this.mapping.page(view, view.section.cfiBase);\n\t}\n\n};\n\nSingleViewManager.prototype.isVisible = function(view, offsetPrev, offsetNext, _container){\n\tvar position = view.position();\n\tvar container = _container || this.bounds();\n\n\tif(this.settings.axis === \"horizontal\" &&\n\t\tposition.right > container.left - offsetPrev &&\n\t\tposition.left < container.right + offsetNext) {\n\n\t\treturn true;\n\n\t} else if(this.settings.axis === \"vertical\" &&\n\t\tposition.bottom > container.top - offsetPrev &&\n\t\tposition.top < container.bottom + offsetNext) {\n\n\t\treturn true;\n\t}\n\n\treturn false;\n\n};\n\nSingleViewManager.prototype.visible = function(){\n\t// return this.views.displayed();\n\tvar container = this.bounds();\n\tvar views = this.views.displayed();\n\tvar viewsLength = views.length;\n\tvar visible = [];\n\tvar isVisible;\n\tvar view;\n\n\tfor (var i = 0; i < viewsLength; i++) {\n\t\tview = views[i];\n\t\tisVisible = this.isVisible(view, 0, 0, container);\n\n\t\tif(isVisible === true) {\n\t\t\tvisible.push(view);\n\t\t}\n\n\t}\n\treturn visible;\n};\n\nSingleViewManager.prototype.scrollBy = function(x, y, silent){\n\tif(silent) {\n\t\tthis.ignore = true;\n\t}\n\n\tif(this.settings.height) {\n\n\t\tif(x) this.container.scrollLeft += x;\n\t\tif(y) this.container.scrollTop += y;\n\n\t} else {\n\t\twindow.scrollBy(x,y);\n\t}\n\t// console.log(\"scrollBy\", x, y);\n\tthis.scrolled = true;\n\tthis.onScroll();\n};\n\nSingleViewManager.prototype.scrollTo = function(x, y, silent){\n\tif(silent) {\n\t\tthis.ignore = true;\n\t}\n\n\tif(this.settings.height) {\n\t\tthis.container.scrollLeft = x;\n\t\tthis.container.scrollTop = y;\n\t} else {\n\t\twindow.scrollTo(x,y);\n\t}\n\t// console.log(\"scrollTo\", x, y);\n\tthis.scrolled = true;\n\tthis.onScroll();\n\t// if(this.container.scrollLeft != x){\n\t// setTimeout(function() {\n\t// this.scrollTo(x, y, silent);\n\t// }.bind(this), 10);\n\t// return;\n\t// };\n };\n\nSingleViewManager.prototype.onScroll = function(){\n\n};\n\nSingleViewManager.prototype.bounds = function() {\n\tvar bounds;\n\n\tbounds = this.stage.bounds();\n\n\treturn bounds;\n};\n\nSingleViewManager.prototype.applyLayout = function(layout) {\n\n\tthis.layout = layout;\n\tthis.updateLayout();\n\n\tthis.mapping = new Mapping(this.layout);\n\t // this.manager.layout(this.layout.format);\n};\n\nSingleViewManager.prototype.updateLayout = function() {\n\tif (!this.stage) {\n\t\treturn;\n\t}\n\n\tthis._stageSize = this.stage.size();\n\n\tif(this.settings.axis === \"vertical\") {\n\t\tthis.layout.calculate(this._stageSize.width, this._stageSize.height);\n\t} else {\n\t\tthis.layout.calculate(\n\t\t\tthis._stageSize.width,\n\t\t\tthis._stageSize.height,\n\t\t\tthis.settings.gap\n\t\t);\n\n\t\t// Set the look ahead offset for what is visible\n\t\tthis.settings.offset = this.layout.delta;\n\n\t\tthis.stage.addStyleRules(\"iframe\", [{\"margin-right\" : this.layout.gap + \"px\"}]);\n\n\t}\n\n\t// Set the dimensions for views\n\tthis.viewSettings.width = this.layout.width;\n\tthis.viewSettings.height = this.layout.height;\n\n\tthis.setLayout(this.layout);\n\n};\n\nSingleViewManager.prototype.setLayout = function(layout){\n\n\tthis.viewSettings.layout = layout;\n\n\tif(this.views) {\n\n\t\tthis.views.each(function(view){\n\t\t\tview.setLayout(layout);\n\t\t});\n\n\t}\n\n};\n\nSingleViewManager.prototype.updateFlow = function(flow){\n\tvar axis = (flow === \"paginated\") ? \"horizontal\" : \"vertical\";\n\n\tthis.settings.axis = axis;\n\n\tthis.viewSettings.axis = axis;\n\n\tthis.settings.overflow = (flow === \"paginated\") ? \"hidden\" : \"auto\";\n\t// this.views.each(function(view){\n\t// \tview.setAxis(axis);\n\t// });\n\n};\n\n //-- Enable binding events to Manager\n RSVP.EventTarget.mixin(SingleViewManager.prototype);\n\n module.exports = SingleViewManager;\n","var EpubCFI = require('./epubcfi');\n\nfunction Mapping(layout){\n\tthis.layout = layout;\n};\n\nMapping.prototype.section = function(view) {\n\tvar ranges = this.findRanges(view);\n\tvar map = this.rangeListToCfiList(view.section.cfiBase, ranges);\n\n\treturn map;\n};\n\nMapping.prototype.page = function(contents, cfiBase, start, end) {\n\tvar root = contents && contents.document ? contents.document.body : false;\n\n\tif (!root) {\n\t\treturn;\n\t}\n\n\treturn this.rangePairToCfiPair(cfiBase, {\n\t\tstart: this.findStart(root, start, end),\n\t\tend: this.findEnd(root, start, end)\n\t});\n};\n\nMapping.prototype.walk = function(root, func) {\n\t//var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, null, false);\n\tvar treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {\n\t\t\tacceptNode: function (node) {\n\t\t\t\t\tif ( node.data.trim().length > 0 ) {\n\t\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn NodeFilter.FILTER_REJECT;\n\t\t\t\t\t}\n\t\t\t}\n\t}, false);\n\tvar node;\n\tvar result;\n\twhile ((node = treeWalker.nextNode())) {\n\t\tresult = func(node);\n\t\tif(result) break;\n\t}\n\n\treturn result;\n};\n\nMapping.prototype.findRanges = function(view){\n\tvar columns = [];\n\tvar scrollWidth = view.contents.scrollWidth();\n\tvar count = this.layout.count(scrollWidth);\n\tvar column = this.layout.column;\n\tvar gap = this.layout.gap;\n\tvar start, end;\n\n\tfor (var i = 0; i < count.pages; i++) {\n\t\tstart = (column + gap) * i;\n\t\tend = (column * (i+1)) + (gap * i);\n\t\tcolumns.push({\n\t\t\tstart: this.findStart(view.document.body, start, end),\n\t\t\tend: this.findEnd(view.document.body, start, end)\n\t\t});\n\t}\n\n\treturn columns;\n};\n\nMapping.prototype.findStart = function(root, start, end){\n\tvar stack = [root];\n\tvar $el;\n\tvar found;\n\tvar $prev = root;\n\twhile (stack.length) {\n\n\t\t$el = stack.shift();\n\n\t\tfound = this.walk($el, function(node){\n\t\t\tvar left, right;\n\t\t\tvar elPos;\n\t\t\tvar elRange;\n\n\n\t\t\tif(node.nodeType == Node.TEXT_NODE){\n\t\t\t\telRange = document.createRange();\n\t\t\t\telRange.selectNodeContents(node);\n\t\t\t\telPos = elRange.getBoundingClientRect();\n\t\t\t} else {\n\t\t\t\telPos = node.getBoundingClientRect();\n\t\t\t}\n\n\t\t\tleft = elPos.left;\n\t\t\tright = elPos.right;\n\n\t\t\tif( left >= start && left <= end ) {\n\t\t\t\treturn node;\n\t\t\t} else if (right > start) {\n\t\t\t\treturn node;\n\t\t\t} else {\n\t\t\t\t$prev = node;\n\t\t\t\tstack.push(node);\n\t\t\t}\n\n\t\t});\n\n\t\tif(found) {\n\t\t\treturn this.findTextStartRange(found, start, end);\n\t\t}\n\n\t}\n\n\t// Return last element\n\treturn this.findTextStartRange($prev, start, end);\n};\n\nMapping.prototype.findEnd = function(root, start, end){\n\tvar stack = [root];\n\tvar $el;\n\tvar $prev = root;\n\tvar found;\n\n\twhile (stack.length) {\n\n\t\t$el = stack.shift();\n\n\t\tfound = this.walk($el, function(node){\n\n\t\t\tvar left, right;\n\t\t\tvar elPos;\n\t\t\tvar elRange;\n\n\n\t\t\tif(node.nodeType == Node.TEXT_NODE){\n\t\t\t\telRange = document.createRange();\n\t\t\t\telRange.selectNodeContents(node);\n\t\t\t\telPos = elRange.getBoundingClientRect();\n\t\t\t} else {\n\t\t\t\telPos = node.getBoundingClientRect();\n\t\t\t}\n\n\t\t\tleft = elPos.left;\n\t\t\tright = elPos.right;\n\n\t\t\tif(left > end && $prev) {\n\t\t\t\treturn $prev;\n\t\t\t} else if(right > end) {\n\t\t\t\treturn node;\n\t\t\t} else {\n\t\t\t\t$prev = node;\n\t\t\t\tstack.push(node);\n\t\t\t}\n\n\t\t});\n\n\n\t\tif(found){\n\t\t\treturn this.findTextEndRange(found, start, end);\n\t\t}\n\n\t}\n\n\t// end of chapter\n\treturn this.findTextEndRange($prev, start, end);\n};\n\n\nMapping.prototype.findTextStartRange = function(node, start, end){\n\tvar ranges = this.splitTextNodeIntoRanges(node);\n\tvar prev;\n\tvar range;\n\tvar pos;\n\n\tfor (var i = 0; i < ranges.length; i++) {\n\t\trange = ranges[i];\n\n\t\tpos = range.getBoundingClientRect();\n\n\t\tif( pos.left >= start ) {\n\t\t\treturn range;\n\t\t}\n\n\t\tprev = range;\n\n\t}\n\n\treturn ranges[0];\n};\n\nMapping.prototype.findTextEndRange = function(node, start, end){\n\tvar ranges = this.splitTextNodeIntoRanges(node);\n\tvar prev;\n\tvar range;\n\tvar pos;\n\n\tfor (var i = 0; i < ranges.length; i++) {\n\t\trange = ranges[i];\n\n\t\tpos = range.getBoundingClientRect();\n\n\t\tif(pos.left > end && prev) {\n\t\t\treturn prev;\n\t\t} else if(pos.right > end) {\n\t\t\treturn range;\n\t\t}\n\n\t\tprev = range;\n\n\t}\n\n\t// Ends before limit\n\treturn ranges[ranges.length-1];\n\n};\n\nMapping.prototype.splitTextNodeIntoRanges = function(node, _splitter){\n\tvar ranges = [];\n\tvar textContent = node.textContent || \"\";\n\tvar text = textContent.trim();\n\tvar range;\n\tvar rect;\n\tvar list;\n\tvar doc = node.ownerDocument;\n\tvar splitter = _splitter || \" \";\n\n\tpos = text.indexOf(splitter);\n\n\tif(pos === -1 || node.nodeType != Node.TEXT_NODE) {\n\t\trange = doc.createRange();\n\t\trange.selectNodeContents(node);\n\t\treturn [range];\n\t}\n\n\trange = doc.createRange();\n\trange.setStart(node, 0);\n\trange.setEnd(node, pos);\n\tranges.push(range);\n\trange = false;\n\n\twhile ( pos != -1 ) {\n\n\t\tpos = text.indexOf(splitter, pos + 1);\n\t\tif(pos > 0) {\n\n\t\t\tif(range) {\n\t\t\t\trange.setEnd(node, pos);\n\t\t\t\tranges.push(range);\n\t\t\t}\n\n\t\t\trange = doc.createRange();\n\t\t\trange.setStart(node, pos+1);\n\t\t}\n\t}\n\n\tif(range) {\n\t\trange.setEnd(node, text.length);\n\t\tranges.push(range);\n\t}\n\n\treturn ranges;\n};\n\n\n\nMapping.prototype.rangePairToCfiPair = function(cfiBase, rangePair){\n\n\tvar startRange = rangePair.start;\n\tvar endRange = rangePair.end;\n\n\tstartRange.collapse(true);\n\tendRange.collapse(true);\n\n\t// startCfi = section.cfiFromRange(startRange);\n\t// endCfi = section.cfiFromRange(endRange);\n\tstartCfi = new EpubCFI(startRange, cfiBase).toString();\n\tendCfi = new EpubCFI(endRange, cfiBase).toString();\n\n\treturn {\n\t\tstart: startCfi,\n\t\tend: endCfi\n\t};\n\n};\n\nMapping.prototype.rangeListToCfiList = function(cfiBase, columns){\n\tvar map = [];\n\tvar rangePair, cifPair;\n\n\tfor (var i = 0; i < columns.length; i++) {\n\t\tcifPair = this.rangePairToCfiPair(cfiBase, columns[i]);\n\n\t\tmap.push(cifPair);\n\n\t}\n\n\treturn map;\n};\n\nmodule.exports = Mapping;\n","var core = require('./core');\nvar Parser = require('./parser');\nvar RSVP = require('rsvp');\nvar URI = require('urijs');\n\nfunction Navigation(_package, _request){\n\tvar navigation = this;\n\tvar parse = new Parser();\n\tvar request = _request || require('./request');\n\n\tthis.package = _package;\n\tthis.toc = [];\n\tthis.tocByHref = {};\n\tthis.tocById = {};\n\n\tif(_package.navPath) {\n\t\tthis.navUrl = URI(_package.navPath).absoluteTo(_package.baseUrl).toString();\n\t\tthis.nav = {};\n\n\t\tthis.nav.load = function(_request){\n\t\t\tvar loading = new RSVP.defer();\n\t\t\tvar loaded = loading.promise;\n\n\t\t\trequest(navigation.navUrl, 'xml').then(function(xml){\n\t\t\t\tnavigation.toc = parse.nav(xml);\n\t\t\t\tnavigation.loaded(navigation.toc);\n\t\t\t\tloading.resolve(navigation.toc);\n\t\t\t});\n\n\t\t\treturn loaded;\n\t\t};\n\n\t}\n\n\tif(_package.ncxPath) {\n\t\tthis.ncxUrl = URI(_package.ncxPath).absoluteTo(_package.baseUrl).toString();\n\t\tthis.ncx = {};\n\n\t\tthis.ncx.load = function(_request){\n\t\t\tvar loading = new RSVP.defer();\n\t\t\tvar loaded = loading.promise;\n\n\t\t\trequest(navigation.ncxUrl, 'xml').then(function(xml){\n\t\t\t\tnavigation.toc = parse.toc(xml);\n\t\t\t\tnavigation.loaded(navigation.toc);\n\t\t\t\tloading.resolve(navigation.toc);\n\t\t\t});\n\n\t\t\treturn loaded;\n\t\t};\n\n\t}\n};\n\n// Load the navigation\nNavigation.prototype.load = function(_request) {\n\tvar request = _request || require('./request');\n\tvar loading, loaded;\n\n\tif(this.nav) {\n\t\tloading = this.nav.load();\n\t} else if(this.ncx) {\n\t\tloading = this.ncx.load();\n\t} else {\n\t\tloaded = new RSVP.defer();\n\t\tloaded.resolve([]);\n\t\tloading = loaded.promise;\n\t}\n\n\treturn loading;\n\n};\n\nNavigation.prototype.loaded = function(toc) {\n\tvar item;\n\n\tfor (var i = 0; i < toc.length; i++) {\n\t\titem = toc[i];\n\t\tthis.tocByHref[item.href] = i;\n\t\tthis.tocById[item.id] = i;\n\t}\n\n};\n\n// Get an item from the navigation\nNavigation.prototype.get = function(target) {\n\tvar index;\n\n\tif(!target) {\n\t\treturn this.toc;\n\t}\n\n\tif(target.indexOf(\"#\") === 0) {\n\t\tindex = this.tocById[target.substring(1)];\n\t} else if(target in this.tocByHref){\n\t\tindex = this.tocByHref[target];\n\t}\n\n\treturn this.toc[index];\n};\n\nmodule.exports = Navigation;\n","var URI = require('urijs');\nvar core = require('./core');\nvar EpubCFI = require('./epubcfi');\n\n\nfunction Parser(){};\n\nParser.prototype.container = function(containerXml){\n\t\t//-- \n\t\tvar rootfile, fullpath, folder, encoding;\n\n\t\tif(!containerXml) {\n\t\t\tconsole.error(\"Container File Not Found\");\n\t\t\treturn;\n\t\t}\n\n\t\trootfile = core.qs(containerXml, \"rootfile\");\n\n\t\tif(!rootfile) {\n\t\t\tconsole.error(\"No RootFile Found\");\n\t\t\treturn;\n\t\t}\n\n\t\tfullpath = rootfile.getAttribute('full-path');\n\t\tfolder = URI(fullpath).directory();\n\t\tencoding = containerXml.xmlEncoding;\n\n\t\t//-- Now that we have the path we can parse the contents\n\t\treturn {\n\t\t\t'packagePath' : fullpath,\n\t\t\t'basePath' : folder,\n\t\t\t'encoding' : encoding\n\t\t};\n};\n\nParser.prototype.identifier = function(packageXml){\n\tvar metadataNode;\n\n\tif(!packageXml) {\n\t\tconsole.error(\"Package File Not Found\");\n\t\treturn;\n\t}\n\n\tmetadataNode = core.qs(packageXml, \"metadata\");\n\n\tif(!metadataNode) {\n\t\tconsole.error(\"No Metadata Found\");\n\t\treturn;\n\t}\n\n\treturn this.getElementText(metadataNode, \"identifier\");\n};\n\nParser.prototype.packageContents = function(packageXml){\n\tvar parse = this;\n\tvar metadataNode, manifestNode, spineNode;\n\tvar manifest, navPath, ncxPath, coverPath;\n\tvar spineNodeIndex;\n\tvar spine;\n\tvar spineIndexByURL;\n\tvar metadata;\n\n\tif(!packageXml) {\n\t\tconsole.error(\"Package File Not Found\");\n\t\treturn;\n\t}\n\n\tmetadataNode = core.qs(packageXml, \"metadata\");\n\tif(!metadataNode) {\n\t\tconsole.error(\"No Metadata Found\");\n\t\treturn;\n\t}\n\n\tmanifestNode = core.qs(packageXml, \"manifest\");\n\tif(!manifestNode) {\n\t\tconsole.error(\"No Manifest Found\");\n\t\treturn;\n\t}\n\n\tspineNode = core.qs(packageXml, \"spine\");\n\tif(!spineNode) {\n\t\tconsole.error(\"No Spine Found\");\n\t\treturn;\n\t}\n\n\tmanifest = parse.manifest(manifestNode);\n\tnavPath = parse.findNavPath(manifestNode);\n\tncxPath = parse.findNcxPath(manifestNode, spineNode);\n\tcoverPath = parse.findCoverPath(packageXml);\n\n\tspineNodeIndex = Array.prototype.indexOf.call(spineNode.parentNode.childNodes, spineNode);\n\n\tspine = parse.spine(spineNode, manifest);\n\n\tmetadata = parse.metadata(metadataNode);\n\n\tmetadata.direction = spineNode.getAttribute(\"page-progression-direction\");\n\n\treturn {\n\t\t'metadata' : metadata,\n\t\t'spine' : spine,\n\t\t'manifest' : manifest,\n\t\t'navPath' : navPath,\n\t\t'ncxPath' : ncxPath,\n\t\t'coverPath': coverPath,\n\t\t'spineNodeIndex' : spineNodeIndex\n\t};\n};\n\n//-- Find TOC NAV\nParser.prototype.findNavPath = function(manifestNode){\n\t// Find item with property 'nav'\n\t// Should catch nav irregardless of order\n\t// var node = manifestNode.querySelector(\"item[properties$='nav'], item[properties^='nav '], item[properties*=' nav ']\");\n\tvar node = core.qsp(manifestNode, \"item\", {\"properties\":\"nav\"});\n\treturn node ? node.getAttribute('href') : false;\n};\n\n//-- Find TOC NCX: media-type=\"application/x-dtbncx+xml\" href=\"toc.ncx\"\nParser.prototype.findNcxPath = function(manifestNode, spineNode){\n\t// var node = manifestNode.querySelector(\"item[media-type='application/x-dtbncx+xml']\");\n\tvar node = core.qsp(manifestNode, \"item\", {\"media-type\":\"application/x-dtbncx+xml\"});\n\tvar tocId;\n\n\t// If we can't find the toc by media-type then try to look for id of the item in the spine attributes as\n\t// according to http://www.idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.4.1.2,\n\t// \"The item that describes the NCX must be referenced by the spine toc attribute.\"\n\tif (!node) {\n\t\ttocId = spineNode.getAttribute(\"toc\");\n\t\tif(tocId) {\n\t\t\t// node = manifestNode.querySelector(\"item[id='\" + tocId + \"']\");\n\t\t\tnode = manifestNode.getElementById(tocId);\n\t\t}\n\t}\n\n\treturn node ? node.getAttribute('href') : false;\n};\n\n//-- Expanded to match Readium web components\nParser.prototype.metadata = function(xml){\n\tvar metadata = {},\n\t\t\tp = this;\n\n\tmetadata.title = p.getElementText(xml, 'title');\n\tmetadata.creator = p.getElementText(xml, 'creator');\n\tmetadata.description = p.getElementText(xml, 'description');\n\n\tmetadata.pubdate = p.getElementText(xml, 'date');\n\n\tmetadata.publisher = p.getElementText(xml, 'publisher');\n\n\tmetadata.identifier = p.getElementText(xml, \"identifier\");\n\tmetadata.language = p.getElementText(xml, \"language\");\n\tmetadata.rights = p.getElementText(xml, \"rights\");\n\n\tmetadata.modified_date = p.getPropertyText(xml, 'dcterms:modified');\n\n\tmetadata.layout = p.getPropertyText(xml, \"rendition:layout\");\n\tmetadata.orientation = p.getPropertyText(xml, 'rendition:orientation');\n\tmetadata.flow = p.getPropertyText(xml, 'rendition:flow');\n\tmetadata.viewport = p.getPropertyText(xml, 'rendition:viewport');\n\t// metadata.page_prog_dir = packageXml.querySelector(\"spine\").getAttribute(\"page-progression-direction\");\n\n\treturn metadata;\n};\n\n//-- Find Cover: \n//-- Fallback for Epub 2.0\nParser.prototype.findCoverPath = function(packageXml){\n\tvar pkg = core.qs(packageXml, \"package\");\n\tvar epubVersion = pkg.getAttribute('version');\n\n\tif (epubVersion === '2.0') {\n\t\tvar metaCover = core.qsp(packageXml, 'meta', {'name':'cover'});\n\t\tif (metaCover) {\n\t\t\tvar coverId = metaCover.getAttribute('content');\n\t\t\t// var cover = packageXml.querySelector(\"item[id='\" + coverId + \"']\");\n\t\t\tvar cover = packageXml.getElementById(coverId);\n\t\t\treturn cover ? cover.getAttribute('href') : false;\n\t\t}\n\t\telse {\n\t\t\treturn false;\n\t\t}\n\t}\n\telse {\n\t\t// var node = packageXml.querySelector(\"item[properties='cover-image']\");\n\t\tvar node = core.qsp(packageXml, 'item', {'properties':'cover-image'});\n\t\treturn node ? node.getAttribute('href') : false;\n\t}\n};\n\nParser.prototype.getElementText = function(xml, tag){\n\tvar found = xml.getElementsByTagNameNS(\"http://purl.org/dc/elements/1.1/\", tag),\n\t\tel;\n\n\tif(!found || found.length === 0) return '';\n\n\tel = found[0];\n\n\tif(el.childNodes.length){\n\t\treturn el.childNodes[0].nodeValue;\n\t}\n\n\treturn '';\n\n};\n\nParser.prototype.getPropertyText = function(xml, property){\n\tvar el = core.qsp(xml, \"meta\", {\"property\":property});\n\n\tif(el && el.childNodes.length){\n\t\treturn el.childNodes[0].nodeValue;\n\t}\n\n\treturn '';\n};\n\nParser.prototype.querySelectorText = function(xml, q){\n\tvar el = xml.querySelector(q);\n\n\tif(el && el.childNodes.length){\n\t\treturn el.childNodes[0].nodeValue;\n\t}\n\n\treturn '';\n};\n\nParser.prototype.manifest = function(manifestXml){\n\tvar manifest = {};\n\n\t//-- Turn items into an array\n\t// var selected = manifestXml.querySelectorAll(\"item\");\n\tvar selected = core.qsa(manifestXml, \"item\");\n\tvar items = Array.prototype.slice.call(selected);\n\n\t//-- Create an object with the id as key\n\titems.forEach(function(item){\n\t\tvar id = item.getAttribute('id'),\n\t\t\t\thref = item.getAttribute('href') || '',\n\t\t\t\ttype = item.getAttribute('media-type') || '',\n\t\t\t\tproperties = item.getAttribute('properties') || '';\n\n\t\tmanifest[id] = {\n\t\t\t'href' : href,\n\t\t\t// 'url' : href,\n\t\t\t'type' : type,\n\t\t\t'properties' : properties.length ? properties.split(' ') : []\n\t\t};\n\n\t});\n\n\treturn manifest;\n\n};\n\nParser.prototype.spine = function(spineXml, manifest){\n\tvar spine = [];\n\n\tvar selected = spineXml.getElementsByTagName(\"itemref\"),\n\t\t\titems = Array.prototype.slice.call(selected);\n\n\tvar epubcfi = new EpubCFI();\n\n\t//-- Add to array to mantain ordering and cross reference with manifest\n\titems.forEach(function(item, index){\n\t\tvar idref = item.getAttribute('idref');\n\t\t// var cfiBase = epubcfi.generateChapterComponent(spineNodeIndex, index, Id);\n\t\tvar props = item.getAttribute('properties') || '';\n\t\tvar propArray = props.length ? props.split(' ') : [];\n\t\t// var manifestProps = manifest[Id].properties;\n\t\t// var manifestPropArray = manifestProps.length ? manifestProps.split(' ') : [];\n\n\t\tvar itemref = {\n\t\t\t'idref' : idref,\n\t\t\t'linear' : item.getAttribute('linear') || '',\n\t\t\t'properties' : propArray,\n\t\t\t// 'href' : manifest[Id].href,\n\t\t\t// 'url' : manifest[Id].url,\n\t\t\t'index' : index\n\t\t\t// 'cfiBase' : cfiBase\n\t\t};\n\t\tspine.push(itemref);\n\t});\n\n\treturn spine;\n};\n\nParser.prototype.querySelectorByType = function(html, element, type){\n\tvar query;\n\tif (typeof html.querySelector != \"undefined\") {\n\t\tquery = html.querySelector(element+'[*|type=\"'+type+'\"]');\n\t}\n\t// Handle IE not supporting namespaced epub:type in querySelector\n\tif(!query || query.length === 0) {\n\t\tquery = core.qsa(html, element);\n\t\tfor (var i = 0; i < query.length; i++) {\n\t\t\tif(query[i].getAttributeNS(\"http://www.idpf.org/2007/ops\", \"type\") === type) {\n\t\t\t\treturn query[i];\n\t\t\t}\n\t\t}\n\t} else {\n\t\treturn query;\n\t}\n};\n\nParser.prototype.nav = function(navHtml, spineIndexByURL, bookSpine){\n\tvar navElement = this.querySelectorByType(navHtml, \"nav\", \"toc\");\n\t// var navItems = navElement ? navElement.querySelectorAll(\"ol li\") : [];\n\tvar navItems = navElement ? core.qsa(navElement, \"li\") : [];\n\tvar length = navItems.length;\n\tvar i;\n\tvar toc = {};\n\tvar list = [];\n\tvar item, parent;\n\n\tif(!navItems || length === 0) return list;\n\n\tfor (i = 0; i < length; ++i) {\n\t\titem = this.navItem(navItems[i], spineIndexByURL, bookSpine);\n\t\ttoc[item.id] = item;\n\t\tif(!item.parent) {\n\t\t\tlist.push(item);\n\t\t} else {\n\t\t\tparent = toc[item.parent];\n\t\t\tparent.subitems.push(item);\n\t\t}\n\t}\n\n\treturn list;\n};\n\nParser.prototype.navItem = function(item, spineIndexByURL, bookSpine){\n\tvar id = item.getAttribute('id') || false,\n\t\t\t// content = item.querySelector(\"a, span\"),\n\t\t\tcontent = core.qs(item, \"a\"),\n\t\t\tsrc = content.getAttribute('href') || '',\n\t\t\ttext = content.textContent || \"\",\n\t\t\t// split = src.split(\"#\"),\n\t\t\t// baseUrl = split[0],\n\t\t\t// spinePos = spineIndexByURL[baseUrl],\n\t\t\t// spineItem = bookSpine[spinePos],\n\t\t\tsubitems = [],\n\t\t\tparentNode = item.parentNode,\n\t\t\tparent;\n\t\t\t// cfi = spineItem ? spineItem.cfi : '';\n\n\tif(parentNode && parentNode.nodeName === \"navPoint\") {\n\t\tparent = parentNode.getAttribute('id');\n\t}\n\n\t/*\n\tif(!id) {\n\t\tif(spinePos) {\n\t\t\tspineItem = bookSpine[spinePos];\n\t\t\tid = spineItem.id;\n\t\t\tcfi = spineItem.cfi;\n\t\t} else {\n\t\t\tid = 'epubjs-autogen-toc-id-' + EPUBJS.core.uuid();\n\t\t\titem.setAttribute('id', id);\n\t\t}\n\t}\n\t*/\n\n\treturn {\n\t\t\"id\": id,\n\t\t\"href\": src,\n\t\t\"label\": text,\n\t\t\"subitems\" : subitems,\n\t\t\"parent\" : parent\n\t};\n};\n\nParser.prototype.ncx = function(tocXml, spineIndexByURL, bookSpine){\n\t// var navPoints = tocXml.querySelectorAll(\"navMap navPoint\");\n\tvar navPoints = core.qsa(tocXml, \"navPoint\");\n\tvar length = navPoints.length;\n\tvar i;\n\tvar toc = {};\n\tvar list = [];\n\tvar item, parent;\n\n\tif(!navPoints || length === 0) return list;\n\n\tfor (i = 0; i < length; ++i) {\n\t\titem = this.ncxItem(navPoints[i], spineIndexByURL, bookSpine);\n\t\ttoc[item.id] = item;\n\t\tif(!item.parent) {\n\t\t\tlist.push(item);\n\t\t} else {\n\t\t\tparent = toc[item.parent];\n\t\t\tparent.subitems.push(item);\n\t\t}\n\t}\n\n\treturn list;\n};\n\nParser.prototype.ncxItem = function(item, spineIndexByURL, bookSpine){\n\tvar id = item.getAttribute('id') || false,\n\t\t\t// content = item.querySelector(\"content\"),\n\t\t\tcontent = core.qs(item, \"content\"),\n\t\t\tsrc = content.getAttribute('src'),\n\t\t\t// navLabel = item.querySelector(\"navLabel\"),\n\t\t\tnavLabel = core.qs(item, \"navLabel\"),\n\t\t\ttext = navLabel.textContent ? navLabel.textContent : \"\",\n\t\t\t// split = src.split(\"#\"),\n\t\t\t// baseUrl = split[0],\n\t\t\t// spinePos = spineIndexByURL[baseUrl],\n\t\t\t// spineItem = bookSpine[spinePos],\n\t\t\tsubitems = [],\n\t\t\tparentNode = item.parentNode,\n\t\t\tparent;\n\t\t\t// cfi = spineItem ? spineItem.cfi : '';\n\n\tif(parentNode && parentNode.nodeName === \"navPoint\") {\n\t\tparent = parentNode.getAttribute('id');\n\t}\n\n\t/*\n\tif(!id) {\n\t\tif(spinePos) {\n\t\t\tspineItem = bookSpine[spinePos];\n\t\t\tid = spineItem.id;\n\t\t\tcfi = spineItem.cfi;\n\t\t} else {\n\t\t\tid = 'epubjs-autogen-toc-id-' + EPUBJS.core.uuid();\n\t\t\titem.setAttribute('id', id);\n\t\t}\n\t}\n\t*/\n\n\treturn {\n\t\t\"id\": id,\n\t\t\"href\": src,\n\t\t\"label\": text,\n\t\t\"subitems\" : subitems,\n\t\t\"parent\" : parent\n\t};\n};\n\nParser.prototype.pageList = function(navHtml, spineIndexByURL, bookSpine){\n\tvar navElement = this.querySelectorByType(navHtml, \"nav\", \"page-list\");\n\t// var navItems = navElement ? navElement.querySelectorAll(\"ol li\") : [];\n\tvar navItems = navElement ? core.qsa(navElement, \"li\") : [];\n\tvar length = navItems.length;\n\tvar i;\n\tvar toc = {};\n\tvar list = [];\n\tvar item;\n\n\tif(!navItems || length === 0) return list;\n\n\tfor (i = 0; i < length; ++i) {\n\t\titem = this.pageListItem(navItems[i], spineIndexByURL, bookSpine);\n\t\tlist.push(item);\n\t}\n\n\treturn list;\n};\n\nParser.prototype.pageListItem = function(item, spineIndexByURL, bookSpine){\n\tvar id = item.getAttribute('id') || false,\n\t\t// content = item.querySelector(\"a\"),\n\t\tcontent = core.qs(item, \"a\"),\n\t\thref = content.getAttribute('href') || '',\n\t\ttext = content.textContent || \"\",\n\t\tpage = parseInt(text),\n\t\tisCfi = href.indexOf(\"epubcfi\"),\n\t\tsplit,\n\t\tpackageUrl,\n\t\tcfi;\n\n\tif(isCfi != -1) {\n\t\tsplit = href.split(\"#\");\n\t\tpackageUrl = split[0];\n\t\tcfi = split.length > 1 ? split[1] : false;\n\t\treturn {\n\t\t\t\"cfi\" : cfi,\n\t\t\t\"href\" : href,\n\t\t\t\"packageUrl\" : packageUrl,\n\t\t\t\"page\" : page\n\t\t};\n\t} else {\n\t\treturn {\n\t\t\t\"href\" : href,\n\t\t\t\"page\" : page\n\t\t};\n\t}\n};\n\nmodule.exports = Parser;\n","var RSVP = require('rsvp');\nvar core = require('./core');\n\nfunction Queue(_context){\n\tthis._q = [];\n\tthis.context = _context;\n\tthis.tick = core.requestAnimationFrame;\n\tthis.running = false;\n\tthis.paused = false;\n};\n\n// Add an item to the queue\nQueue.prototype.enqueue = function() {\n\tvar deferred, promise;\n\tvar queued;\n\tvar task = [].shift.call(arguments);\n\tvar args = arguments;\n\n\t// Handle single args without context\n\t// if(args && !Array.isArray(args)) {\n\t// args = [args];\n\t// }\n\tif(!task) {\n\t\treturn console.error(\"No Task Provided\");\n\t}\n\n\tif(typeof task === \"function\"){\n\n\t\tdeferred = new RSVP.defer();\n\t\tpromise = deferred.promise;\n\n\t\tqueued = {\n\t\t\t\"task\" : task,\n\t\t\t\"args\" : args,\n\t\t\t//\"context\" : context,\n\t\t\t\"deferred\" : deferred,\n\t\t\t\"promise\" : promise\n\t\t};\n\n\t} else {\n\t\t// Task is a promise\n\t\tqueued = {\n\t\t\t\"promise\" : task\n\t\t};\n\n\t}\n\n\tthis._q.push(queued);\n\n\t// Wait to start queue flush\n\tif (this.paused == false && !this.running) {\n\t\t// setTimeout(this.flush.bind(this), 0);\n\t\t// this.tick.call(window, this.run.bind(this));\n\t\tthis.run();\n\t}\n\n\treturn queued.promise;\n};\n\n// Run one item\nQueue.prototype.dequeue = function(){\n\tvar inwait, task, result;\n\n\tif(this._q.length) {\n\t\tinwait = this._q.shift();\n\t\ttask = inwait.task;\n\t\tif(task){\n\t\t\t// console.log(task)\n\n\t\t\tresult = task.apply(this.context, inwait.args);\n\n\t\t\tif(result && typeof result[\"then\"] === \"function\") {\n\t\t\t\t// Task is a function that returns a promise\n\t\t\t\treturn result.then(function(){\n\t\t\t\t\tinwait.deferred.resolve.apply(this.context, arguments);\n\t\t\t\t}.bind(this));\n\t\t\t} else {\n\t\t\t\t// Task resolves immediately\n\t\t\t\tinwait.deferred.resolve.apply(this.context, result);\n\t\t\t\treturn inwait.promise;\n\t\t\t}\n\n\n\n\t\t} else if(inwait.promise) {\n\t\t\t// Task is a promise\n\t\t\treturn inwait.promise;\n\t\t}\n\n\t} else {\n\t\tinwait = new RSVP.defer();\n\t\tinwait.deferred.resolve();\n\t\treturn inwait.promise;\n\t}\n\n};\n\n// Run All Immediately\nQueue.prototype.dump = function(){\n\twhile(this._q.length) {\n\t\tthis.dequeue();\n\t}\n};\n\n// Run all sequentially, at convince\n\nQueue.prototype.run = function(){\n\n\tif(!this.running){\n\t\tthis.running = true;\n\t\tthis.defered = new RSVP.defer();\n\t}\n\n\tthis.tick.call(window, function() {\n\n\t\tif(this._q.length) {\n\n\t\t\tthis.dequeue()\n\t\t\t\t.then(function(){\n\t\t\t\t\tthis.run();\n\t\t\t\t}.bind(this));\n\n\t\t} else {\n\t\t\tthis.defered.resolve();\n\t\t\tthis.running = undefined;\n\t\t}\n\n\t}.bind(this));\n\n\t// Unpause\n\tif(this.paused == true) {\n\t\tthis.paused = false;\n\t}\n\n\treturn this.defered.promise;\n};\n\n// Flush all, as quickly as possible\nQueue.prototype.flush = function(){\n\n\tif(this.running){\n\t\treturn this.running;\n\t}\n\n\tif(this._q.length) {\n\t\tthis.running = this.dequeue()\n\t\t\t.then(function(){\n\t\t\t\tthis.running = undefined;\n\t\t\t\treturn this.flush();\n\t\t\t}.bind(this));\n\n\t\treturn this.running;\n\t}\n\n};\n\n// Clear all items in wait\nQueue.prototype.clear = function(){\n\tthis._q = [];\n\tthis.running = false;\n};\n\nQueue.prototype.length = function(){\n\treturn this._q.length;\n};\n\nQueue.prototype.pause = function(){\n\tthis.paused = true;\n};\n\n// Create a new task from a callback\nfunction Task(task, args, context){\n\n\treturn function(){\n\t\tvar toApply = arguments || [];\n\n\t\treturn new RSVP.Promise(function(resolve, reject) {\n\t\t\tvar callback = function(value){\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\t// Add the callback to the arguments list\n\t\t\ttoApply.push(callback);\n\n\t\t\t// Apply all arguments to the functions\n\t\t\ttask.apply(this, toApply);\n\n\t}.bind(this));\n\n\t};\n\n};\n\nmodule.exports = Queue;\n","var RSVP = require('rsvp');\nvar URI = require('urijs');\nvar core = require('./core');\nvar replace = require('./replacements');\nvar Hook = require('./hook');\nvar EpubCFI = require('./epubcfi');\nvar Queue = require('./queue');\n// var View = require('./view');\nvar Views = require('./views');\nvar Layout = require('./layout');\nvar Mapping = require('./mapping');\n\nfunction Rendition(book, options) {\n\n\tthis.settings = core.extend(this.settings || {}, {\n\t\twidth: null,\n\t\theight: null,\n\t\tignoreClass: '',\n\t\tmanager: \"single\",\n\t\tview: \"iframe\",\n\t\tflow: null,\n\t\tlayout: null,\n\t\tspread: null,\n\t\tminSpreadWidth: 800, //-- overridden by spread: none (never) / both (always),\n\t\tuseBase64: true\n\t});\n\n\tcore.extend(this.settings, options);\n\n\tthis.viewSettings = {\n\t\tignoreClass: this.settings.ignoreClass\n\t};\n\n\tthis.book = book;\n\n\tthis.views = null;\n\n\t//-- Adds Hook methods to the Rendition prototype\n\tthis.hooks = {};\n\tthis.hooks.display = new Hook(this);\n\tthis.hooks.serialize = new Hook(this);\n\tthis.hooks.content = new Hook(this);\n\tthis.hooks.layout = new Hook(this);\n\tthis.hooks.render = new Hook(this);\n\tthis.hooks.show = new Hook(this);\n\n\tthis.hooks.content.register(replace.links.bind(this));\n\tthis.hooks.content.register(this.passViewEvents.bind(this));\n\n\t// this.hooks.display.register(this.afterDisplay.bind(this));\n\n\tthis.epubcfi = new EpubCFI();\n\n\tthis.q = new Queue(this);\n\n\tthis.q.enqueue(this.book.opened);\n\n\t// Block the queue until rendering is started\n\t// this.starting = new RSVP.defer();\n\t// this.started = this.starting.promise;\n\tthis.q.enqueue(this.start);\n\n\tif(this.book.unarchived) {\n\t\tthis.q.enqueue(this.replacements.bind(this));\n\t}\n\n};\n\nRendition.prototype.setManager = function(manager) {\n\tthis.manager = manager;\n};\n\nRendition.prototype.requireManager = function(manager) {\n\tvar viewManager;\n\n\t// If manager is a string, try to load from register managers,\n\t// or require included managers directly\n\tif (typeof manager === \"string\") {\n\t\t// Use global or require\n\t\tviewManager = typeof ePub != \"undefined\" ? ePub.ViewManagers[manager] : undefined; //require('./managers/'+manager);\n\t} else {\n\t\t// otherwise, assume we were passed a function\n\t\tviewManager = manager\n\t}\n\n\treturn viewManager;\n};\n\nRendition.prototype.requireView = function(view) {\n\tvar View;\n\n\tif (typeof view == \"string\") {\n\t\tView = typeof ePub != \"undefined\" ? ePub.Views[view] : undefined; //require('./views/'+view);\n\t} else {\n\t\t// otherwise, assume we were passed a function\n\t\tView = view\n\t}\n\n\treturn View;\n};\n\nRendition.prototype.start = function(){\n\n\tif(!this.manager) {\n\t\tthis.ViewManager = this.requireManager(this.settings.manager);\n\t\tthis.View = this.requireView(this.settings.view);\n\n\t\tthis.manager = new this.ViewManager({\n\t\t\tview: this.View,\n\t\t\tqueue: this.q,\n\t\t\trequest: this.book.request,\n\t\t\tsettings: this.settings\n\t\t});\n\t}\n\n\t// Parse metadata to get layout props\n\tthis.settings.globalLayoutProperties = this.determineLayoutProperties(this.book.package.metadata);\n\n\tthis.flow(this.settings.globalLayoutProperties.flow);\n\n\tthis.layout(this.settings.globalLayoutProperties);\n\n\t// Listen for displayed views\n\tthis.manager.on(\"added\", this.afterDisplayed.bind(this));\n\n\t// Listen for resizing\n\tthis.manager.on(\"resized\", this.onResized.bind(this));\n\n\t// Listen for scroll changes\n\tthis.manager.on(\"scroll\", this.reportLocation.bind(this));\n\n\n\tthis.on('displayed', this.reportLocation.bind(this));\n\n\t// Trigger that rendering has started\n\tthis.trigger(\"started\");\n\n\t// Start processing queue\n\t// this.starting.resolve();\n};\n\n// Call to attach the container to an element in the dom\n// Container must be attached before rendering can begin\nRendition.prototype.attachTo = function(element){\n\n\treturn this.q.enqueue(function () {\n\n\t\t// Start rendering\n\t\tthis.manager.render(element, {\n\t\t\t\"width\" : this.settings.width,\n\t\t\t\"height\" : this.settings.height\n\t\t});\n\n\t\t// Trigger Attached\n\t\tthis.trigger(\"attached\");\n\n\t}.bind(this));\n\n};\n\nRendition.prototype.display = function(target){\n\n\t// if (!this.book.spine.spineItems.length > 0) {\n\t\t// Book isn't open yet\n\t\t// return this.q.enqueue(this.display, target);\n\t// }\n\n\treturn this.q.enqueue(this._display, target);\n\n};\n\nRendition.prototype._display = function(target){\n\tvar isCfiString = this.epubcfi.isCfiString(target);\n\tvar displaying = new RSVP.defer();\n\tvar displayed = displaying.promise;\n\tvar section;\n\tvar moveTo;\n\n\tsection = this.book.spine.get(target);\n\n\tif(!section){\n\t\tdisplaying.reject(new Error(\"No Section Found\"));\n\t\treturn displayed;\n\t}\n\n\t// Trim the target fragment\n\t// removing the chapter\n\tif(!isCfiString && typeof target === \"string\" &&\n\t\ttarget.indexOf(\"#\") > -1) {\n\t\t\tmoveTo = target.substring(target.indexOf(\"#\")+1);\n\t}\n\n\tif (isCfiString) {\n\t\tmoveTo = target;\n\t}\n\n\treturn this.manager.display(section, moveTo)\n\t\t.then(function(){\n\t\t\tthis.trigger(\"displayed\", section);\n\t\t}.bind(this));\n\n};\n\n/*\nRendition.prototype.render = function(view, show) {\n\n\t// view.onLayout = this.layout.format.bind(this.layout);\n\tview.create();\n\n\t// Fit to size of the container, apply padding\n\tthis.manager.resizeView(view);\n\n\t// Render Chain\n\treturn view.section.render(this.book.request)\n\t\t.then(function(contents){\n\t\t\treturn view.load(contents);\n\t\t}.bind(this))\n\t\t.then(function(doc){\n\t\t\treturn this.hooks.content.trigger(view, this);\n\t\t}.bind(this))\n\t\t.then(function(){\n\t\t\tthis.layout.format(view.contents);\n\t\t\treturn this.hooks.layout.trigger(view, this);\n\t\t}.bind(this))\n\t\t.then(function(){\n\t\t\treturn view.display();\n\t\t}.bind(this))\n\t\t.then(function(){\n\t\t\treturn this.hooks.render.trigger(view, this);\n\t\t}.bind(this))\n\t\t.then(function(){\n\t\t\tif(show !== false) {\n\t\t\t\tthis.q.enqueue(function(view){\n\t\t\t\t\tview.show();\n\t\t\t\t}, view);\n\t\t\t}\n\t\t\t// this.map = new Map(view, this.layout);\n\t\t\tthis.hooks.show.trigger(view, this);\n\t\t\tthis.trigger(\"rendered\", view.section);\n\n\t\t}.bind(this))\n\t\t.catch(function(e){\n\t\t\tthis.trigger(\"loaderror\", e);\n\t\t}.bind(this));\n\n};\n*/\n\nRendition.prototype.afterDisplayed = function(view){\n\tthis.hooks.content.trigger(view, this);\n\tthis.trigger(\"rendered\", view.section);\n\tthis.reportLocation();\n};\n\nRendition.prototype.onResized = function(size){\n\n\tif(this.location) {\n\t\tthis.display(this.location.start);\n\t}\n\n\tthis.trigger(\"resized\", {\n\t\twidth: size.width,\n\t\theight: size.height\n\t});\n\n};\n\nRendition.prototype.moveTo = function(offset){\n\tthis.manager.moveTo(offset);\n};\n\nRendition.prototype.next = function(){\n\treturn this.q.enqueue(this.manager.next.bind(this.manager))\n\t\t.then(this.reportLocation.bind(this));\n};\n\nRendition.prototype.prev = function(){\n\treturn this.q.enqueue(this.manager.prev.bind(this.manager))\n\t\t.then(this.reportLocation.bind(this));\n};\n\n//-- http://www.idpf.org/epub/301/spec/epub-publications.html#meta-properties-rendering\nRendition.prototype.determineLayoutProperties = function(metadata){\n\tvar settings;\n\tvar layout = this.settings.layout || metadata.layout || \"reflowable\";\n\tvar spread = this.settings.spread || metadata.spread || \"auto\";\n\tvar orientation = this.settings.orientation || metadata.orientation || \"auto\";\n\tvar flow = this.settings.flow || metadata.flow || \"auto\";\n\tvar viewport = metadata.viewport || \"\";\n\tvar minSpreadWidth = this.settings.minSpreadWidth || metadata.minSpreadWidth || 800;\n\n\tif (this.settings.width >= 0 && this.settings.height >= 0) {\n\t\tviewport = \"width=\"+this.settings.width+\", height=\"+this.settings.height+\"\";\n\t}\n\n\tsettings = {\n\t\tlayout : layout,\n\t\tspread : spread,\n\t\torientation : orientation,\n\t\tflow : flow,\n\t\tviewport : viewport,\n\t\tminSpreadWidth : minSpreadWidth\n\t};\n\n\treturn settings;\n};\n\n// Rendition.prototype.applyLayoutProperties = function(){\n// \tvar settings = this.determineLayoutProperties(this.book.package.metadata);\n//\n// \tthis.flow(settings.flow);\n//\n// \tthis.layout(settings);\n// };\n\n// paginated | scrolled\n// (scrolled-continuous vs scrolled-doc are handled by different view managers)\nRendition.prototype.flow = function(_flow){\n\tvar flow;\n\tif (_flow === \"scrolled-doc\" || _flow === \"scrolled-continuous\") {\n\t\tflow = \"scrolled\";\n\t}\n\n\tif (_flow === \"auto\" || _flow === \"paginated\") {\n\t\tflow = \"paginated\";\n\t}\n\n\tif (this._layout) {\n\t\tthis._layout.flow(flow);\n\t}\n\n\tif (this.manager) {\n\t\tthis.manager.updateFlow(flow);\n\t}\n};\n\n// reflowable | pre-paginated\nRendition.prototype.layout = function(settings){\n\tif (settings) {\n\t\tthis._layout = new Layout(settings);\n\t\tthis._layout.spread(settings.spread, this.settings.minSpreadWidth);\n\n\t\tthis.mapping = new Mapping(this._layout);\n\t}\n\n\tif (this.manager && this._layout) {\n\t\tthis.manager.applyLayout(this._layout);\n\t}\n\n\treturn this._layout;\n};\n\n// none | auto (TODO: implement landscape, portrait, both)\nRendition.prototype.spread = function(spread, min){\n\n\tthis._layout.spread(spread, min);\n\n\tif (this.manager.isRendered()) {\n\t\tthis.manager.updateLayout();\n\t}\n};\n\n\nRendition.prototype.reportLocation = function(){\n\treturn this.q.enqueue(function(){\n\t\tvar location = this.manager.currentLocation();\n\t\tif (location && location.then && typeof location.then === 'function') {\n\t\t\tlocation.then(function(result) {\n\t\t\t\tthis.location = result;\n\t\t\t\tthis.trigger(\"locationChanged\", this.location);\n\t\t\t}.bind(this));\n\t\t} else if (location) {\n\t\t\tthis.location = location;\n\t\t\tthis.trigger(\"locationChanged\", this.location);\n\t\t}\n\n\t}.bind(this));\n};\n\n\nRendition.prototype.destroy = function(){\n\t// Clear the queue\n\tthis.q.clear();\n\n\tthis.views.clear();\n\n\tclearTimeout(this.trimTimeout);\n\tif(this.settings.hidden) {\n\t\tthis.element.removeChild(this.wrapper);\n\t} else {\n\t\tthis.element.removeChild(this.container);\n\t}\n\n};\n\nRendition.prototype.passViewEvents = function(view){\n\tview.contents.listenedEvents.forEach(function(e){\n\t\tview.on(e, this.triggerViewEvent.bind(this));\n\t}.bind(this));\n\n\tview.on(\"selected\", this.triggerSelectedEvent.bind(this));\n};\n\nRendition.prototype.triggerViewEvent = function(e){\n\tthis.trigger(e.type, e);\n};\n\nRendition.prototype.triggerSelectedEvent = function(cfirange){\n\tthis.trigger(\"selected\", cfirange);\n};\n\nRendition.prototype.replacements = function(){\n\t// Wait for loading\n\t// return this.q.enqueue(function () {\n\t\t// Get thes books manifest\n\t\tvar manifest = this.book.package.manifest;\n\t\tvar manifestArray = Object.keys(manifest).\n\t\t\tmap(function (key){\n\t\t\t\treturn manifest[key];\n\t\t\t});\n\n\t\t// Exclude HTML\n\t\tvar items = manifestArray.\n\t\t\tfilter(function (item){\n\t\t\t\tif (item.type != \"application/xhtml+xml\" &&\n\t\t\t\t\t\titem.type != \"text/html\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t});\n\n\t\t// Only CSS\n\t\tvar css = items.\n\t\t\tfilter(function (item){\n\t\t\t\tif (item.type === \"text/css\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t});\n\n\t\t// Css Urls\n\t\tvar cssUrls = css.map(function(item) {\n\t\t\treturn item.href;\n\t\t});\n\n\t\t// All Assets Urls\n\t\tvar urls = items.\n\t\t\tmap(function(item) {\n\t\t\t\treturn item.href;\n\t\t\t}.bind(this));\n\n\t\t// Create blob urls for all the assets\n\t\tvar processing = urls.\n\t\t\tmap(function(url) {\n\t\t\t\tvar absolute = URI(url).absoluteTo(this.book.baseUrl).toString();\n\t\t\t\t// Full url from archive base\n\t\t\t\treturn this.book.unarchived.createUrl(absolute, {\"base64\": this.settings.useBase64});\n\t\t\t}.bind(this));\n\n\t\tvar replacementUrls;\n\n\t\t// After all the urls are created\n\t\treturn RSVP.all(processing)\n\t\t\t.then(function(_replacementUrls) {\n\t\t\t\tvar replaced = [];\n\n\t\t\t\treplacementUrls = _replacementUrls;\n\n\t\t\t\t// Replace Asset Urls in the text of all css files\n\t\t\t\tcssUrls.forEach(function(href) {\n\t\t\t\t\treplaced.push(this.replaceCss(href, urls, replacementUrls));\n\t\t\t\t}.bind(this));\n\n\t\t\t\treturn RSVP.all(replaced);\n\n\t\t\t}.bind(this))\n\t\t\t.then(function () {\n\t\t\t\t// Replace Asset Urls in chapters\n\t\t\t\t// by registering a hook after the sections contents has been serialized\n\t\t\t\tthis.book.spine.hooks.serialize.register(function(output, section) {\n\n\t\t\t\t\tthis.replaceAssets(section, urls, replacementUrls);\n\n\t\t\t\t}.bind(this));\n\n\t\t\t}.bind(this))\n\t\t\t.catch(function(reason){\n\t\t\t\tconsole.error(reason);\n\t\t\t});\n\t// }.bind(this));\n};\n\nRendition.prototype.replaceCss = function(href, urls, replacementUrls){\n\t\tvar newUrl;\n\t\tvar indexInUrls;\n\n\t\t// Find the absolute url of the css file\n\t\tvar fileUri = URI(href);\n\t\tvar absolute = fileUri.absoluteTo(this.book.baseUrl).toString();\n\t\t// Get the text of the css file from the archive\n\t\tvar textResponse = this.book.unarchived.getText(absolute);\n\t\t// Get asset links relative to css file\n\t\tvar relUrls = urls.\n\t\t\tmap(function(assetHref) {\n\t\t\t\tvar assetUri = URI(assetHref).absoluteTo(this.book.baseUrl);\n\t\t\t\tvar relative = assetUri.relativeTo(absolute).toString();\n\t\t\t\treturn relative;\n\t\t\t}.bind(this));\n\n\t\treturn textResponse.then(function (text) {\n\t\t\t// Replacements in the css text\n\t\t\ttext = replace.substitute(text, relUrls, replacementUrls);\n\n\t\t\t// Get the new url\n\t\t\tif (this.settings.useBase64) {\n\t\t\t\tnewUrl = core.createBase64Url(text, 'text/css');\n\t\t\t} else {\n\t\t\t\tnewUrl = core.createBlobUrl(text, 'text/css');\n\t\t\t}\n\n\t\t\t// switch the url in the replacementUrls\n\t\t\tindexInUrls = urls.indexOf(href);\n\t\t\tif (indexInUrls > -1) {\n\t\t\t\treplacementUrls[indexInUrls] = newUrl;\n\t\t\t}\n\n\t\t\treturn new RSVP.Promise(function(resolve, reject){\n\t\t\t\tresolve(urls, replacementUrls);\n\t\t\t});\n\n\t\t}.bind(this));\n\n};\n\nRendition.prototype.replaceAssets = function(section, urls, replacementUrls){\n\tvar fileUri = URI(section.url);\n\t// Get Urls relative to current sections\n\tvar relUrls = urls.\n\t\tmap(function(href) {\n\t\t\tvar assetUri = URI(href).absoluteTo(this.book.baseUrl);\n\t\t\tvar relative = assetUri.relativeTo(fileUri).toString();\n\t\t\treturn relative;\n\t\t}.bind(this));\n\n\n\tsection.output = replace.substitute(section.output, relUrls, replacementUrls);\n};\n\nRendition.prototype.range = function(_cfi, ignoreClass){\n\tvar cfi = new EpubCFI(_cfi);\n\tvar found = this.visible().filter(function (view) {\n\t\tif(cfi.spinePos === view.index) return true;\n\t});\n\n\t// Should only every return 1 item\n\tif (found.length) {\n\t\treturn found[0].range(cfi, ignoreClass);\n\t}\n};\n\nRendition.prototype.adjustImages = function(view) {\n\n\tview.addStylesheetRules([\n\t\t\t[\"img\",\n\t\t\t\t[\"max-width\", (view.layout.spreadWidth) + \"px\"],\n\t\t\t\t[\"max-height\", (view.layout.height) + \"px\"]\n\t\t\t]\n\t]);\n\treturn new RSVP.Promise(function(resolve, reject){\n\t\t// Wait to apply\n\t\tsetTimeout(function() {\n\t\t\tresolve();\n\t\t}, 1);\n\t});\n};\n\n//-- Enable binding events to Renderer\nRSVP.EventTarget.mixin(Rendition.prototype);\n\nmodule.exports = Rendition;\n","var URI = require('urijs');\nvar core = require('./core');\n\nfunction base(doc, section){\n\tvar base;\n\tvar head;\n\n\tif(!doc){\n\t\treturn;\n\t}\n\n\t// head = doc.querySelector(\"head\");\n\t// base = head.querySelector(\"base\");\n\thead = core.qs(doc, \"head\");\n\tbase = core.qs(head, \"base\");\n\n\tif(!base) {\n\t\tbase = doc.createElement(\"base\");\n\t\thead.insertBefore(base, head.firstChild);\n\t}\n\n\tbase.setAttribute(\"href\", section.url);\n}\n\nfunction canonical(doc, section){\n\tvar head;\n\tvar link;\n\tvar url = section.url; // window.location.origin + window.location.pathname + \"?loc=\" + encodeURIComponent(section.url);\n\n\tif(!doc){\n\t\treturn;\n\t}\n\n\thead = core.qs(doc, \"head\");\n\tlink = core.qs(head, \"link[rel='canonical']\");\n\n\tif (link) {\n\t\tlink.setAttribute(\"href\", url);\n\t} else {\n\t\tlink = doc.createElement(\"link\");\n\t\tlink.setAttribute(\"rel\", \"canonical\");\n\t\tlink.setAttribute(\"href\", url);\n\t\thead.appendChild(link);\n\t}\n}\n\nfunction links(view, renderer) {\n\n\tvar links = view.document.querySelectorAll(\"a[href]\");\n\tvar replaceLinks = function(link){\n\t\tvar href = link.getAttribute(\"href\");\n\n\t\tif(href.indexOf(\"mailto:\") === 0){\n\t\t\treturn;\n\t\t}\n\n\t\tvar linkUri = URI(href);\n\t\tvar absolute = linkUri.absoluteTo(view.section.url);\n\t\tvar relative = absolute.relativeTo(this.book.baseUrl).toString();\n\n\t\tif(linkUri.protocol()){\n\n\t\t\tlink.setAttribute(\"target\", \"_blank\");\n\n\t\t}else{\n\t\t\t/*\n\t\t\tif(baseDirectory) {\n\t\t\t\t// We must ensure that the file:// protocol is preserved for\n\t\t\t\t// local file links, as in certain contexts (such as under\n\t\t\t\t// Titanium), file links without the file:// protocol will not\n\t\t\t\t// work\n\t\t\t\tif (baseUri.protocol === \"file\") {\n\t\t\t\t\trelative = core.resolveUrl(baseUri.base, href);\n\t\t\t\t} else {\n\t\t\t\t\trelative = core.resolveUrl(baseDirectory, href);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\trelative = href;\n\t\t\t}\n\t\t\t*/\n\n\t\t\tif(linkUri.fragment()) {\n\t\t\t\t// do nothing with fragment yet\n\t\t\t} else {\n\t\t\t\tlink.onclick = function(){\n\t\t\t\t\trenderer.display(relative);\n\t\t\t\t\treturn false;\n\t\t\t\t};\n\t\t\t}\n\n\t\t}\n\t}.bind(this);\n\n\tfor (var i = 0; i < links.length; i++) {\n\t\treplaceLinks(links[i]);\n\t}\n\n\n};\n\nfunction substitute(content, urls, replacements) {\n\turls.forEach(function(url, i){\n\t\tif (url && replacements[i]) {\n\t\t\tcontent = content.replace(new RegExp(url, 'g'), replacements[i]);\n\t\t}\n\t});\n\treturn content;\n}\nmodule.exports = {\n\t'base': base,\n\t'canonical' : canonical,\n\t'links': links,\n\t'substitute': substitute\n};\n","var RSVP = require('rsvp');\nvar URI = require('urijs');\nvar core = require('./core');\n\nfunction request(url, type, withCredentials, headers) {\n\tvar supportsURL = (typeof window != \"undefined\") ? window.URL : false; // TODO: fallback for url if window isn't defined\n\tvar BLOB_RESPONSE = supportsURL ? \"blob\" : \"arraybuffer\";\n\tvar uri;\n\n\tvar deferred = new RSVP.defer();\n\n\tvar xhr = new XMLHttpRequest();\n\n\t//-- Check from PDF.js:\n\t// https://github.com/mozilla/pdf.js/blob/master/web/compatibility.js\n\tvar xhrPrototype = XMLHttpRequest.prototype;\n\n\tvar header;\n\n\tif (!('overrideMimeType' in xhrPrototype)) {\n\t\t// IE10 might have response, but not overrideMimeType\n\t\tObject.defineProperty(xhrPrototype, 'overrideMimeType', {\n\t\t\tvalue: function xmlHttpRequestOverrideMimeType(mimeType) {}\n\t\t});\n\t}\n\tif(withCredentials) {\n\t\txhr.withCredentials = true;\n\t}\n\n\txhr.onreadystatechange = handler;\n\txhr.onerror = err;\n\n\txhr.open(\"GET\", url, true);\n\n\tfor(header in headers) {\n\t\txhr.setRequestHeader(header, headers[header]);\n\t}\n\n\tif(type == \"json\") {\n\t\txhr.setRequestHeader(\"Accept\", \"application/json\");\n\t}\n\n\t// If type isn't set, determine it from the file extension\n\tif(!type) {\n\t\turi = URI(url);\n\t\ttype = uri.suffix();\n\t}\n\n\tif(type == 'blob'){\n\t\txhr.responseType = BLOB_RESPONSE;\n\t}\n\n\n\tif(core.isXml(type)) {\n\t\t// xhr.responseType = \"document\";\n\t\txhr.overrideMimeType('text/xml'); // for OPF parsing\n\t}\n\n\tif(type == 'xhtml') {\n\t\t// xhr.responseType = \"document\";\n\t}\n\n\tif(type == 'html' || type == 'htm') {\n\t\t// xhr.responseType = \"document\";\n\t }\n\n\tif(type == \"binary\") {\n\t\txhr.responseType = \"arraybuffer\";\n\t}\n\n\txhr.send();\n\n\tfunction err(e) {\n\t\tconsole.error(e);\n\t\tdeferred.reject(e);\n\t}\n\n\tfunction handler() {\n\t\tif (this.readyState === XMLHttpRequest.DONE) {\n\n\t\t\tif (this.status === 200 || this.responseXML ) { //-- Firefox is reporting 0 for blob urls\n\t\t\t\tvar r;\n\n\t\t\t\tif (!this.response && !this.responseXML) {\n\t\t\t\t\tdeferred.reject({\n\t\t\t\t\t\tstatus: this.status,\n\t\t\t\t\t\tmessage : \"Empty Response\",\n\t\t\t\t\t\tstack : new Error().stack\n\t\t\t\t\t});\n\t\t\t\t\treturn deferred.promise;\n\t\t\t\t}\n\n\t\t\t\tif (this.status === 403) {\n\t\t\t\t\tdeferred.reject({\n\t\t\t\t\t\tstatus: this.status,\n\t\t\t\t\t\tresponse: this.response,\n\t\t\t\t\t\tmessage : \"Forbidden\",\n\t\t\t\t\t\tstack : new Error().stack\n\t\t\t\t\t});\n\t\t\t\t\treturn deferred.promise;\n\t\t\t\t}\n\n\t\t\t\tif((this.responseType == '' || this.responseType == 'document')\n\t\t\t\t\t\t&& this.responseXML){\n\t\t\t\t\tr = this.responseXML;\n\t\t\t\t} else\n\t\t\t\tif(core.isXml(type)){\n\t\t\t\t\t// xhr.overrideMimeType('text/xml'); // for OPF parsing\n\t\t\t\t\t// If this.responseXML wasn't set, try to parse using a DOMParser from text\n\t\t\t\t\tr = core.parse(this.response, \"text/xml\");\n\t\t\t\t}else\n\t\t\t\tif(type == 'xhtml'){\n\t\t\t\t\tr = core.parse(this.response, \"application/xhtml+xml\");\n\t\t\t\t}else\n\t\t\t\tif(type == 'html' || type == 'htm'){\n\t\t\t\t\tr = core.parse(this.response, \"text/html\");\n\t\t\t\t}else\n\t\t\t\tif(type == 'json'){\n\t\t\t\t\tr = JSON.parse(this.response);\n\t\t\t\t}else\n\t\t\t\tif(type == 'blob'){\n\n\t\t\t\t\tif(supportsURL) {\n\t\t\t\t\t\tr = this.response;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t//-- Safari doesn't support responseType blob, so create a blob from arraybuffer\n\t\t\t\t\t\tr = new Blob([this.response]);\n\t\t\t\t\t}\n\n\t\t\t\t}else{\n\t\t\t\t\tr = this.response;\n\t\t\t\t}\n\n\t\t\t\tdeferred.resolve(r);\n\t\t\t} else {\n\n\t\t\t\tdeferred.reject({\n\t\t\t\t\tstatus: this.status,\n\t\t\t\t\tmessage : this.response,\n\t\t\t\t\tstack : new Error().stack\n\t\t\t\t});\n\n\t\t\t}\n\t\t}\n\t}\n\n\treturn deferred.promise;\n};\n\nmodule.exports = request;\n","var RSVP = require('rsvp');\nvar URI = require('urijs');\nvar core = require('./core');\nvar EpubCFI = require('./epubcfi');\nvar Hook = require('./hook');\n\nfunction Section(item, hooks){\n\t\tthis.idref = item.idref;\n\t\tthis.linear = item.linear;\n\t\tthis.properties = item.properties;\n\t\tthis.index = item.index;\n\t\tthis.href = item.href;\n\t\tthis.url = item.url;\n\t\tthis.next = item.next;\n\t\tthis.prev = item.prev;\n\n\t\tthis.cfiBase = item.cfiBase;\n\n\t\tif (hooks) {\n\t\t\tthis.hooks = hooks;\n\t\t} else {\n\t\t\tthis.hooks = {};\n\t\t\tthis.hooks.serialize = new Hook(this);\n\t\t\tthis.hooks.content = new Hook(this);\n\t\t}\n\n};\n\n\nSection.prototype.load = function(_request){\n\tvar request = _request || this.request || require('./request');\n\tvar loading = new RSVP.defer();\n\tvar loaded = loading.promise;\n\n\tif(this.contents) {\n\t\tloading.resolve(this.contents);\n\t} else {\n\t\trequest(this.url)\n\t\t\t.then(function(xml){\n\t\t\t\tvar base;\n\t\t\t\tvar directory = URI(this.url).directory();\n\n\t\t\t\tthis.document = xml;\n\t\t\t\tthis.contents = xml.documentElement;\n\n\t\t\t\treturn this.hooks.content.trigger(this.document, this);\n\t\t\t}.bind(this))\n\t\t\t.then(function(){\n\t\t\t\tloading.resolve(this.contents);\n\t\t\t}.bind(this))\n\t\t\t.catch(function(error){\n\t\t\t\tloading.reject(error);\n\t\t\t});\n\t}\n\n\treturn loaded;\n};\n\nSection.prototype.base = function(_document){\n\t\tvar task = new RSVP.defer();\n\t\tvar base = _document.createElement(\"base\"); // TODO: check if exists\n\t\tvar head;\n\t\tconsole.log(window.location.origin + \"/\" +this.url);\n\n\t\tbase.setAttribute(\"href\", window.location.origin + \"/\" +this.url);\n\n\t\tif(_document) {\n\t\t\thead = _document.querySelector(\"head\");\n\t\t}\n\t\tif(head) {\n\t\t\thead.insertBefore(base, head.firstChild);\n\t\t\ttask.resolve();\n\t\t} else {\n\t\t\ttask.reject(new Error(\"No head to insert into\"));\n\t\t}\n\n\n\t\treturn task.promise;\n};\n\nSection.prototype.beforeSectionLoad = function(){\n\t// Stub for a hook - replace me for now\n};\n\nSection.prototype.render = function(_request){\n\tvar rendering = new RSVP.defer();\n\tvar rendered = rendering.promise;\n\tthis.output; // TODO: better way to return this from hooks?\n\n\tthis.load(_request).\n\t\tthen(function(contents){\n\t\t\tvar serializer;\n\n\t\t\tif (typeof XMLSerializer === \"undefined\") {\n\t\t\t\tXMLSerializer = require('xmldom').XMLSerializer;\n\t\t\t}\n\t\t\tserializer = new XMLSerializer();\n\t\t\tthis.output = serializer.serializeToString(contents);\n\t\t\treturn this.output;\n\t\t}.bind(this)).\n\t\tthen(function(){\n\t\t\treturn this.hooks.serialize.trigger(this.output, this);\n\t\t}.bind(this)).\n\t\tthen(function(){\n\t\t\trendering.resolve(this.output);\n\t\t}.bind(this))\n\t\t.catch(function(error){\n\t\t\trendering.reject(error);\n\t\t});\n\n\treturn rendered;\n};\n\nSection.prototype.find = function(_query){\n\n};\n\n/**\n* Reconciles the current chapters layout properies with\n* the global layout properities.\n* Takes: global layout settings object, chapter properties string\n* Returns: Object with layout properties\n*/\nSection.prototype.reconcileLayoutSettings = function(global){\n\t//-- Get the global defaults\n\tvar settings = {\n\t\tlayout : global.layout,\n\t\tspread : global.spread,\n\t\torientation : global.orientation\n\t};\n\n\t//-- Get the chapter's display type\n\tthis.properties.forEach(function(prop){\n\t\tvar rendition = prop.replace(\"rendition:\", '');\n\t\tvar split = rendition.indexOf(\"-\");\n\t\tvar property, value;\n\n\t\tif(split != -1){\n\t\t\tproperty = rendition.slice(0, split);\n\t\t\tvalue = rendition.slice(split+1);\n\n\t\t\tsettings[property] = value;\n\t\t}\n\t});\n return settings;\n};\n\nSection.prototype.cfiFromRange = function(_range) {\n\treturn new EpubCFI(_range, this.cfiBase).toString();\n};\n\nSection.prototype.cfiFromElement = function(el) {\n\treturn new EpubCFI(el, this.cfiBase).toString();\n};\n\nmodule.exports = Section;\n","var RSVP = require('rsvp');\nvar core = require('./core');\nvar EpubCFI = require('./epubcfi');\nvar Hook = require('./hook');\nvar Section = require('./section');\nvar replacements = require('./replacements');\n\nfunction Spine(_request){\n\tthis.request = _request;\n\tthis.spineItems = [];\n\tthis.spineByHref = {};\n\tthis.spineById = {};\n\n\tthis.hooks = {};\n\tthis.hooks.serialize = new Hook();\n\tthis.hooks.content = new Hook();\n\n\t// Register replacements\n\tthis.hooks.content.register(replacements.base);\n\tthis.hooks.content.register(replacements.canonical);\n\n\tthis.epubcfi = new EpubCFI();\n\n\tthis.loaded = false;\n};\n\nSpine.prototype.load = function(_package) {\n\n\tthis.items = _package.spine;\n\tthis.manifest = _package.manifest;\n\tthis.spineNodeIndex = _package.spineNodeIndex;\n\tthis.baseUrl = _package.baseUrl || '';\n\tthis.length = this.items.length;\n\n\tthis.items.forEach(function(item, index){\n\t\tvar href, url;\n\t\tvar manifestItem = this.manifest[item.idref];\n\t\tvar spineItem;\n\n\t\titem.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.idref);\n\n\t\tif(manifestItem) {\n\t\t\titem.href = manifestItem.href;\n\t\t\titem.url = this.baseUrl + item.href;\n\n\t\t\tif(manifestItem.properties.length){\n\t\t\t\titem.properties.push.apply(item.properties, manifestItem.properties);\n\t\t\t}\n\t\t}\n\n\t\t// if(index > 0) {\n\t\t\titem.prev = function(){ return this.get(index-1); }.bind(this);\n\t\t// }\n\n\t\t// if(index+1 < this.items.length) {\n\t\t\titem.next = function(){ return this.get(index+1); }.bind(this);\n\t\t// }\n\n\t\tspineItem = new Section(item, this.hooks);\n\n\t\tthis.append(spineItem);\n\n\n\t}.bind(this));\n\n\tthis.loaded = true;\n};\n\n// book.spine.get();\n// book.spine.get(1);\n// book.spine.get(\"chap1.html\");\n// book.spine.get(\"#id1234\");\nSpine.prototype.get = function(target) {\n\tvar index = 0;\n\n\tif(this.epubcfi.isCfiString(target)) {\n\t\tcfi = new EpubCFI(target);\n\t\tindex = cfi.spinePos;\n\t} else if(target && (typeof target === \"number\" || isNaN(target) === false)){\n\t\tindex = target;\n\t} else if(target && target.indexOf(\"#\") === 0) {\n\t\tindex = this.spineById[target.substring(1)];\n\t} else if(target) {\n\t\t// Remove fragments\n\t\ttarget = target.split(\"#\")[0];\n\t\tindex = this.spineByHref[target];\n\t}\n\n\treturn this.spineItems[index] || null;\n};\n\nSpine.prototype.append = function(section) {\n\tvar index = this.spineItems.length;\n\tsection.index = index;\n\n\tthis.spineItems.push(section);\n\n\tthis.spineByHref[section.href] = index;\n\tthis.spineById[section.idref] = index;\n\n\treturn index;\n};\n\nSpine.prototype.prepend = function(section) {\n\tvar index = this.spineItems.unshift(section);\n\tthis.spineByHref[section.href] = 0;\n\tthis.spineById[section.idref] = 0;\n\n\t// Re-index\n\tthis.spineItems.forEach(function(item, index){\n\t\titem.index = index;\n\t});\n\n\treturn 0;\n};\n\nSpine.prototype.insert = function(section, index) {\n\n};\n\nSpine.prototype.remove = function(section) {\n\tvar index = this.spineItems.indexOf(section);\n\n\tif(index > -1) {\n\t\tdelete this.spineByHref[section.href];\n\t\tdelete this.spineById[section.idref];\n\n\t\treturn this.spineItems.splice(index, 1);\n\t}\n};\n\nSpine.prototype.each = function() {\n\treturn this.spineItems.forEach.apply(this.spineItems, arguments);\n};\n\nmodule.exports = Spine;\n","var core = require('./core');\n\nfunction Stage(_options) {\n\tthis.settings = _options || {};\n\tthis.id = \"epubjs-container-\" + core.uuid();\n\n\tthis.container = this.create(this.settings);\n\n\tif(this.settings.hidden) {\n\t\tthis.wrapper = this.wrap(this.container);\n\t}\n\n}\n\n/**\n* Creates an element to render to.\n* Resizes to passed width and height or to the elements size\n*/\nStage.prototype.create = function(options){\n\tvar height = options.height;// !== false ? options.height : \"100%\";\n\tvar width = options.width;// !== false ? options.width : \"100%\";\n\tvar overflow = options.overflow || false;\n\tvar axis = options.axis || \"vertical\";\n\n\tif(options.height && core.isNumber(options.height)) {\n\t\theight = options.height + \"px\";\n\t}\n\n\tif(options.width && core.isNumber(options.width)) {\n\t\twidth = options.width + \"px\";\n\t}\n\n\t// Create new container element\n\tcontainer = document.createElement(\"div\");\n\n\tcontainer.id = this.id;\n\tcontainer.classList.add(\"epub-container\");\n\n\t// Style Element\n\t// container.style.fontSize = \"0\";\n\tcontainer.style.wordSpacing = \"0\";\n\tcontainer.style.lineHeight = \"0\";\n\tcontainer.style.verticalAlign = \"top\";\n\n\tif(axis === \"horizontal\") {\n\t\tcontainer.style.whiteSpace = \"nowrap\";\n\t}\n\n\tif(width){\n\t\tcontainer.style.width = width;\n\t}\n\n\tif(height){\n\t\tcontainer.style.height = height;\n\t}\n\n\tif (overflow) {\n\t\tcontainer.style.overflow = overflow;\n\t}\n\n\treturn container;\n};\n\nStage.wrap = function(container) {\n\tvar wrapper = document.createElement(\"div\");\n\n\twrapper.style.visibility = \"hidden\";\n\twrapper.style.overflow = \"hidden\";\n\twrapper.style.width = \"0\";\n\twrapper.style.height = \"0\";\n\n\twrapper.appendChild(container);\n\treturn wrapper;\n};\n\n\nStage.prototype.getElement = function(_element){\n\tvar element;\n\n\tif(core.isElement(_element)) {\n\t\telement = _element;\n\t} else if (typeof _element === \"string\") {\n\t\telement = document.getElementById(_element);\n\t}\n\n\tif(!element){\n\t\tconsole.error(\"Not an Element\");\n\t\treturn;\n\t}\n\n\treturn element;\n};\n\nStage.prototype.attachTo = function(what){\n\n\tvar element = this.getElement(what);\n\tvar base;\n\n\tif(!element){\n\t\treturn;\n\t}\n\n\tif(this.settings.hidden) {\n\t\tbase = this.wrapper;\n\t} else {\n\t\tbase = this.container;\n\t}\n\n\telement.appendChild(base);\n\n\tthis.element = element;\n\n\treturn element;\n\n};\n\nStage.prototype.getContainer = function() {\n\treturn this.container;\n};\n\nStage.prototype.onResize = function(func){\n\t// Only listen to window for resize event if width and height are not fixed.\n\t// This applies if it is set to a percent or auto.\n\tif(!core.isNumber(this.settings.width) ||\n\t\t !core.isNumber(this.settings.height) ) {\n\t\twindow.addEventListener(\"resize\", func, false);\n\t}\n\n};\n\nStage.prototype.size = function(width, height){\n\tvar bounds;\n\t// var width = _width || this.settings.width;\n\t// var height = _height || this.settings.height;\n\n\t// If width or height are set to false, inherit them from containing element\n\tif(width === null) {\n\t\tbounds = this.element.getBoundingClientRect();\n\n\t\tif(bounds.width) {\n\t\t\twidth = bounds.width;\n\t\t\tthis.container.style.width = bounds.width + \"px\";\n\t\t}\n\t}\n\n\tif(height === null) {\n\t\tbounds = bounds || this.element.getBoundingClientRect();\n\n\t\tif(bounds.height) {\n\t\t\theight = bounds.height;\n\t\t\tthis.container.style.height = bounds.height + \"px\";\n\t\t}\n\n\t}\n\n\tif(!core.isNumber(width)) {\n\t\tbounds = this.container.getBoundingClientRect();\n\t\twidth = bounds.width;\n\t\t//height = bounds.height;\n\t}\n\n\tif(!core.isNumber(height)) {\n\t\tbounds = bounds || this.container.getBoundingClientRect();\n\t\t//width = bounds.width;\n\t\theight = bounds.height;\n\t}\n\n\n\tthis.containerStyles = window.getComputedStyle(this.container);\n\n\tthis.containerPadding = {\n\t\tleft: parseFloat(this.containerStyles[\"padding-left\"]) || 0,\n\t\tright: parseFloat(this.containerStyles[\"padding-right\"]) || 0,\n\t\ttop: parseFloat(this.containerStyles[\"padding-top\"]) || 0,\n\t\tbottom: parseFloat(this.containerStyles[\"padding-bottom\"]) || 0\n\t};\n\n\treturn {\n\t\twidth: width -\n\t\t\t\t\t\tthis.containerPadding.left -\n\t\t\t\t\t\tthis.containerPadding.right,\n\t\theight: height -\n\t\t\t\t\t\tthis.containerPadding.top -\n\t\t\t\t\t\tthis.containerPadding.bottom\n\t};\n\n};\n\nStage.prototype.bounds = function(){\n\n\tif(!this.container) {\n\t\treturn core.windowBounds();\n\t} else {\n\t\treturn this.container.getBoundingClientRect();\n\t}\n\n}\n\nStage.prototype.getSheet = function(){\n\tvar style = document.createElement(\"style\");\n\n\t// WebKit hack --> https://davidwalsh.name/add-rules-stylesheets\n\tstyle.appendChild(document.createTextNode(\"\"));\n\n\tdocument.head.appendChild(style);\n\n\treturn style.sheet;\n}\n\nStage.prototype.addStyleRules = function(selector, rulesArray){\n\tvar scope = \"#\" + this.id + \" \";\n\tvar rules = \"\";\n\n\tif(!this.sheet){\n\t\tthis.sheet = this.getSheet();\n\t}\n\n\trulesArray.forEach(function(set) {\n\t\tfor (var prop in set) {\n\t\t\tif(set.hasOwnProperty(prop)) {\n\t\t\t\trules += prop + \":\" + set[prop] + \";\";\n\t\t\t}\n\t\t}\n\t})\n\n\tthis.sheet.insertRule(scope + selector + \" {\" + rules + \"}\", 0);\n}\n\n\n\nmodule.exports = Stage;\n","var RSVP = require('rsvp');\nvar URI = require('urijs');\nvar core = require('./core');\nvar request = require('./request');\nvar mime = require('../libs/mime/mime');\n\nfunction Unarchive() {\n\n\tthis.checkRequirements();\n\tthis.urlCache = {};\n\n}\n\nUnarchive.prototype.checkRequirements = function(callback){\n\ttry {\n\t\tif (typeof JSZip !== 'undefined') {\n\t\t\tthis.zip = new JSZip();\n\t\t} else {\n\t\t\tJSZip = require('jszip');\n\t\t\tthis.zip = new JSZip();\n\t\t}\n\t} catch (e) {\n\t\tconsole.error(\"JSZip lib not loaded\");\n\t}\n};\n\nUnarchive.prototype.open = function(zipUrl, isBase64){\n\tif (zipUrl instanceof ArrayBuffer || isBase64) {\n\t\treturn this.zip.loadAsync(zipUrl, {\"base64\": isBase64});\n\t} else {\n\t\treturn request(zipUrl, \"binary\")\n\t\t\t.then(function(data){\n\t\t\t\treturn this.zip.loadAsync(data);\n\t\t\t}.bind(this));\n\t}\n};\n\nUnarchive.prototype.request = function(url, type){\n\tvar deferred = new RSVP.defer();\n\tvar response;\n\tvar r;\n\n\t// If type isn't set, determine it from the file extension\n\tif(!type) {\n\t\turi = URI(url);\n\t\ttype = uri.suffix();\n\t}\n\n\tif(type == 'blob'){\n\t\tresponse = this.getBlob(url);\n\t} else {\n\t\tresponse = this.getText(url);\n\t}\n\n\tif (response) {\n\t\tresponse.then(function (r) {\n\t\t\tresult = this.handleResponse(r, type);\n\t\t\tdeferred.resolve(result);\n\t\t}.bind(this));\n\t} else {\n\t\tdeferred.reject({\n\t\t\tmessage : \"File not found in the epub: \" + url,\n\t\t\tstack : new Error().stack\n\t\t});\n\t}\n\treturn deferred.promise;\n};\n\nUnarchive.prototype.handleResponse = function(response, type){\n\tvar r;\n\n\tif(type == \"json\") {\n\t\tr = JSON.parse(response);\n\t}\n\telse\n\tif(core.isXml(type)) {\n\t\tr = core.parse(response, \"text/xml\");\n\t}\n\telse\n\tif(type == 'xhtml') {\n\t\tr = core.parse(response, \"application/xhtml+xml\");\n\t}\n\telse\n\tif(type == 'html' || type == 'htm') {\n\t\tr = core.parse(response, \"text/html\");\n\t } else {\n\t\t r = response;\n\t }\n\n\treturn r;\n};\n\nUnarchive.prototype.getBlob = function(url, _mimeType){\n\tvar decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash\n\tvar entry = this.zip.file(decodededUrl);\n\tvar mimeType;\n\n\tif(entry) {\n\t\tmimeType = _mimeType || mime.lookup(entry.name);\n\t\treturn entry.async(\"uint8array\").then(function(uint8array) {\n\t\t\treturn new Blob([uint8array], {type : mimeType});\n\t\t});\n\t}\n};\n\nUnarchive.prototype.getText = function(url, encoding){\n\tvar decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash\n\tvar entry = this.zip.file(decodededUrl);\n\n\tif(entry) {\n\t\treturn entry.async(\"string\").then(function(text) {\n\t\t\treturn text;\n\t\t});\n\t}\n};\n\nUnarchive.prototype.getBase64 = function(url, _mimeType){\n\tvar decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash\n\tvar entry = this.zip.file(decodededUrl);\n\tvar mimeType;\n\n\tif(entry) {\n\t\tmimeType = _mimeType || mime.lookup(entry.name);\n\t\treturn entry.async(\"base64\").then(function(data) {\n\t\t\treturn \"data:\" + mimeType + \";base64,\" + data;\n\t\t});\n\t}\n};\n\nUnarchive.prototype.createUrl = function(url, options){\n\tvar deferred = new RSVP.defer();\n\tvar _URL = window.URL || window.webkitURL || window.mozURL;\n\tvar tempUrl;\n\tvar blob;\n\tvar response;\n\tvar useBase64 = options && options.base64;\n\n\tif(url in this.urlCache) {\n\t\tdeferred.resolve(this.urlCache[url]);\n\t\treturn deferred.promise;\n\t}\n\n\tif (useBase64) {\n\t\tresponse = this.getBase64(url);\n\n\t\tif (response) {\n\t\t\tresponse.then(function(tempUrl) {\n\n\t\t\t\tthis.urlCache[url] = tempUrl;\n\t\t\t\tdeferred.resolve(tempUrl);\n\n\t\t\t}.bind(this));\n\n\t\t}\n\n\t} else {\n\n\t\tresponse = this.getBlob(url);\n\n\t\tif (response) {\n\t\t\tresponse.then(function(blob) {\n\n\t\t\t\ttempUrl = _URL.createObjectURL(blob);\n\t\t\t\tthis.urlCache[url] = tempUrl;\n\t\t\t\tdeferred.resolve(tempUrl);\n\n\t\t\t}.bind(this));\n\n\t\t}\n\t}\n\n\n\tif (!response) {\n\t\tdeferred.reject({\n\t\t\tmessage : \"File not found in the epub: \" + url,\n\t\t\tstack : new Error().stack\n\t\t});\n\t}\n\n\treturn deferred.promise;\n};\n\nUnarchive.prototype.revokeUrl = function(url){\n\tvar _URL = window.URL || window.webkitURL || window.mozURL;\n\tvar fromCache = this.urlCache[url];\n\tif(fromCache) _URL.revokeObjectURL(fromCache);\n};\n\nmodule.exports = Unarchive;\n","function Views(container) {\n\tthis.container = container;\n\tthis._views = [];\n\tthis.length = 0;\n\tthis.hidden = false;\n};\n\nViews.prototype.all = function() {\n\treturn this._views;\n};\n\nViews.prototype.first = function() {\n\treturn this._views[0];\n};\n\nViews.prototype.last = function() {\n\treturn this._views[this._views.length-1];\n};\n\nViews.prototype.indexOf = function(view) {\n\treturn this._views.indexOf(view);\n};\n\nViews.prototype.slice = function() {\n\treturn this._views.slice.apply(this._views, arguments);\n};\n\nViews.prototype.get = function(i) {\n\treturn this._views[i];\n};\n\nViews.prototype.append = function(view){\n\tthis._views.push(view);\n\tif(this.container){\n\t\tthis.container.appendChild(view.element);\n\t}\n\tthis.length++;\n\treturn view;\n};\n\nViews.prototype.prepend = function(view){\n\tthis._views.unshift(view);\n\tif(this.container){\n\t\tthis.container.insertBefore(view.element, this.container.firstChild);\n\t}\n\tthis.length++;\n\treturn view;\n};\n\nViews.prototype.insert = function(view, index) {\n\tthis._views.splice(index, 0, view);\n\n\tif(this.container){\n\t\tif(index < this.container.children.length){\n\t\t\tthis.container.insertBefore(view.element, this.container.children[index]);\n\t\t} else {\n\t\t\tthis.container.appendChild(view.element);\n\t\t}\n\t}\n\n\tthis.length++;\n\treturn view;\n};\n\nViews.prototype.remove = function(view) {\n\tvar index = this._views.indexOf(view);\n\n\tif(index > -1) {\n\t\tthis._views.splice(index, 1);\n\t}\n\n\n\tthis.destroy(view);\n\n\tthis.length--;\n};\n\nViews.prototype.destroy = function(view) {\n\tview.off(\"resized\");\n\n\tif(view.displayed){\n\t\tview.destroy();\n\t}\n\n\tif(this.container){\n\t\t this.container.removeChild(view.element);\n\t}\n\tview = null;\n};\n\n// Iterators\n\nViews.prototype.each = function() {\n\treturn this._views.forEach.apply(this._views, arguments);\n};\n\nViews.prototype.clear = function(){\n\t// Remove all views\n\tvar view;\n\tvar len = this.length;\n\n\tif(!this.length) return;\n\n\tfor (var i = 0; i < len; i++) {\n\t\tview = this._views[i];\n\t\tthis.destroy(view);\n\t}\n\n\tthis._views = [];\n\tthis.length = 0;\n};\n\nViews.prototype.find = function(section){\n\n\tvar view;\n\tvar len = this.length;\n\n\tfor (var i = 0; i < len; i++) {\n\t\tview = this._views[i];\n\t\tif(view.displayed && view.section.index == section.index) {\n\t\t\treturn view;\n\t\t}\n\t}\n\n};\n\nViews.prototype.displayed = function(){\n\tvar displayed = [];\n\tvar view;\n\tvar len = this.length;\n\n\tfor (var i = 0; i < len; i++) {\n\t\tview = this._views[i];\n\t\tif(view.displayed){\n\t\t\tdisplayed.push(view);\n\t\t}\n\t}\n\treturn displayed;\n};\n\nViews.prototype.show = function(){\n\tvar view;\n\tvar len = this.length;\n\n\tfor (var i = 0; i < len; i++) {\n\t\tview = this._views[i];\n\t\tif(view.displayed){\n\t\t\tview.show();\n\t\t}\n\t}\n\tthis.hidden = false;\n};\n\nViews.prototype.hide = function(){\n\tvar view;\n\tvar len = this.length;\n\n\tfor (var i = 0; i < len; i++) {\n\t\tview = this._views[i];\n\t\tif(view.displayed){\n\t\t\tview.hide();\n\t\t}\n\t}\n\tthis.hidden = true;\n};\n\nmodule.exports = Views;\n","var RSVP = require('rsvp');\nvar core = require('../core');\nvar EpubCFI = require('../epubcfi');\nvar Contents = require('../contents');\n\nfunction IframeView(section, options) {\n\tthis.settings = core.extend({\n\t\tignoreClass : '',\n\t\taxis: 'vertical',\n\t\twidth: 0,\n\t\theight: 0,\n\t\tlayout: undefined,\n\t\tglobalLayoutProperties: {},\n\t}, options || {});\n\n\tthis.id = \"epubjs-view-\" + core.uuid();\n\tthis.section = section;\n\tthis.index = section.index;\n\n\tthis.element = this.container(this.settings.axis);\n\n\tthis.added = false;\n\tthis.displayed = false;\n\tthis.rendered = false;\n\n\tthis.width = this.settings.width;\n\tthis.height = this.settings.height;\n\n\tthis.fixedWidth = 0;\n\tthis.fixedHeight = 0;\n\n\t// Blank Cfi for Parsing\n\tthis.epubcfi = new EpubCFI();\n\n\tthis.layout = this.settings.layout;\n\t// Dom events to listen for\n\t// this.listenedEvents = [\"keydown\", \"keyup\", \"keypressed\", \"mouseup\", \"mousedown\", \"click\", \"touchend\", \"touchstart\"];\n};\n\nIframeView.prototype.container = function(axis) {\n\tvar element = document.createElement('div');\n\n\telement.classList.add(\"epub-view\");\n\n\t// this.element.style.minHeight = \"100px\";\n\telement.style.height = \"0px\";\n\telement.style.width = \"0px\";\n\telement.style.overflow = \"hidden\";\n\n\tif(axis && axis == \"horizontal\"){\n\t\telement.style.display = \"inline-block\";\n\t} else {\n\t\telement.style.display = \"block\";\n\t}\n\n\treturn element;\n};\n\nIframeView.prototype.create = function() {\n\n\tif(this.iframe) {\n\t\treturn this.iframe;\n\t}\n\n\tif(!this.element) {\n\t\tthis.element = this.createContainer();\n\t}\n\n\tthis.iframe = document.createElement('iframe');\n\tthis.iframe.id = this.id;\n\tthis.iframe.scrolling = \"no\"; // Might need to be removed: breaks ios width calculations\n\tthis.iframe.style.overflow = \"hidden\";\n\tthis.iframe.seamless = \"seamless\";\n\t// Back up if seamless isn't supported\n\tthis.iframe.style.border = \"none\";\n\n\tthis.resizing = true;\n\n\t// this.iframe.style.display = \"none\";\n\tthis.element.style.visibility = \"hidden\";\n\tthis.iframe.style.visibility = \"hidden\";\n\n\tthis.iframe.style.width = \"0\";\n\tthis.iframe.style.height = \"0\";\n\tthis._width = 0;\n\tthis._height = 0;\n\n\tthis.element.appendChild(this.iframe);\n\tthis.added = true;\n\n\tthis.elementBounds = core.bounds(this.element);\n\n\t// if(width || height){\n\t// this.resize(width, height);\n\t// } else if(this.width && this.height){\n\t// this.resize(this.width, this.height);\n\t// } else {\n\t// this.iframeBounds = core.bounds(this.iframe);\n\t// }\n\n\t// Firefox has trouble with baseURI and srcdoc\n\t// TODO: Disable for now in firefox\n\n\tif(!!(\"srcdoc\" in this.iframe)) {\n\t\tthis.supportsSrcdoc = true;\n\t} else {\n\t\tthis.supportsSrcdoc = false;\n\t}\n\n\treturn this.iframe;\n};\n\nIframeView.prototype.render = function(request, show) {\n\n\t// view.onLayout = this.layout.format.bind(this.layout);\n\tthis.create();\n\n\t// Fit to size of the container, apply padding\n\tthis.size();\n\n\tif(!this.sectionRender) {\n\t\tthis.sectionRender = this.section.render(request);\n\t}\n\n\t// Render Chain\n\treturn this.sectionRender\n\t\t.then(function(contents){\n\t\t\treturn this.load(contents);\n\t\t}.bind(this))\n\t\t// .then(function(doc){\n\t\t// \treturn this.hooks.content.trigger(view, this);\n\t\t// }.bind(this))\n\t\t.then(function(){\n\t\t\t// this.settings.layout.format(view.contents);\n\t\t\t// return this.hooks.layout.trigger(view, this);\n\t\t}.bind(this))\n\t\t// .then(function(){\n\t\t// \treturn this.display();\n\t\t// }.bind(this))\n\t\t// .then(function(){\n\t\t// \treturn this.hooks.render.trigger(view, this);\n\t\t// }.bind(this))\n\t\t.then(function(){\n\n\t\t\t// apply the layout function to the contents\n\t\t\tthis.settings.layout.format(this.contents);\n\n\t\t\t// Expand the iframe to the full size of the content\n\t\t\tthis.expand();\n\n\t\t\t// Listen for events that require an expansion of the iframe\n\t\t\tthis.addListeners();\n\n\t\t\tif(show !== false) {\n\t\t\t\t//this.q.enqueue(function(view){\n\t\t\t\t\t// this.show();\n\t\t\t\t//}, view);\n\t\t\t}\n\t\t\t// this.map = new Map(view, this.layout);\n\t\t\t//this.hooks.show.trigger(view, this);\n\t\t\tthis.trigger(\"rendered\", this.section);\n\n\t\t}.bind(this))\n\t\t.catch(function(e){\n\t\t\tthis.trigger(\"loaderror\", e);\n\t\t}.bind(this));\n\n};\n\n// Determine locks base on settings\nIframeView.prototype.size = function(_width, _height) {\n\tvar width = _width || this.settings.width;\n\tvar height = _height || this.settings.height;\n\n\tif(this.layout.name === \"pre-paginated\") {\n\t\tthis.lock(\"both\", width, height);\n\t} else if(this.settings.axis === \"horizontal\") {\n\t\tthis.lock(\"height\", width, height);\n\t} else {\n\t\tthis.lock(\"width\", width, height);\n\t}\n\n};\n\n// Lock an axis to element dimensions, taking borders into account\nIframeView.prototype.lock = function(what, width, height) {\n\tvar elBorders = core.borders(this.element);\n\tvar iframeBorders;\n\n\tif(this.iframe) {\n\t\tiframeBorders = core.borders(this.iframe);\n\t} else {\n\t\tiframeBorders = {width: 0, height: 0};\n\t}\n\n\tif(what == \"width\" && core.isNumber(width)){\n\t\tthis.lockedWidth = width - elBorders.width - iframeBorders.width;\n\t\tthis.resize(this.lockedWidth, width); // width keeps ratio correct\n\t}\n\n\tif(what == \"height\" && core.isNumber(height)){\n\t\tthis.lockedHeight = height - elBorders.height - iframeBorders.height;\n\t\tthis.resize(width, this.lockedHeight);\n\t}\n\n\tif(what === \"both\" &&\n\t\t core.isNumber(width) &&\n\t\t core.isNumber(height)){\n\n\t\tthis.lockedWidth = width - elBorders.width - iframeBorders.width;\n\t\tthis.lockedHeight = height - elBorders.height - iframeBorders.height;\n\n\t\tthis.resize(this.lockedWidth, this.lockedHeight);\n\t}\n\n\tif(this.displayed && this.iframe) {\n\n\t\t\t// this.contents.layout();\n\t\t\tthis.expand();\n\n\t}\n\n\n\n};\n\n// Resize a single axis based on content dimensions\nIframeView.prototype.expand = function(force) {\n\tvar width = this.lockedWidth;\n\tvar height = this.lockedHeight;\n\tvar columns;\n\n\tvar textWidth, textHeight;\n\n\tif(!this.iframe || this._expanding) return;\n\n\tthis._expanding = true;\n\n\t// Expand Horizontally\n\t// if(height && !width) {\n\tif(this.settings.axis === \"horizontal\") {\n\t\t// Get the width of the text\n\t\ttextWidth = this.contents.textWidth();\n\t\t// Check if the textWidth has changed\n\t\tif(textWidth != this._textWidth){\n\t\t\t// Get the contentWidth by resizing the iframe\n\t\t\t// Check with a min reset of the textWidth\n\t\t\twidth = this.contentWidth(textWidth);\n\n\t\t\tcolumns = Math.ceil(width / (this.settings.layout.columnWidth + this.settings.layout.gap));\n\n\t\t\tif ( this.settings.layout.divisor > 1 &&\n\t\t\t\t\t this.settings.layout.name === \"reflowable\" &&\n\t\t\t\t\t(columns % 2 > 0)) {\n\t\t\t\t\t// add a blank page\n\t\t\t\t\twidth += this.settings.layout.gap + this.settings.layout.columnWidth;\n\t\t\t}\n\n\t\t\t// Save the textWdith\n\t\t\tthis._textWidth = textWidth;\n\t\t\t// Save the contentWidth\n\t\t\tthis._contentWidth = width;\n\t\t} else {\n\t\t\t// Otherwise assume content height hasn't changed\n\t\t\twidth = this._contentWidth;\n\t\t}\n\t} // Expand Vertically\n\telse if(this.settings.axis === \"vertical\") {\n\t\ttextHeight = this.contents.textHeight();\n\t\tif(textHeight != this._textHeight){\n\t\t\theight = this.contentHeight(textHeight);\n\t\t\tthis._textHeight = textHeight;\n\t\t\tthis._contentHeight = height;\n\t\t} else {\n\t\t\theight = this._contentHeight;\n\t\t}\n\n\t}\n\n\t// Only Resize if dimensions have changed or\n\t// if Frame is still hidden, so needs reframing\n\tif(this._needsReframe || width != this._width || height != this._height){\n\t\tthis.resize(width, height);\n\t}\n\n\tthis._expanding = false;\n};\n\nIframeView.prototype.contentWidth = function(min) {\n\tvar prev;\n\tvar width;\n\n\t// Save previous width\n\tprev = this.iframe.style.width;\n\t// Set the iframe size to min, width will only ever be greater\n\t// Will preserve the aspect ratio\n\tthis.iframe.style.width = (min || 0) + \"px\";\n\t// Get the scroll overflow width\n\twidth = this.contents.scrollWidth();\n\t// Reset iframe size back\n\tthis.iframe.style.width = prev;\n\treturn width;\n};\n\nIframeView.prototype.contentHeight = function(min) {\n\tvar prev;\n\tvar height;\n\n\tprev = this.iframe.style.height;\n\tthis.iframe.style.height = (min || 0) + \"px\";\n\theight = this.contents.scrollHeight();\n\n\tthis.iframe.style.height = prev;\n\treturn height;\n};\n\n\nIframeView.prototype.resize = function(width, height) {\n\n\tif(!this.iframe) return;\n\n\tif(core.isNumber(width)){\n\t\tthis.iframe.style.width = width + \"px\";\n\t\tthis._width = width;\n\t}\n\n\tif(core.isNumber(height)){\n\t\tthis.iframe.style.height = height + \"px\";\n\t\tthis._height = height;\n\t}\n\n\tthis.iframeBounds = core.bounds(this.iframe);\n\n\tthis.reframe(this.iframeBounds.width, this.iframeBounds.height);\n\n};\n\nIframeView.prototype.reframe = function(width, height) {\n\tvar size;\n\n\t// if(!this.displayed) {\n\t// this._needsReframe = true;\n\t// return;\n\t// }\n\tif(core.isNumber(width)){\n\t\tthis.element.style.width = width + \"px\";\n\t}\n\n\tif(core.isNumber(height)){\n\t\tthis.element.style.height = height + \"px\";\n\t}\n\n\tthis.prevBounds = this.elementBounds;\n\n\tthis.elementBounds = core.bounds(this.element);\n\n\tsize = {\n\t\twidth: this.elementBounds.width,\n\t\theight: this.elementBounds.height,\n\t\twidthDelta: this.elementBounds.width - this.prevBounds.width,\n\t\theightDelta: this.elementBounds.height - this.prevBounds.height,\n\t};\n\n\tthis.onResize(this, size);\n\n\tthis.trigger(\"resized\", size);\n\n};\n\n\nIframeView.prototype.load = function(contents) {\n\tvar loading = new RSVP.defer();\n\tvar loaded = loading.promise;\n\n\tif(!this.iframe) {\n\t\tloading.reject(new Error(\"No Iframe Available\"));\n\t\treturn loaded;\n\t}\n\n\tthis.iframe.onload = function(event) {\n\n\t\tthis.onLoad(event, loading);\n\n\t}.bind(this);\n\n\tif(this.supportsSrcdoc){\n\t\tthis.iframe.srcdoc = contents;\n\t} else {\n\n\t\tthis.document = this.iframe.contentDocument;\n\n\t\tif(!this.document) {\n\t\t\tloading.reject(new Error(\"No Document Available\"));\n\t\t\treturn loaded;\n\t\t}\n\n\t\tthis.iframe.contentDocument.open();\n\t\tthis.iframe.contentDocument.write(contents);\n\t\tthis.iframe.contentDocument.close();\n\n\t}\n\n\treturn loaded;\n};\n\nIframeView.prototype.onLoad = function(event, promise) {\n\n\t\tthis.window = this.iframe.contentWindow;\n\t\tthis.document = this.iframe.contentDocument;\n\n\t\tthis.contents = new Contents(this.document, this.document.body, this.section.cfiBase);\n\n\t\tthis.rendering = false;\n\n\t\tvar link = this.document.querySelector(\"link[rel='canonical']\");\n\t\tif (link) {\n\t\t\tlink.setAttribute(\"href\", this.section.url);\n\t\t} else {\n\t\t\tlink = this.document.createElement(\"link\");\n\t\t\tlink.setAttribute(\"rel\", \"canonical\");\n\t\t\tlink.setAttribute(\"href\", this.section.url);\n\t\t\tthis.document.querySelector(\"head\").appendChild(link);\n\t\t}\n\n\t\tthis.contents.on(\"expand\", function () {\n\t\t\tif(this.displayed && this.iframe) {\n\t\t\t\t\tthis.expand();\n\t\t\t}\n\t\t});\n\n\t\tpromise.resolve(this.contents);\n};\n\n\n\n// IframeView.prototype.layout = function(layoutFunc) {\n//\n// this.iframe.style.display = \"inline-block\";\n//\n// // Reset Body Styles\n// // this.document.body.style.margin = \"0\";\n// //this.document.body.style.display = \"inline-block\";\n// //this.document.documentElement.style.width = \"auto\";\n//\n// if(layoutFunc){\n// this.layoutFunc = layoutFunc;\n// }\n//\n// this.contents.layout(this.layoutFunc);\n//\n// };\n//\n// IframeView.prototype.onLayout = function(view) {\n// // stub\n// };\n\nIframeView.prototype.setLayout = function(layout) {\n\tthis.layout = layout;\n};\n\nIframeView.prototype.setAxis = function(axis) {\n\tthis.settings.axis = axis;\n};\n\nIframeView.prototype.resizeListenters = function() {\n\t// Test size again\n\tclearTimeout(this.expanding);\n\tthis.expanding = setTimeout(this.expand.bind(this), 350);\n};\n\nIframeView.prototype.addListeners = function() {\n\t//TODO: Add content listeners for expanding\n};\n\nIframeView.prototype.removeListeners = function(layoutFunc) {\n\t//TODO: remove content listeners for expanding\n};\n\nIframeView.prototype.display = function(request) {\n\tvar displayed = new RSVP.defer();\n\n\tif (!this.displayed) {\n\n\t\tthis.render(request).then(function () {\n\n\t\t\tthis.trigger(\"displayed\", this);\n\t\t\tthis.onDisplayed(this);\n\n\t\t\tthis.displayed = true;\n\t\t\tdisplayed.resolve(this);\n\n\t\t}.bind(this));\n\n\t} else {\n\t\tdisplayed.resolve(this);\n\t}\n\n\n\treturn displayed.promise;\n};\n\nIframeView.prototype.show = function() {\n\n\tthis.element.style.visibility = \"visible\";\n\n\tif(this.iframe){\n\t\tthis.iframe.style.visibility = \"visible\";\n\t}\n\n\tthis.trigger(\"shown\", this);\n};\n\nIframeView.prototype.hide = function() {\n\t// this.iframe.style.display = \"none\";\n\tthis.element.style.visibility = \"hidden\";\n\tthis.iframe.style.visibility = \"hidden\";\n\n\tthis.stopExpanding = true;\n\tthis.trigger(\"hidden\", this);\n};\n\nIframeView.prototype.position = function() {\n\treturn this.element.getBoundingClientRect();\n};\n\nIframeView.prototype.locationOf = function(target) {\n\tvar parentPos = this.iframe.getBoundingClientRect();\n\tvar targetPos = this.contents.locationOf(target, this.settings.ignoreClass);\n\n\treturn {\n\t\t\"left\": window.scrollX + parentPos.left + targetPos.left,\n\t\t\"top\": window.scrollY + parentPos.top + targetPos.top\n\t};\n};\n\nIframeView.prototype.onDisplayed = function(view) {\n\t// Stub, override with a custom functions\n};\n\nIframeView.prototype.onResize = function(view, e) {\n\t// Stub, override with a custom functions\n};\n\nIframeView.prototype.bounds = function() {\n\tif(!this.elementBounds) {\n\t\tthis.elementBounds = core.bounds(this.element);\n\t}\n\treturn this.elementBounds;\n};\n\nIframeView.prototype.destroy = function() {\n\n\tif(this.displayed){\n\t\tthis.displayed = false;\n\n\t\tthis.removeListeners();\n\n\t\tthis.stopExpanding = true;\n\t\tthis.element.removeChild(this.iframe);\n\t\tthis.displayed = false;\n\t\tthis.iframe = null;\n\n\t\tthis._textWidth = null;\n\t\tthis._textHeight = null;\n\t\tthis._width = null;\n\t\tthis._height = null;\n\t}\n\t// this.element.style.height = \"0px\";\n\t// this.element.style.width = \"0px\";\n};\n\nRSVP.EventTarget.mixin(IframeView.prototype);\n\nmodule.exports = IframeView;\n","var Book = require('./book');\nvar EpubCFI = require('./epubcfi');\nvar Rendition = require('./rendition');\nvar Contents = require('./contents');\nvar RSVP = require('rsvp');\n\nfunction ePub(_url) {\n\treturn new Book(_url);\n};\n\nePub.VERSION = \"0.3.0\";\n\nePub.CFI = EpubCFI;\nePub.Rendition = Rendition;\nePub.Contents = Contents;\nePub.RSVP = RSVP;\n\nePub.ViewManagers = {};\nePub.Views = {};\nePub.register = {\n\tmanager : function(name, manager){\n\t\treturn ePub.ViewManagers[name] = manager;\n\t},\n\tview : function(name, view){\n\t\treturn ePub.Views[name] = view;\n\t}\n};\n\n// Default Views\nePub.register.view(\"iframe\", require('./views/iframe'));\n// ePub.register.view(\"inline\", require('./views/inline'));\n\n// Default View Managers\nePub.register.manager(\"single\", require('./managers/single'));\nePub.register.manager(\"continuous\", require('./managers/continuous'));\n\nmodule.exports = ePub;\n"]} \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 5006272..531dcc7 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -6,7 +6,7 @@ var uglify = require('gulp-uglify'); var gutil = require('gulp-util'); var plumber = require('gulp-plumber'); var onError = function (err) { - gutil.log(gutil.colors.green(err)); + gutil.log(gutil.colors.green(err)); }; var server = require("./tools/serve.js"); @@ -24,73 +24,73 @@ var mochify = require('mochify'); // Lint JS gulp.task('lint', function() { - return gulp.src('src/*.js') - .pipe(jshint()) - .pipe(jshint.reporter('default')); + return gulp.src('src/*.js') + .pipe(jshint()) + .pipe(jshint.reporter('default')); }); // set up the browserify instance on a task basis gulp.task('bundle', function () { - return bundle('epub.js'); + return bundle('epub.js'); }); // Minify JS gulp.task('minify', ['bundle'], function(){ - var uglifyOptions = { - mangle: true, - preserveComments : "license" - }; - return gulp.src('dist/epub.js') - .pipe(plumber({ errorHandler: onError })) - .pipe(rename('epub.min.js')) - // .pipe(sourcemaps.init({loadMaps: true})) - .pipe(uglify(uglifyOptions)) - // .pipe(sourcemaps.write('./')) - .pipe(size({ showFiles: true })) - .pipe(gulp.dest('dist')); + var uglifyOptions = { + mangle: true, + preserveComments : "license" + }; + return gulp.src('dist/epub.js') + .pipe(plumber({ errorHandler: onError })) + .pipe(rename('epub.min.js')) + // .pipe(sourcemaps.init({loadMaps: true})) + .pipe(uglify(uglifyOptions)) + // .pipe(sourcemaps.write('./')) + .pipe(size({ showFiles: true })) + .pipe(gulp.dest('dist')); }); // Watch Our Files gulp.task('watch', function(cb) { - bundle('epub.js', cb); + bundle('epub.js', cb); }); gulp.task('serve', function(cb) { - server(); - bundle('epub.js', cb); + server(); + bundle('epub.js', cb); }); gulp.task('serve:no-watch', function(cb) { - server(); + server(); }); gulp.task('test', function(cb) { - mochify('./test/*.js', { - reporter: 'spec', - transform: 'brfs', - "web-security": false, - "webSecurityEnabled": false, - // "localUrlAccess": true, - watch: true, - wd: false, - debug: false - }) - .bundle(); + mochify('./test/*.js', { + reporter: 'spec', + transform: 'brfs', + "web-security": false, + "webSecurityEnabled": false, + // "localUrlAccess": true, + watch: true, + wd: false, + debug: false + }) + .bundle(); }); gulp.task('test:once', function(cb) { - mochify('./test/*.js', { - reporter: 'spec', - transform: 'brfs', - "web-security": false, - "webSecurityEnabled": false, - // "localUrlAccess": true, - watch: false, - wd: false, - debug: false - }) - .bundle(); + mochify('./test/*.js', { + reporter: 'spec', + transform: 'brfs', + "web-security": false, + "webSecurityEnabled": false, + // "localUrlAccess": true, + watch: false, + wd: false, + debug: false + }) + .bundle(); }); // Default @@ -98,51 +98,51 @@ gulp.task('default', ['lint', 'bundle']); function bundle(file, watch) { - var opt = { - entries: ['src/'+file], - standalone: 'ePub', - debug : true - }; + var opt = { + entries: ['src/'+file], + standalone: 'ePub', + debug : true + }; - var b = browserify(opt); + var b = browserify(opt); - // Expose epub module for require - b.require('./src/'+file, {expose: 'epub'}); + // Expose epub module for require + b.require('./src/'+file, {expose: 'epub'}); - // Keep JSZip library seperate, - // must be loaded to use Unarchive or `require` will throw an error - b.external('jszip'); + // Keep JSZip library seperate, + // must be loaded to use Unarchive or `require` will throw an error + b.external('jszip'); - b.external('xmldom'); + b.external('xmldom'); - // Ignore optional URI libraries - var urijsPath = URI(require.resolve('urijs')); - ['./punycode.js', './IPv6.js'].forEach(function(lib) { - var libPath = URI(lib).absoluteTo(urijsPath).toString(); - b.ignore(libPath); - }); + // Ignore optional URI libraries + var urijsPath = URI(require.resolve('urijs')); + ['./punycode.js', './IPv6.js'].forEach(function(lib) { + var libPath = URI(lib).absoluteTo(urijsPath).toString(); + b.ignore(libPath); + }); - // watchify() if watch requested, otherwise run browserify() once - var bundler = watch ? watchify(b) : b; + // watchify() if watch requested, otherwise run browserify() once + var bundler = watch ? watchify(b) : b; - function rebundle() { - var stream = bundler.bundle(); - return stream - .on('error', gutil.log) - .pipe(source(file)) - .pipe(buffer()) - .pipe(sourcemaps.init({loadMaps: true})) - .pipe(sourcemaps.write('./')) - .pipe(size({ showFiles: true })) - .pipe(gulp.dest('./dist/')); - } + function rebundle() { + var stream = bundler.bundle(); + return stream + .on('error', gutil.log) + .pipe(source(file)) + .pipe(buffer()) + .pipe(sourcemaps.init({loadMaps: true})) + .pipe(sourcemaps.write('./')) + .pipe(size({ showFiles: true })) + .pipe(gulp.dest('./dist/')); + } - // listen for an update and run rebundle - bundler.on('update', function() { - rebundle(); - gutil.log('Rebundle...'); - }); + // listen for an update and run rebundle + bundler.on('update', function() { + rebundle(); + gutil.log('Rebundle...'); + }); - // run it once the first time buildScript is called - return rebundle(); + // run it once the first time buildScript is called + return rebundle(); } diff --git a/src/book.js b/src/book.js index c081424..1dfd0b4 100644 --- a/src/book.js +++ b/src/book.js @@ -12,264 +12,264 @@ var EpubCFI = require('./epubcfi'); function Book(_url, options){ - this.settings = core.extend(this.settings || {}, { + this.settings = core.extend(this.settings || {}, { requestMethod: this.requestMethod }); - core.extend(this.settings, options); + core.extend(this.settings, options); - // Promises - this.opening = new RSVP.defer(); - this.opened = this.opening.promise; - this.isOpen = false; + // Promises + this.opening = new RSVP.defer(); + this.opened = this.opening.promise; + this.isOpen = false; - this.url = undefined; + this.url = undefined; - this.loading = { - manifest: new RSVP.defer(), - spine: new RSVP.defer(), - metadata: new RSVP.defer(), - cover: new RSVP.defer(), - navigation: new RSVP.defer(), - pageList: new RSVP.defer() - }; + this.loading = { + manifest: new RSVP.defer(), + spine: new RSVP.defer(), + metadata: new RSVP.defer(), + cover: new RSVP.defer(), + navigation: new RSVP.defer(), + pageList: new RSVP.defer() + }; - this.loaded = { - manifest: this.loading.manifest.promise, - spine: this.loading.spine.promise, - metadata: this.loading.metadata.promise, - cover: this.loading.cover.promise, - navigation: this.loading.navigation.promise, - pageList: this.loading.pageList.promise - }; + this.loaded = { + manifest: this.loading.manifest.promise, + spine: this.loading.spine.promise, + metadata: this.loading.metadata.promise, + cover: this.loading.cover.promise, + navigation: this.loading.navigation.promise, + pageList: this.loading.pageList.promise + }; - this.ready = RSVP.hash(this.loaded); + this.ready = RSVP.hash(this.loaded); - // Queue for methods used before opening - this.isRendered = false; - // this._q = core.queue(this); + // Queue for methods used before opening + this.isRendered = false; + // this._q = core.queue(this); - this.request = this.settings.requestMethod.bind(this); + this.request = this.settings.requestMethod.bind(this); - this.spine = new Spine(this.request); - this.locations = new Locations(this.spine, this.request); + this.spine = new Spine(this.request); + this.locations = new Locations(this.spine, this.request); - if(_url) { - this.open(_url).catch(function (error) { - var err = new Error("Cannot load book at "+ _url ); - console.error(err); + if(_url) { + this.open(_url).catch(function (error) { + var err = new Error("Cannot load book at "+ _url ); + console.error(err); - this.trigger("loadFailed", error); - }.bind(this)); - } + this.trigger("loadFailed", error); + }.bind(this)); + } }; Book.prototype.open = function(_url, options){ - var uri; - var parse = new Parser(); - var epubPackage; - var epubContainer; - var book = this; - var containerPath = "META-INF/container.xml"; - var location; - var absoluteUri; - var isArrayBuffer = false; - var isBase64 = options && options.base64; + var uri; + var parse = new Parser(); + var epubPackage; + var epubContainer; + var book = this; + var containerPath = "META-INF/container.xml"; + var location; + var absoluteUri; + var isArrayBuffer = false; + var isBase64 = options && options.base64; - if(!_url) { - this.opening.resolve(this); - return this.opened; - } - - // Reuse parsed url or create a new uri object - // if(typeof(_url) === "object") { - // uri = _url; - // } else { - // uri = core.uri(_url); - // } - if (_url instanceof ArrayBuffer || isBase64) { - isArrayBuffer = true; - this.url = '/'; - } else { - uri = URI(_url); + if(!_url) { + this.opening.resolve(this); + return this.opened; } - if (window && window.location && uri) { - absoluteUri = uri.absoluteTo(window.location.href); - this.url = absoluteUri.toString(); - } else if (window && window.location) { - this.url = window.location.href; - } else { - this.url = _url; - } + // Reuse parsed url or create a new uri object + // if(typeof(_url) === "object") { + // uri = _url; + // } else { + // uri = core.uri(_url); + // } + if (_url instanceof ArrayBuffer || isBase64) { + isArrayBuffer = true; + this.url = '/'; + } else { + uri = URI(_url); + } - // Find path to the Container - if(uri && uri.suffix() === "opf") { - // Direct link to package, no container - this.packageUrl = _url; - this.containerUrl = ''; + if (window && window.location && uri) { + absoluteUri = uri.absoluteTo(window.location.href); + this.url = absoluteUri.toString(); + } else if (window && window.location) { + this.url = window.location.href; + } else { + this.url = _url; + } - if(uri.origin()) { - this.baseUrl = uri.origin() + "/" + uri.directory() + "/"; - } else if(absoluteUri){ - this.baseUrl = absoluteUri.origin(); - this.baseUrl += absoluteUri.directory() + "/"; - } else { - this.baseUrl = uri.directory() + "/"; - } + // Find path to the Container + if(uri && uri.suffix() === "opf") { + // Direct link to package, no container + this.packageUrl = _url; + this.containerUrl = ''; - epubPackage = this.request(this.packageUrl) - .catch(function(error) { - book.opening.reject(error); - }); + if(uri.origin()) { + this.baseUrl = uri.origin() + "/" + uri.directory() + "/"; + } else if(absoluteUri){ + this.baseUrl = absoluteUri.origin(); + this.baseUrl += absoluteUri.directory() + "/"; + } else { + this.baseUrl = uri.directory() + "/"; + } - } else if(isArrayBuffer || isBase64 || this.isArchivedUrl(uri)) { - // Book is archived - this.url = '/'; - this.containerUrl = URI(containerPath).absoluteTo(this.url).toString(); + epubPackage = this.request(this.packageUrl) + .catch(function(error) { + book.opening.reject(error); + }); - epubContainer = this.unarchive(_url, isBase64). - then(function() { - return this.request(this.containerUrl); - }.bind(this)) - .catch(function(error) { - book.opening.reject(error); - }); - } - // Find the path to the Package from the container - else if (!uri.suffix()) { + } else if(isArrayBuffer || isBase64 || this.isArchivedUrl(uri)) { + // Book is archived + this.url = '/'; + this.containerUrl = URI(containerPath).absoluteTo(this.url).toString(); - this.containerUrl = this.url + containerPath; + epubContainer = this.unarchive(_url, isBase64). + then(function() { + return this.request(this.containerUrl); + }.bind(this)) + .catch(function(error) { + book.opening.reject(error); + }); + } + // Find the path to the Package from the container + else if (!uri.suffix()) { - epubContainer = this.request(this.containerUrl) - .catch(function(error) { - // handle errors in loading container - book.opening.reject(error); - }); - } + this.containerUrl = this.url + containerPath; - if (epubContainer) { - epubPackage = epubContainer. - then(function(containerXml){ - return parse.container(containerXml); // Container has path to content - }). - then(function(paths){ - var packageUri = URI(paths.packagePath); - var absPackageUri = packageUri.absoluteTo(book.url); - var absWindowUri; + epubContainer = this.request(this.containerUrl) + .catch(function(error) { + // handle errors in loading container + book.opening.reject(error); + }); + } - book.packageUrl = absPackageUri.toString(); - book.encoding = paths.encoding; + if (epubContainer) { + epubPackage = epubContainer. + then(function(containerXml){ + return parse.container(containerXml); // Container has path to content + }). + then(function(paths){ + var packageUri = URI(paths.packagePath); + var absPackageUri = packageUri.absoluteTo(book.url); + var absWindowUri; - // Set Url relative to the content - if(absPackageUri.origin()) { - book.baseUrl = absPackageUri.origin() + absPackageUri.directory() + "/"; - } else { - if(packageUri.directory()) { - book.baseUrl = "/" + packageUri.directory() + "/"; - } else { - book.baseUrl = "/" - } - } + book.packageUrl = absPackageUri.toString(); + book.encoding = paths.encoding; - return book.request(book.packageUrl); - }).catch(function(error) { - // handle errors in either of the two requests - book.opening.reject(error); - }); - } + // Set Url relative to the content + if(absPackageUri.origin()) { + book.baseUrl = absPackageUri.origin() + absPackageUri.directory() + "/"; + } else { + if(packageUri.directory()) { + book.baseUrl = "/" + packageUri.directory() + "/"; + } else { + book.baseUrl = "/" + } + } - epubPackage.then(function(packageXml) { + return book.request(book.packageUrl); + }).catch(function(error) { + // handle errors in either of the two requests + book.opening.reject(error); + }); + } - if (!packageXml) { - return; - } + epubPackage.then(function(packageXml) { - // Get package information from epub opf - book.unpack(packageXml); + if (!packageXml) { + return; + } - // Resolve promises - book.loading.manifest.resolve(book.package.manifest); - book.loading.metadata.resolve(book.package.metadata); - book.loading.spine.resolve(book.spine); - book.loading.cover.resolve(book.cover); + // Get package information from epub opf + book.unpack(packageXml); - book.isOpen = true; + // Resolve promises + book.loading.manifest.resolve(book.package.manifest); + book.loading.metadata.resolve(book.package.metadata); + book.loading.spine.resolve(book.spine); + book.loading.cover.resolve(book.cover); - // Clear queue of any waiting book request + book.isOpen = true; - // Resolve book opened promise - book.opening.resolve(book); + // Clear queue of any waiting book request - }).catch(function(error) { - // handle errors in parsing the book - // console.error(error.message, error.stack); - book.opening.reject(error); - }); + // Resolve book opened promise + book.opening.resolve(book); - return this.opened; + }).catch(function(error) { + // handle errors in parsing the book + // console.error(error.message, error.stack); + book.opening.reject(error); + }); + + return this.opened; }; Book.prototype.unpack = function(packageXml){ - var book = this, - parse = new Parser(); + var book = this, + parse = new Parser(); - book.package = parse.packageContents(packageXml); // Extract info from contents - if(!book.package) { - return; - } + book.package = parse.packageContents(packageXml); // Extract info from contents + if(!book.package) { + return; + } - book.package.baseUrl = book.baseUrl; // Provides a url base for resolving paths + book.package.baseUrl = book.baseUrl; // Provides a url base for resolving paths - this.spine.load(book.package); + this.spine.load(book.package); - book.navigation = new Navigation(book.package, this.request); - book.navigation.load().then(function(toc){ - book.toc = toc; - book.loading.navigation.resolve(book.toc); - }); + book.navigation = new Navigation(book.package, this.request); + book.navigation.load().then(function(toc){ + book.toc = toc; + book.loading.navigation.resolve(book.toc); + }); - // //-- Set Global Layout setting based on metadata - // MOVE TO RENDER - // book.globalLayoutProperties = book.parseLayoutProperties(book.package.metadata); + // //-- Set Global Layout setting based on metadata + // MOVE TO RENDER + // book.globalLayoutProperties = book.parseLayoutProperties(book.package.metadata); - book.cover = URI(book.package.coverPath).absoluteTo(book.baseUrl).toString(); + book.cover = URI(book.package.coverPath).absoluteTo(book.baseUrl).toString(); }; // Alias for book.spine.get Book.prototype.section = function(target) { - return this.spine.get(target); + return this.spine.get(target); }; // Sugar to render a book Book.prototype.renderTo = function(element, options) { - // var renderMethod = (options && options.method) ? - // options.method : - // "single"; + // var renderMethod = (options && options.method) ? + // options.method : + // "single"; - this.rendition = new Rendition(this, options); - this.rendition.attachTo(element); + this.rendition = new Rendition(this, options); + this.rendition.attachTo(element); - return this.rendition; + return this.rendition; }; Book.prototype.requestMethod = function(_url) { - // Switch request methods - if(this.unarchived) { - return this.unarchived.request(_url); - } else { - return request(_url, null, this.requestCredentials, this.requestHeaders); - } + // Switch request methods + if(this.unarchived) { + return this.unarchived.request(_url); + } else { + return request(_url, null, this.requestCredentials, this.requestHeaders); + } }; Book.prototype.setRequestCredentials = function(_credentials) { - this.requestCredentials = _credentials; + this.requestCredentials = _credentials; }; Book.prototype.setRequestHeaders = function(_headers) { - this.requestHeaders = _headers; + this.requestHeaders = _headers; }; Book.prototype.unarchive = function(bookUrl, isBase64){ @@ -279,21 +279,21 @@ Book.prototype.unarchive = function(bookUrl, isBase64){ //-- Checks if url has a .epub or .zip extension, or is ArrayBuffer (of zip/epub) Book.prototype.isArchivedUrl = function(bookUrl){ - var uri; - var extension; + var uri; + var extension; - if (bookUrl instanceof ArrayBuffer) { + if (bookUrl instanceof ArrayBuffer) { return true; } - // Reuse parsed url or create a new uri object - // if(typeof(bookUrl) === "object") { - // uri = bookUrl; - // } else { - // uri = core.uri(bookUrl); - // } - uri = URI(bookUrl); - extension = uri.suffix(); + // Reuse parsed url or create a new uri object + // if(typeof(bookUrl) === "object") { + // uri = bookUrl; + // } else { + // uri = core.uri(bookUrl); + // } + uri = URI(bookUrl); + extension = uri.suffix(); if(extension && (extension == "epub" || extension == "zip")){ return true; @@ -319,13 +319,13 @@ Book.prototype.coverUrl = function(){ }; Book.prototype.range = function(cfiRange) { - var cfi = new EpubCFI(cfiRange); - var item = this.spine.get(cfi.spinePos); + var cfi = new EpubCFI(cfiRange); + var item = this.spine.get(cfi.spinePos); - return item.load().then(function (contents) { - var range = cfi.toRange(item.document); - return range; - }) + return item.load().then(function (contents) { + var range = cfi.toRange(item.document); + return range; + }) }; module.exports = Book; @@ -335,7 +335,7 @@ RSVP.EventTarget.mixin(Book.prototype); //-- Handle RSVP Errors RSVP.on('error', function(event) { - console.error(event); + console.error(event); }); RSVP.configure('instrument', false); //-- true | will logging out all RSVP rejections @@ -343,5 +343,5 @@ RSVP.configure('instrument', false); //-- true | will logging out all RSVP rejec // RSVP.on('chained', listener); // RSVP.on('fulfilled', listener); RSVP.on('rejected', function(event){ - console.error(event.detail.message, event.detail.stack); + console.error(event.detail.message, event.detail.stack); }); diff --git a/src/contents.js b/src/contents.js index 2689cbf..5447221 100644 --- a/src/contents.js +++ b/src/contents.js @@ -5,221 +5,221 @@ var Mapping = require('./mapping'); function Contents(doc, content, cfiBase) { - // Blank Cfi for Parsing - this.epubcfi = new EpubCFI(); + // Blank Cfi for Parsing + this.epubcfi = new EpubCFI(); - this.document = doc; - this.documentElement = this.document.documentElement; - this.content = content || this.document.body; - this.window = this.document.defaultView; - // Dom events to listen for - this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"]; + this.document = doc; + this.documentElement = this.document.documentElement; + this.content = content || this.document.body; + this.window = this.document.defaultView; + // Dom events to listen for + this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"]; - this._size = { - width: 0, - height: 0 - } + this._size = { + width: 0, + height: 0 + } - this.cfiBase = cfiBase || ""; + this.cfiBase = cfiBase || ""; - this.listeners(); + this.listeners(); }; Contents.prototype.width = function(w) { - // var frame = this.documentElement; - var frame = this.content; + // var frame = this.documentElement; + var frame = this.content; - if (w && core.isNumber(w)) { - w = w + "px"; - } + if (w && core.isNumber(w)) { + w = w + "px"; + } - if (w) { - frame.style.width = w; - // this.content.style.width = w; - } + if (w) { + frame.style.width = w; + // this.content.style.width = w; + } - return this.window.getComputedStyle(frame)['width']; + return this.window.getComputedStyle(frame)['width']; }; Contents.prototype.height = function(h) { - // var frame = this.documentElement; - var frame = this.content; + // var frame = this.documentElement; + var frame = this.content; - if (h && core.isNumber(h)) { - h = h + "px"; - } + if (h && core.isNumber(h)) { + h = h + "px"; + } - if (h) { - frame.style.height = h; - // this.content.style.height = h; - } + if (h) { + frame.style.height = h; + // this.content.style.height = h; + } - return this.window.getComputedStyle(frame)['height']; + return this.window.getComputedStyle(frame)['height']; }; Contents.prototype.contentWidth = function(w) { - var content = this.content || this.document.body; + var content = this.content || this.document.body; - if (w && core.isNumber(w)) { - w = w + "px"; - } + if (w && core.isNumber(w)) { + w = w + "px"; + } - if (w) { - content.style.width = w; - } + if (w) { + content.style.width = w; + } - return this.window.getComputedStyle(content)['width']; + return this.window.getComputedStyle(content)['width']; }; Contents.prototype.contentHeight = function(h) { - var content = this.content || this.document.body; + var content = this.content || this.document.body; - if (h && core.isNumber(h)) { - h = h + "px"; - } + if (h && core.isNumber(h)) { + h = h + "px"; + } - if (h) { - content.style.height = h; - } + if (h) { + content.style.height = h; + } - return this.window.getComputedStyle(content)['height']; + return this.window.getComputedStyle(content)['height']; }; Contents.prototype.textWidth = function() { - var width; - var range = this.document.createRange(); - var content = this.content || this.document.body; + var width; + var range = this.document.createRange(); + var content = this.content || this.document.body; - // Select the contents of frame - range.selectNodeContents(content); + // Select the contents of frame + range.selectNodeContents(content); - // get the width of the text content - width = range.getBoundingClientRect().width; + // get the width of the text content + width = range.getBoundingClientRect().width; - return width; + return width; }; Contents.prototype.textHeight = function() { - var height; - var range = this.document.createRange(); - var content = this.content || this.document.body; + var height; + var range = this.document.createRange(); + var content = this.content || this.document.body; - range.selectNodeContents(content); + range.selectNodeContents(content); - height = range.getBoundingClientRect().height; + height = range.getBoundingClientRect().height; - return height; + return height; }; Contents.prototype.scrollWidth = function() { - var width = this.documentElement.scrollWidth; + var width = this.documentElement.scrollWidth; - return width; + return width; }; Contents.prototype.scrollHeight = function() { - var height = this.documentElement.scrollHeight; + var height = this.documentElement.scrollHeight; - return height; + return height; }; Contents.prototype.overflow = function(overflow) { - if (overflow) { - this.documentElement.style.overflow = overflow; - } + if (overflow) { + this.documentElement.style.overflow = overflow; + } - return this.window.getComputedStyle(this.documentElement)['overflow']; + return this.window.getComputedStyle(this.documentElement)['overflow']; }; Contents.prototype.overflowX = function(overflow) { - if (overflow) { - this.documentElement.style.overflowX = overflow; - } + if (overflow) { + this.documentElement.style.overflowX = overflow; + } - return this.window.getComputedStyle(this.documentElement)['overflowX']; + return this.window.getComputedStyle(this.documentElement)['overflowX']; }; Contents.prototype.overflowY = function(overflow) { - if (overflow) { - this.documentElement.style.overflowY = overflow; - } + if (overflow) { + this.documentElement.style.overflowY = overflow; + } - return this.window.getComputedStyle(this.documentElement)['overflowY']; + return this.window.getComputedStyle(this.documentElement)['overflowY']; }; Contents.prototype.css = function(property, value) { - var content = this.content || this.document.body; + var content = this.content || this.document.body; - if (value) { - content.style[property] = value; - } + if (value) { + content.style[property] = value; + } - return this.window.getComputedStyle(content)[property]; + return this.window.getComputedStyle(content)[property]; }; Contents.prototype.viewport = function(options) { - var width, height, scale, scalable; - var $viewport = this.document.querySelector("meta[name='viewport']"); - var newContent = ''; + var width, height, scale, scalable; + var $viewport = this.document.querySelector("meta[name='viewport']"); + var newContent = ''; - /** - * check for the viewport size - * - */ - if($viewport && $viewport.hasAttribute("content")) { - content = $viewport.getAttribute("content"); - contents = content.split(/\s*,\s*/); - if(contents[0]){ - width = contents[0].replace("width=", '').trim(); - } - if(contents[1]){ - height = contents[1].replace("height=", '').trim(); - } - if(contents[2]){ - scale = contents[2].replace("initial-scale=", '').trim(); - } - if(contents[3]){ - scalable = contents[3].replace("user-scalable=", '').trim(); - } - } + /** + * check for the viewport size + * + */ + if($viewport && $viewport.hasAttribute("content")) { + content = $viewport.getAttribute("content"); + contents = content.split(/\s*,\s*/); + if(contents[0]){ + width = contents[0].replace("width=", '').trim(); + } + if(contents[1]){ + height = contents[1].replace("height=", '').trim(); + } + if(contents[2]){ + scale = contents[2].replace("initial-scale=", '').trim(); + } + if(contents[3]){ + scalable = contents[3].replace("user-scalable=", '').trim(); + } + } - if (options) { + if (options) { - newContent += "width=" + (options.width || width); - newContent += ", height=" + (options.height || height); - if (options.scale || scale) { - newContent += ", initial-scale=" + (options.scale || scale); - } - if (options.scalable || scalable) { - newContent += ", user-scalable=" + (options.scalable || scalable); - } + newContent += "width=" + (options.width || width); + newContent += ", height=" + (options.height || height); + if (options.scale || scale) { + newContent += ", initial-scale=" + (options.scale || scale); + } + if (options.scalable || scalable) { + newContent += ", user-scalable=" + (options.scalable || scalable); + } - if (!$viewport) { - $viewport = this.document.createElement("meta"); - $viewport.setAttribute("name", "viewport"); - this.document.querySelector('head').appendChild($viewport); - } + if (!$viewport) { + $viewport = this.document.createElement("meta"); + $viewport.setAttribute("name", "viewport"); + this.document.querySelector('head').appendChild($viewport); + } - $viewport.setAttribute("content", newContent); - } + $viewport.setAttribute("content", newContent); + } - return { - width: parseInt(width), - height: parseInt(height) - }; + return { + width: parseInt(width), + height: parseInt(height) + }; }; @@ -245,417 +245,417 @@ Contents.prototype.viewport = function(options) { // }; Contents.prototype.expand = function() { - this.trigger("expand"); + this.trigger("expand"); }; Contents.prototype.listeners = function() { - this.imageLoadListeners(); + this.imageLoadListeners(); - this.mediaQueryListeners(); + this.mediaQueryListeners(); - // this.fontLoadListeners(); + // this.fontLoadListeners(); - this.addEventListeners(); + this.addEventListeners(); - this.addSelectionListeners(); + this.addSelectionListeners(); - this.resizeListeners(); + this.resizeListeners(); }; Contents.prototype.removeListeners = function() { - this.removeEventListeners(); + this.removeEventListeners(); - this.removeSelectionListeners(); + this.removeSelectionListeners(); }; Contents.prototype.resizeListeners = function() { - var width, height; - // Test size again - clearTimeout(this.expanding); + var width, height; + // Test size again + clearTimeout(this.expanding); - width = this.scrollWidth(); - height = this.scrollHeight(); + width = this.scrollWidth(); + height = this.scrollHeight(); - if (width != this._size.width || height != this._size.height) { + if (width != this._size.width || height != this._size.height) { - this._size = { - width: width, - height: height - } + this._size = { + width: width, + height: height + } - this.trigger("resize", this._size); - } + this.trigger("resize", this._size); + } - this.expanding = setTimeout(this.resizeListeners.bind(this), 350); + this.expanding = setTimeout(this.resizeListeners.bind(this), 350); }; //https://github.com/tylergaw/media-query-events/blob/master/js/mq-events.js Contents.prototype.mediaQueryListeners = function() { - var sheets = this.document.styleSheets; - var mediaChangeHandler = function(m){ - if(m.matches && !this._expanding) { - setTimeout(this.expand.bind(this), 1); - // this.expand(); - } - }.bind(this); + var sheets = this.document.styleSheets; + var mediaChangeHandler = function(m){ + if(m.matches && !this._expanding) { + setTimeout(this.expand.bind(this), 1); + // this.expand(); + } + }.bind(this); - for (var i = 0; i < sheets.length; i += 1) { - var rules = sheets[i].cssRules; - if(!rules) return; // Stylesheets changed - for (var j = 0; j < rules.length; j += 1) { - //if (rules[j].constructor === CSSMediaRule) { - if(rules[j].media){ - var mql = this.window.matchMedia(rules[j].media.mediaText); - mql.addListener(mediaChangeHandler); - //mql.onchange = mediaChangeHandler; - } - } - } + for (var i = 0; i < sheets.length; i += 1) { + var rules = sheets[i].cssRules; + if(!rules) return; // Stylesheets changed + for (var j = 0; j < rules.length; j += 1) { + //if (rules[j].constructor === CSSMediaRule) { + if(rules[j].media){ + var mql = this.window.matchMedia(rules[j].media.mediaText); + mql.addListener(mediaChangeHandler); + //mql.onchange = mediaChangeHandler; + } + } + } }; Contents.prototype.observe = function(target) { - var renderer = this; + var renderer = this; - // create an observer instance - var observer = new MutationObserver(function(mutations) { - if(renderer._expanding) { - renderer.expand(); - } - // mutations.forEach(function(mutation) { - // console.log(mutation); - // }); - }); + // create an observer instance + var observer = new MutationObserver(function(mutations) { + if(renderer._expanding) { + renderer.expand(); + } + // mutations.forEach(function(mutation) { + // console.log(mutation); + // }); + }); - // configuration of the observer: - var config = { attributes: true, childList: true, characterData: true, subtree: true }; + // configuration of the observer: + var config = { attributes: true, childList: true, characterData: true, subtree: true }; - // pass in the target node, as well as the observer options - observer.observe(target, config); + // pass in the target node, as well as the observer options + observer.observe(target, config); - return observer; + return observer; }; Contents.prototype.imageLoadListeners = function(target) { - var images = this.document.querySelectorAll("img"); - var img; - for (var i = 0; i < images.length; i++) { - img = images[i]; + var images = this.document.querySelectorAll("img"); + var img; + for (var i = 0; i < images.length; i++) { + img = images[i]; - if (typeof img.naturalWidth !== "undefined" && - img.naturalWidth === 0) { - img.onload = this.expand.bind(this); - } - } + if (typeof img.naturalWidth !== "undefined" && + img.naturalWidth === 0) { + img.onload = this.expand.bind(this); + } + } }; Contents.prototype.fontLoadListeners = function(target) { - if (!this.document || !this.document.fonts) { - return; - } + if (!this.document || !this.document.fonts) { + return; + } - this.document.fonts.ready.then(function () { - this.expand(); - }.bind(this)); + this.document.fonts.ready.then(function () { + this.expand(); + }.bind(this)); }; Contents.prototype.root = function() { - if(!this.document) return null; - return this.document.documentElement; + if(!this.document) return null; + return this.document.documentElement; }; Contents.prototype.locationOf = function(target, ignoreClass) { - var position; - var targetPos = {"left": 0, "top": 0}; + var position; + var targetPos = {"left": 0, "top": 0}; - if(!this.document) return; + if(!this.document) return; - if(this.epubcfi.isCfiString(target)) { - range = new EpubCFI(target).toRange(this.document, ignoreClass); + if(this.epubcfi.isCfiString(target)) { + range = new EpubCFI(target).toRange(this.document, ignoreClass); - if(range) { - if (range.startContainer.nodeType === Node.ELEMENT_NODE) { - position = range.startContainer.getBoundingClientRect(); - targetPos.left = position.left; - targetPos.top = position.top; - } else { - position = range.getBoundingClientRect(); - targetPos.left = position.left; - targetPos.top = position.top; - } - } + if(range) { + if (range.startContainer.nodeType === Node.ELEMENT_NODE) { + position = range.startContainer.getBoundingClientRect(); + targetPos.left = position.left; + targetPos.top = position.top; + } else { + position = range.getBoundingClientRect(); + targetPos.left = position.left; + targetPos.top = position.top; + } + } - } else if(typeof target === "string" && - target.indexOf("#") > -1) { + } else if(typeof target === "string" && + target.indexOf("#") > -1) { - id = target.substring(target.indexOf("#")+1); - el = this.document.getElementById(id); + id = target.substring(target.indexOf("#")+1); + el = this.document.getElementById(id); - if(el) { - position = el.getBoundingClientRect(); - targetPos.left = position.left; - targetPos.top = position.top; - } - } + if(el) { + position = el.getBoundingClientRect(); + targetPos.left = position.left; + targetPos.top = position.top; + } + } - return targetPos; + return targetPos; }; Contents.prototype.addStylesheet = function(src) { - return new RSVP.Promise(function(resolve, reject){ - var $stylesheet; - var ready = false; + return new RSVP.Promise(function(resolve, reject){ + var $stylesheet; + var ready = false; - if(!this.document) { - resolve(false); - return; - } + if(!this.document) { + resolve(false); + return; + } - $stylesheet = this.document.createElement('link'); - $stylesheet.type = 'text/css'; - $stylesheet.rel = "stylesheet"; - $stylesheet.href = src; - $stylesheet.onload = $stylesheet.onreadystatechange = function() { - if ( !ready && (!this.readyState || this.readyState == 'complete') ) { - ready = true; - // Let apply - setTimeout(function(){ - resolve(true); - }, 1); - } - }; + $stylesheet = this.document.createElement('link'); + $stylesheet.type = 'text/css'; + $stylesheet.rel = "stylesheet"; + $stylesheet.href = src; + $stylesheet.onload = $stylesheet.onreadystatechange = function() { + if ( !ready && (!this.readyState || this.readyState == 'complete') ) { + ready = true; + // Let apply + setTimeout(function(){ + resolve(true); + }, 1); + } + }; - this.document.head.appendChild($stylesheet); + this.document.head.appendChild($stylesheet); - }.bind(this)); + }.bind(this)); }; // https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule Contents.prototype.addStylesheetRules = function(rules) { - var styleEl; - var styleSheet; + var styleEl; + var styleSheet; - if(!this.document) return; + if(!this.document) return; - styleEl = this.document.createElement('style'); + styleEl = this.document.createElement('style'); - // Append style element to head - this.document.head.appendChild(styleEl); + // Append style element to head + this.document.head.appendChild(styleEl); - // Grab style sheet - styleSheet = styleEl.sheet; + // Grab style sheet + styleSheet = styleEl.sheet; - for (var i = 0, rl = rules.length; i < rl; i++) { - var j = 1, rule = rules[i], selector = rules[i][0], propStr = ''; - // If the second argument of a rule is an array of arrays, correct our variables. - if (Object.prototype.toString.call(rule[1][0]) === '[object Array]') { - rule = rule[1]; - j = 0; - } + for (var i = 0, rl = rules.length; i < rl; i++) { + var j = 1, rule = rules[i], selector = rules[i][0], propStr = ''; + // If the second argument of a rule is an array of arrays, correct our variables. + if (Object.prototype.toString.call(rule[1][0]) === '[object Array]') { + rule = rule[1]; + j = 0; + } - for (var pl = rule.length; j < pl; j++) { - var prop = rule[j]; - propStr += prop[0] + ':' + prop[1] + (prop[2] ? ' !important' : '') + ';\n'; - } + for (var pl = rule.length; j < pl; j++) { + var prop = rule[j]; + propStr += prop[0] + ':' + prop[1] + (prop[2] ? ' !important' : '') + ';\n'; + } - // Insert CSS Rule - styleSheet.insertRule(selector + '{' + propStr + '}', styleSheet.cssRules.length); - } + // Insert CSS Rule + styleSheet.insertRule(selector + '{' + propStr + '}', styleSheet.cssRules.length); + } }; Contents.prototype.addScript = function(src) { - return new RSVP.Promise(function(resolve, reject){ - var $script; - var ready = false; + return new RSVP.Promise(function(resolve, reject){ + var $script; + var ready = false; - if(!this.document) { - resolve(false); - return; - } + if(!this.document) { + resolve(false); + return; + } - $script = this.document.createElement('script'); - $script.type = 'text/javascript'; - $script.async = true; - $script.src = src; - $script.onload = $script.onreadystatechange = function() { - if ( !ready && (!this.readyState || this.readyState == 'complete') ) { - ready = true; - setTimeout(function(){ - resolve(true); - }, 1); - } - }; + $script = this.document.createElement('script'); + $script.type = 'text/javascript'; + $script.async = true; + $script.src = src; + $script.onload = $script.onreadystatechange = function() { + if ( !ready && (!this.readyState || this.readyState == 'complete') ) { + ready = true; + setTimeout(function(){ + resolve(true); + }, 1); + } + }; - this.document.head.appendChild($script); + this.document.head.appendChild($script); - }.bind(this)); + }.bind(this)); }; Contents.prototype.addEventListeners = function(){ - if(!this.document) { - return; - } - this.listenedEvents.forEach(function(eventName){ - this.document.addEventListener(eventName, this.triggerEvent.bind(this), false); - }, this); + if(!this.document) { + return; + } + this.listenedEvents.forEach(function(eventName){ + this.document.addEventListener(eventName, this.triggerEvent.bind(this), false); + }, this); }; Contents.prototype.removeEventListeners = function(){ - if(!this.document) { - return; - } - this.listenedEvents.forEach(function(eventName){ - this.document.removeEventListener(eventName, this.triggerEvent, false); - }, this); + if(!this.document) { + return; + } + this.listenedEvents.forEach(function(eventName){ + this.document.removeEventListener(eventName, this.triggerEvent, false); + }, this); }; // Pass browser events Contents.prototype.triggerEvent = function(e){ - this.trigger(e.type, e); + this.trigger(e.type, e); }; Contents.prototype.addSelectionListeners = function(){ - if(!this.document) { - return; - } - this.document.addEventListener("selectionchange", this.onSelectionChange.bind(this), false); + if(!this.document) { + return; + } + this.document.addEventListener("selectionchange", this.onSelectionChange.bind(this), false); }; Contents.prototype.removeSelectionListeners = function(){ - if(!this.document) { - return; - } - this.document.removeEventListener("selectionchange", this.onSelectionChange, false); + if(!this.document) { + return; + } + this.document.removeEventListener("selectionchange", this.onSelectionChange, false); }; Contents.prototype.onSelectionChange = function(e){ - if (this.selectionEndTimeout) { - clearTimeout(this.selectionEndTimeout); - } - this.selectionEndTimeout = setTimeout(function() { - var selection = this.window.getSelection(); - this.triggerSelectedEvent(selection); - }.bind(this), 500); + if (this.selectionEndTimeout) { + clearTimeout(this.selectionEndTimeout); + } + this.selectionEndTimeout = setTimeout(function() { + var selection = this.window.getSelection(); + this.triggerSelectedEvent(selection); + }.bind(this), 500); }; Contents.prototype.triggerSelectedEvent = function(selection){ var range, cfirange; - if (selection && selection.rangeCount > 0) { - range = selection.getRangeAt(0); - if(!range.collapsed) { - // cfirange = this.section.cfiFromRange(range); - cfirange = new EpubCFI(range, this.cfiBase).toString(); - this.trigger("selected", cfirange); - this.trigger("selectedRange", range); - } - } + if (selection && selection.rangeCount > 0) { + range = selection.getRangeAt(0); + if(!range.collapsed) { + // cfirange = this.section.cfiFromRange(range); + cfirange = new EpubCFI(range, this.cfiBase).toString(); + this.trigger("selected", cfirange); + this.trigger("selectedRange", range); + } + } }; Contents.prototype.range = function(_cfi, ignoreClass){ - var cfi = new EpubCFI(_cfi); - return cfi.toRange(this.document, ignoreClass); + var cfi = new EpubCFI(_cfi); + return cfi.toRange(this.document, ignoreClass); }; Contents.prototype.map = function(layout){ - var map = new Mapping(layout); - return map.section(); + var map = new Mapping(layout); + return map.section(); }; Contents.prototype.size = function(width, height){ - if (width >= 0) { - this.width(width); - } + if (width >= 0) { + this.width(width); + } - if (height >= 0) { - this.height(height); - } + if (height >= 0) { + this.height(height); + } - this.css("margin", "0"); - this.css("boxSizing", "border-box"); + this.css("margin", "0"); + this.css("boxSizing", "border-box"); }; Contents.prototype.columns = function(width, height, columnWidth, gap){ - var COLUMN_AXIS = core.prefixed('columnAxis'); - var COLUMN_GAP = core.prefixed('columnGap'); - var COLUMN_WIDTH = core.prefixed('columnWidth'); - var COLUMN_FILL = core.prefixed('columnFill'); - var textWidth; + var COLUMN_AXIS = core.prefixed('columnAxis'); + var COLUMN_GAP = core.prefixed('columnGap'); + var COLUMN_WIDTH = core.prefixed('columnWidth'); + var COLUMN_FILL = core.prefixed('columnFill'); + var textWidth; - this.width(width); - this.height(height); + this.width(width); + this.height(height); - // Deal with Mobile trying to scale to viewport - this.viewport({ width: width, height: height, scale: 1.0 }); + // Deal with Mobile trying to scale to viewport + this.viewport({ width: width, height: height, scale: 1.0 }); - // this.overflowY("hidden"); - this.css("overflowY", "hidden"); - this.css("margin", "0"); - this.css("boxSizing", "border-box"); - this.css("maxWidth", "inherit"); + // this.overflowY("hidden"); + this.css("overflowY", "hidden"); + this.css("margin", "0"); + this.css("boxSizing", "border-box"); + this.css("maxWidth", "inherit"); - this.css(COLUMN_AXIS, "horizontal"); - this.css(COLUMN_FILL, "auto"); + this.css(COLUMN_AXIS, "horizontal"); + this.css(COLUMN_FILL, "auto"); - this.css(COLUMN_GAP, gap+"px"); - this.css(COLUMN_WIDTH, columnWidth+"px"); + this.css(COLUMN_GAP, gap+"px"); + this.css(COLUMN_WIDTH, columnWidth+"px"); }; Contents.prototype.scale = function(scale, offsetX, offsetY){ - var scale = "scale(" + scale + ")"; - var translate = ''; - // this.css("position", "absolute")); - this.css("transformOrigin", "top left"); + var scale = "scale(" + scale + ")"; + var translate = ''; + // this.css("position", "absolute")); + this.css("transformOrigin", "top left"); - if (offsetX >= 0 || offsetY >= 0) { - translate = " translate(" + (offsetX || 0 )+ "px, " + (offsetY || 0 )+ "px )"; - } + if (offsetX >= 0 || offsetY >= 0) { + translate = " translate(" + (offsetX || 0 )+ "px, " + (offsetY || 0 )+ "px )"; + } - this.css("transform", scale + translate); + this.css("transform", scale + translate); }; Contents.prototype.fit = function(width, height){ - var viewport = this.viewport(); - var widthScale = width / viewport.width; - var heightScale = height / viewport.height; - var scale = widthScale < heightScale ? widthScale : heightScale; + var viewport = this.viewport(); + var widthScale = width / viewport.width; + var heightScale = height / viewport.height; + var scale = widthScale < heightScale ? widthScale : heightScale; - var offsetY = (height - (viewport.height * scale)) / 2; + var offsetY = (height - (viewport.height * scale)) / 2; - this.width(width); - this.height(height); - this.overflow("hidden"); + this.width(width); + this.height(height); + this.overflow("hidden"); - // Deal with Mobile trying to scale to viewport - this.viewport({ scale: 1.0 }); + // Deal with Mobile trying to scale to viewport + this.viewport({ scale: 1.0 }); - // Scale to the correct size - this.scale(scale, 0, offsetY); + // Scale to the correct size + this.scale(scale, 0, offsetY); - this.css("backgroundColor", "transparent"); + this.css("backgroundColor", "transparent"); }; Contents.prototype.mapPage = function(cfiBase, start, end) { - var mapping = new Mapping(); + var mapping = new Mapping(); - return mapping.page(this, cfiBase, start, end); + return mapping.page(this, cfiBase, start, end); }; Contents.prototype.destroy = function() { - // Stop observing - if(this.observer) { - this.observer.disconnect(); - } + // Stop observing + if(this.observer) { + this.observer.disconnect(); + } - this.removeListeners(); + this.removeListeners(); }; diff --git a/src/core.js b/src/core.js index 68e963d..b2f5033 100644 --- a/src/core.js +++ b/src/core.js @@ -5,536 +5,536 @@ var requestAnimationFrame = (typeof window != 'undefined') ? (window.requestAnim /* //-- Parse the different parts of a url, returning a object function uri(url){ - var uri = { - protocol : '', - host : '', - path : '', - origin : '', - directory : '', - base : '', - filename : '', - extension : '', - fragment : '', - href : url - }, - doubleSlash = url.indexOf('://'), - search = url.indexOf('?'), - fragment = url.indexOf("#"), - withoutProtocol, - dot, - firstSlash; + var uri = { + protocol : '', + host : '', + path : '', + origin : '', + directory : '', + base : '', + filename : '', + extension : '', + fragment : '', + href : url + }, + doubleSlash = url.indexOf('://'), + search = url.indexOf('?'), + fragment = url.indexOf("#"), + withoutProtocol, + dot, + firstSlash; - if(fragment != -1) { - uri.fragment = url.slice(fragment + 1); - url = url.slice(0, fragment); - } + if(fragment != -1) { + uri.fragment = url.slice(fragment + 1); + url = url.slice(0, fragment); + } - if(search != -1) { - uri.search = url.slice(search + 1); - url = url.slice(0, search); - href = url; - } + if(search != -1) { + uri.search = url.slice(search + 1); + url = url.slice(0, search); + href = url; + } - if(doubleSlash != -1) { - uri.protocol = url.slice(0, doubleSlash); - withoutProtocol = url.slice(doubleSlash+3); - firstSlash = withoutProtocol.indexOf('/'); + if(doubleSlash != -1) { + uri.protocol = url.slice(0, doubleSlash); + withoutProtocol = url.slice(doubleSlash+3); + firstSlash = withoutProtocol.indexOf('/'); - if(firstSlash === -1) { - uri.host = uri.path; - uri.path = ""; - } else { - uri.host = withoutProtocol.slice(0, firstSlash); - uri.path = withoutProtocol.slice(firstSlash); - } + if(firstSlash === -1) { + uri.host = uri.path; + uri.path = ""; + } else { + uri.host = withoutProtocol.slice(0, firstSlash); + uri.path = withoutProtocol.slice(firstSlash); + } - uri.origin = uri.protocol + "://" + uri.host; + uri.origin = uri.protocol + "://" + uri.host; - uri.directory = folder(uri.path); + uri.directory = folder(uri.path); - uri.base = uri.origin + uri.directory; - // return origin; - } else { - uri.path = url; - uri.directory = folder(url); - uri.base = uri.directory; - } + uri.base = uri.origin + uri.directory; + // return origin; + } else { + uri.path = url; + uri.directory = folder(url); + uri.base = uri.directory; + } - //-- Filename - uri.filename = url.replace(uri.base, ''); - dot = uri.filename.lastIndexOf('.'); - if(dot != -1) { - uri.extension = uri.filename.slice(dot+1); - } - return uri; + //-- Filename + uri.filename = url.replace(uri.base, ''); + dot = uri.filename.lastIndexOf('.'); + if(dot != -1) { + uri.extension = uri.filename.slice(dot+1); + } + return uri; }; //-- Parse out the folder, will return everything before the last slash function folder(url){ - var lastSlash = url.lastIndexOf('/'); + var lastSlash = url.lastIndexOf('/'); - if(lastSlash == -1) var folder = ''; + if(lastSlash == -1) var folder = ''; - folder = url.slice(0, lastSlash + 1); + folder = url.slice(0, lastSlash + 1); - return folder; + return folder; }; */ function isElement(obj) { - return !!(obj && obj.nodeType == 1); + return !!(obj && obj.nodeType == 1); }; // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript function uuid() { - var d = new Date().getTime(); - var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = (d + Math.random()*16)%16 | 0; - d = Math.floor(d/16); - return (c=='x' ? r : (r&0x7|0x8)).toString(16); - }); - return uuid; + var d = new Date().getTime(); + var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = (d + Math.random()*16)%16 | 0; + d = Math.floor(d/16); + return (c=='x' ? r : (r&0x7|0x8)).toString(16); + }); + return uuid; }; // From Lodash function values(object) { - var index = -1, - props = Object.keys(object), - length = props.length, - result = Array(length); + var index = -1, + props = Object.keys(object), + length = props.length, + result = Array(length); - while (++index < length) { - result[index] = object[props[index]]; - } - return result; + while (++index < length) { + result[index] = object[props[index]]; + } + return result; }; function resolveUrl(base, path) { - var url = [], - segments = [], - baseUri = uri(base), - pathUri = uri(path), - baseDirectory = baseUri.directory, - pathDirectory = pathUri.directory, - directories = [], - // folders = base.split("/"), - paths; + var url = [], + segments = [], + baseUri = uri(base), + pathUri = uri(path), + baseDirectory = baseUri.directory, + pathDirectory = pathUri.directory, + directories = [], + // folders = base.split("/"), + paths; - // if(uri.host) { - // return path; - // } + // if(uri.host) { + // return path; + // } - if(baseDirectory[0] === "/") { - baseDirectory = baseDirectory.substring(1); - } + if(baseDirectory[0] === "/") { + baseDirectory = baseDirectory.substring(1); + } - if(pathDirectory[pathDirectory.length-1] === "/") { - baseDirectory = baseDirectory.substring(0, baseDirectory.length-1); - } + if(pathDirectory[pathDirectory.length-1] === "/") { + baseDirectory = baseDirectory.substring(0, baseDirectory.length-1); + } - if(pathDirectory[0] === "/") { - pathDirectory = pathDirectory.substring(1); - } + if(pathDirectory[0] === "/") { + pathDirectory = pathDirectory.substring(1); + } - if(pathDirectory[pathDirectory.length-1] === "/") { - pathDirectory = pathDirectory.substring(0, pathDirectory.length-1); - } + if(pathDirectory[pathDirectory.length-1] === "/") { + pathDirectory = pathDirectory.substring(0, pathDirectory.length-1); + } - if(baseDirectory) { - directories = baseDirectory.split("/"); - } + if(baseDirectory) { + directories = baseDirectory.split("/"); + } - paths = pathDirectory.split("/"); + paths = pathDirectory.split("/"); - paths.reverse().forEach(function(part, index){ - if(part === ".."){ - directories.pop(); - } else if(part === directories[directories.length-1]) { - directories.pop(); - segments.unshift(part); - } else { - segments.unshift(part); - } - }); + paths.reverse().forEach(function(part, index){ + if(part === ".."){ + directories.pop(); + } else if(part === directories[directories.length-1]) { + directories.pop(); + segments.unshift(part); + } else { + segments.unshift(part); + } + }); - url = [baseUri.origin]; + url = [baseUri.origin]; - if(directories.length) { - url = url.concat(directories); - } + if(directories.length) { + url = url.concat(directories); + } - if(segments) { - url = url.concat(segments); - } + if(segments) { + url = url.concat(segments); + } - url = url.concat(pathUri.filename); + url = url.concat(pathUri.filename); - return url.join("/"); + return url.join("/"); }; function documentHeight() { - return Math.max( - document.documentElement.clientHeight, - document.body.scrollHeight, - document.documentElement.scrollHeight, - document.body.offsetHeight, - document.documentElement.offsetHeight - ); + return Math.max( + document.documentElement.clientHeight, + document.body.scrollHeight, + document.documentElement.scrollHeight, + document.body.offsetHeight, + document.documentElement.offsetHeight + ); }; function isNumber(n) { - return !isNaN(parseFloat(n)) && isFinite(n); + return !isNaN(parseFloat(n)) && isFinite(n); }; function prefixed(unprefixed) { - var vendors = ["Webkit", "Moz", "O", "ms" ], - prefixes = ['-Webkit-', '-moz-', '-o-', '-ms-'], - upper = unprefixed[0].toUpperCase() + unprefixed.slice(1), - length = vendors.length; + var vendors = ["Webkit", "Moz", "O", "ms" ], + prefixes = ['-Webkit-', '-moz-', '-o-', '-ms-'], + upper = unprefixed[0].toUpperCase() + unprefixed.slice(1), + length = vendors.length; - if (typeof(document) === 'undefined' || typeof(document.body.style[unprefixed]) != 'undefined') { - return unprefixed; - } + if (typeof(document) === 'undefined' || typeof(document.body.style[unprefixed]) != 'undefined') { + return unprefixed; + } - for ( var i=0; i < length; i++ ) { - if (typeof(document.body.style[vendors[i] + upper]) != 'undefined') { - return vendors[i] + upper; - } - } + for ( var i=0; i < length; i++ ) { + if (typeof(document.body.style[vendors[i] + upper]) != 'undefined') { + return vendors[i] + upper; + } + } - return unprefixed; + return unprefixed; }; function defaults(obj) { - for (var i = 1, length = arguments.length; i < length; i++) { - var source = arguments[i]; - for (var prop in source) { - if (obj[prop] === void 0) obj[prop] = source[prop]; - } - } - return obj; + for (var i = 1, length = arguments.length; i < length; i++) { + var source = arguments[i]; + for (var prop in source) { + if (obj[prop] === void 0) obj[prop] = source[prop]; + } + } + return obj; }; function extend(target) { - var sources = [].slice.call(arguments, 1); - sources.forEach(function (source) { - if(!source) return; - Object.getOwnPropertyNames(source).forEach(function(propName) { - Object.defineProperty(target, propName, Object.getOwnPropertyDescriptor(source, propName)); - }); - }); - return target; + var sources = [].slice.call(arguments, 1); + sources.forEach(function (source) { + if(!source) return; + Object.getOwnPropertyNames(source).forEach(function(propName) { + Object.defineProperty(target, propName, Object.getOwnPropertyDescriptor(source, propName)); + }); + }); + return target; }; // Fast quicksort insert for sorted array -- based on: // http://stackoverflow.com/questions/1344500/efficient-way-to-insert-a-number-into-a-sorted-array-of-numbers function insert(item, array, compareFunction) { - var location = locationOf(item, array, compareFunction); - array.splice(location, 0, item); + var location = locationOf(item, array, compareFunction); + array.splice(location, 0, item); - return location; + return location; }; // Returns where something would fit in function locationOf(item, array, compareFunction, _start, _end) { - var start = _start || 0; - var end = _end || array.length; - var pivot = parseInt(start + (end - start) / 2); - var compared; - if(!compareFunction){ - compareFunction = function(a, b) { - if(a > b) return 1; - if(a < b) return -1; - if(a = b) return 0; - }; - } - if(end-start <= 0) { - return pivot; - } + var start = _start || 0; + var end = _end || array.length; + var pivot = parseInt(start + (end - start) / 2); + var compared; + if(!compareFunction){ + compareFunction = function(a, b) { + if(a > b) return 1; + if(a < b) return -1; + if(a = b) return 0; + }; + } + if(end-start <= 0) { + return pivot; + } - compared = compareFunction(array[pivot], item); - if(end-start === 1) { - return compared > 0 ? pivot : pivot + 1; - } + compared = compareFunction(array[pivot], item); + if(end-start === 1) { + return compared > 0 ? pivot : pivot + 1; + } - if(compared === 0) { - return pivot; - } - if(compared === -1) { - return locationOf(item, array, compareFunction, pivot, end); - } else{ - return locationOf(item, array, compareFunction, start, pivot); - } + if(compared === 0) { + return pivot; + } + if(compared === -1) { + return locationOf(item, array, compareFunction, pivot, end); + } else{ + return locationOf(item, array, compareFunction, start, pivot); + } }; // Returns -1 of mpt found function indexOfSorted(item, array, compareFunction, _start, _end) { - var start = _start || 0; - var end = _end || array.length; - var pivot = parseInt(start + (end - start) / 2); - var compared; - if(!compareFunction){ - compareFunction = function(a, b) { - if(a > b) return 1; - if(a < b) return -1; - if(a = b) return 0; - }; - } - if(end-start <= 0) { - return -1; // Not found - } + var start = _start || 0; + var end = _end || array.length; + var pivot = parseInt(start + (end - start) / 2); + var compared; + if(!compareFunction){ + compareFunction = function(a, b) { + if(a > b) return 1; + if(a < b) return -1; + if(a = b) return 0; + }; + } + if(end-start <= 0) { + return -1; // Not found + } - compared = compareFunction(array[pivot], item); - if(end-start === 1) { - return compared === 0 ? pivot : -1; - } - if(compared === 0) { - return pivot; // Found - } - if(compared === -1) { - return indexOfSorted(item, array, compareFunction, pivot, end); - } else{ - return indexOfSorted(item, array, compareFunction, start, pivot); - } + compared = compareFunction(array[pivot], item); + if(end-start === 1) { + return compared === 0 ? pivot : -1; + } + if(compared === 0) { + return pivot; // Found + } + if(compared === -1) { + return indexOfSorted(item, array, compareFunction, pivot, end); + } else{ + return indexOfSorted(item, array, compareFunction, start, pivot); + } }; function bounds(el) { - var style = window.getComputedStyle(el); - var widthProps = ["width", "paddingRight", "paddingLeft", "marginRight", "marginLeft", "borderRightWidth", "borderLeftWidth"]; - var heightProps = ["height", "paddingTop", "paddingBottom", "marginTop", "marginBottom", "borderTopWidth", "borderBottomWidth"]; + var style = window.getComputedStyle(el); + var widthProps = ["width", "paddingRight", "paddingLeft", "marginRight", "marginLeft", "borderRightWidth", "borderLeftWidth"]; + var heightProps = ["height", "paddingTop", "paddingBottom", "marginTop", "marginBottom", "borderTopWidth", "borderBottomWidth"]; - var width = 0; - var height = 0; + var width = 0; + var height = 0; - widthProps.forEach(function(prop){ - width += parseFloat(style[prop]) || 0; - }); + widthProps.forEach(function(prop){ + width += parseFloat(style[prop]) || 0; + }); - heightProps.forEach(function(prop){ - height += parseFloat(style[prop]) || 0; - }); + heightProps.forEach(function(prop){ + height += parseFloat(style[prop]) || 0; + }); - return { - height: height, - width: width - }; + return { + height: height, + width: width + }; }; function borders(el) { - var style = window.getComputedStyle(el); - var widthProps = ["paddingRight", "paddingLeft", "marginRight", "marginLeft", "borderRightWidth", "borderLeftWidth"]; - var heightProps = ["paddingTop", "paddingBottom", "marginTop", "marginBottom", "borderTopWidth", "borderBottomWidth"]; + var style = window.getComputedStyle(el); + var widthProps = ["paddingRight", "paddingLeft", "marginRight", "marginLeft", "borderRightWidth", "borderLeftWidth"]; + var heightProps = ["paddingTop", "paddingBottom", "marginTop", "marginBottom", "borderTopWidth", "borderBottomWidth"]; - var width = 0; - var height = 0; + var width = 0; + var height = 0; - widthProps.forEach(function(prop){ - width += parseFloat(style[prop]) || 0; - }); + widthProps.forEach(function(prop){ + width += parseFloat(style[prop]) || 0; + }); - heightProps.forEach(function(prop){ - height += parseFloat(style[prop]) || 0; - }); + heightProps.forEach(function(prop){ + height += parseFloat(style[prop]) || 0; + }); - return { - height: height, - width: width - }; + return { + height: height, + width: width + }; }; function windowBounds() { - var width = window.innerWidth; - var height = window.innerHeight; + var width = window.innerWidth; + var height = window.innerHeight; - return { - top: 0, - left: 0, - right: width, - bottom: height, - width: width, - height: height - }; + return { + top: 0, + left: 0, + right: width, + bottom: height, + width: width, + height: height + }; }; //https://stackoverflow.com/questions/13482352/xquery-looking-for-text-with-single-quote/13483496#13483496 function cleanStringForXpath(str) { - var parts = str.match(/[^'"]+|['"]/g); - parts = parts.map(function(part){ - if (part === "'") { - return '\"\'\"'; // output "'" - } + var parts = str.match(/[^'"]+|['"]/g); + parts = parts.map(function(part){ + if (part === "'") { + return '\"\'\"'; // output "'" + } - if (part === '"') { - return "\'\"\'"; // output '"' - } - return "\'" + part + "\'"; - }); - return "concat(\'\'," + parts.join(",") + ")"; + if (part === '"') { + return "\'\"\'"; // output '"' + } + return "\'" + part + "\'"; + }); + return "concat(\'\'," + parts.join(",") + ")"; }; function indexOfTextNode(textNode){ - var parent = textNode.parentNode; - var children = parent.childNodes; - var sib; - var index = -1; - for (var i = 0; i < children.length; i++) { - sib = children[i]; - if(sib.nodeType === Node.TEXT_NODE){ - index++; - } - if(sib == textNode) break; - } + var parent = textNode.parentNode; + var children = parent.childNodes; + var sib; + var index = -1; + for (var i = 0; i < children.length; i++) { + sib = children[i]; + if(sib.nodeType === Node.TEXT_NODE){ + index++; + } + if(sib == textNode) break; + } - return index; + return index; }; function isXml(ext) { - return ['xml', 'opf', 'ncx'].indexOf(ext) > -1; + return ['xml', 'opf', 'ncx'].indexOf(ext) > -1; } function createBlob(content, mime){ var blob = new Blob([content], {type : mime }); - return blob; + return blob; }; function createBlobUrl(content, mime){ - var _URL = window.URL || window.webkitURL || window.mozURL; + var _URL = window.URL || window.webkitURL || window.mozURL; var tempUrl; var blob = this.createBlob(content, mime); - tempUrl = _URL.createObjectURL(blob); + tempUrl = _URL.createObjectURL(blob); - return tempUrl; + return tempUrl; }; function createBase64Url(content, mime){ - var string; - var data; - var datauri; + var string; + var data; + var datauri; - if (typeof(content) !== "string") { - // Only handles strings - return; - } + if (typeof(content) !== "string") { + // Only handles strings + return; + } - data = btoa(content); + data = btoa(content); - datauri = "data:" + mime + ";base64," + data; + datauri = "data:" + mime + ";base64," + data; - return datauri; + return datauri; }; function type(obj){ - return Object.prototype.toString.call(obj).slice(8, -1); + return Object.prototype.toString.call(obj).slice(8, -1); } function parse(markup, mime) { - var doc; - // console.log("parse", markup); + var doc; + // console.log("parse", markup); - if (typeof DOMParser === "undefined") { - DOMParser = require('xmldom').DOMParser; - } + if (typeof DOMParser === "undefined") { + DOMParser = require('xmldom').DOMParser; + } - doc = new DOMParser().parseFromString(markup, mime); + doc = new DOMParser().parseFromString(markup, mime); - return doc; + return doc; } function qs(el, sel) { - var elements; + var elements; - if (typeof el.querySelector != "undefined") { - return el.querySelector(sel); - } else { - elements = el.getElementsByTagName(sel); - if (elements.length) { - return elements[0]; - } - } + if (typeof el.querySelector != "undefined") { + return el.querySelector(sel); + } else { + elements = el.getElementsByTagName(sel); + if (elements.length) { + return elements[0]; + } + } } function qsa(el, sel) { - if (typeof el.querySelector != "undefined") { - return el.querySelectorAll(sel); - } else { - return el.getElementsByTagName(sel); - } + if (typeof el.querySelector != "undefined") { + return el.querySelectorAll(sel); + } else { + return el.getElementsByTagName(sel); + } } function qsp(el, sel, props) { - var q, filtered; - if (typeof el.querySelector != "undefined") { - sel += '['; - for (var prop in props) { - sel += prop + "='" + props[prop] + "'"; - } - sel += ']'; - return el.querySelector(sel); - } else { - q = el.getElementsByTagName(sel); - filtered = Array.prototype.slice.call(q, 0).filter(function(el) { - for (var prop in props) { - if(el.getAttribute(prop) === props[prop]){ - return true; - } - } - return false; - }); + var q, filtered; + if (typeof el.querySelector != "undefined") { + sel += '['; + for (var prop in props) { + sel += prop + "='" + props[prop] + "'"; + } + sel += ']'; + return el.querySelector(sel); + } else { + q = el.getElementsByTagName(sel); + filtered = Array.prototype.slice.call(q, 0).filter(function(el) { + for (var prop in props) { + if(el.getAttribute(prop) === props[prop]){ + return true; + } + } + return false; + }); - if (filtered) { - return filtered[0]; - } - } + if (filtered) { + return filtered[0]; + } + } } function blob2base64(blob, cb) { - var reader = new FileReader(); - reader.readAsDataURL(blob); - reader.onloadend = function() { - cb(reader.result); - } + var reader = new FileReader(); + reader.readAsDataURL(blob); + reader.onloadend = function() { + cb(reader.result); + } } module.exports = { - // 'uri': uri, - // 'folder': folder, - 'isElement': isElement, - 'uuid': uuid, - 'values': values, - 'resolveUrl': resolveUrl, - 'indexOfSorted': indexOfSorted, - 'documentHeight': documentHeight, - 'isNumber': isNumber, - 'prefixed': prefixed, - 'defaults': defaults, - 'extend': extend, - 'insert': insert, - 'locationOf': locationOf, - 'indexOfSorted': indexOfSorted, - 'requestAnimationFrame': requestAnimationFrame, - 'bounds': bounds, - 'borders': borders, - 'windowBounds': windowBounds, - 'cleanStringForXpath': cleanStringForXpath, - 'indexOfTextNode': indexOfTextNode, - 'isXml': isXml, - 'createBlob': createBlob, - 'createBlobUrl': createBlobUrl, - 'type': type, - 'parse' : parse, - 'qs' : qs, - 'qsa' : qsa, - 'qsp' : qsp, - 'blob2base64' : blob2base64, - 'createBase64Url': createBase64Url + // 'uri': uri, + // 'folder': folder, + 'isElement': isElement, + 'uuid': uuid, + 'values': values, + 'resolveUrl': resolveUrl, + 'indexOfSorted': indexOfSorted, + 'documentHeight': documentHeight, + 'isNumber': isNumber, + 'prefixed': prefixed, + 'defaults': defaults, + 'extend': extend, + 'insert': insert, + 'locationOf': locationOf, + 'indexOfSorted': indexOfSorted, + 'requestAnimationFrame': requestAnimationFrame, + 'bounds': bounds, + 'borders': borders, + 'windowBounds': windowBounds, + 'cleanStringForXpath': cleanStringForXpath, + 'indexOfTextNode': indexOfTextNode, + 'isXml': isXml, + 'createBlob': createBlob, + 'createBlobUrl': createBlobUrl, + 'type': type, + 'parse' : parse, + 'qs' : qs, + 'qsa' : qsa, + 'qsp' : qsp, + 'blob2base64' : blob2base64, + 'createBase64Url': createBase64Url }; diff --git a/src/epub.js b/src/epub.js index 081c528..161017f 100644 --- a/src/epub.js +++ b/src/epub.js @@ -19,7 +19,7 @@ ePub.ViewManagers = {}; ePub.Views = {}; ePub.register = { manager : function(name, manager){ - return ePub.ViewManagers[name] = manager; + return ePub.ViewManagers[name] = manager; }, view : function(name, view){ return ePub.Views[name] = view; diff --git a/src/epubcfi.js b/src/epubcfi.js index 2d1f747..1ab9d9b 100644 --- a/src/epubcfi.js +++ b/src/epubcfi.js @@ -2,730 +2,730 @@ var URI = require('urijs'); var core = require('./core'); /** - EPUB CFI spec: http://www.idpf.org/epub/linking/cfi/epub-cfi.html + EPUB CFI spec: http://www.idpf.org/epub/linking/cfi/epub-cfi.html - Implements: - - Character Offset: epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3) - - Simple Ranges : epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4) + Implements: + - Character Offset: epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3) + - Simple Ranges : epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4) - Does Not Implement: - - Temporal Offset (~) - - Spatial Offset (@) - - Temporal-Spatial Offset (~ + @) - - Text Location Assertion ([) + Does Not Implement: + - Temporal Offset (~) + - Spatial Offset (@) + - Temporal-Spatial Offset (~ + @) + - Text Location Assertion ([) */ function EpubCFI(cfiFrom, base, ignoreClass){ - var type; + var type; - this.str = ''; + this.str = ''; - this.base = {}; - this.spinePos = 0; // For compatibility + this.base = {}; + this.spinePos = 0; // For compatibility - this.range = false; // true || false; + this.range = false; // true || false; - this.path = {}; - this.start = null; - this.end = null; + this.path = {}; + this.start = null; + this.end = null; - // Allow instantiation without the 'new' keyword - if (!(this instanceof EpubCFI)) { - return new EpubCFI(cfiFrom, base, ignoreClass); - } + // Allow instantiation without the 'new' keyword + if (!(this instanceof EpubCFI)) { + return new EpubCFI(cfiFrom, base, ignoreClass); + } - if(typeof base === 'string') { - this.base = this.parseComponent(base); - } else if(typeof base === 'object' && base.steps) { - this.base = base; - } + if(typeof base === 'string') { + this.base = this.parseComponent(base); + } else if(typeof base === 'object' && base.steps) { + this.base = base; + } - type = this.checkType(cfiFrom); + type = this.checkType(cfiFrom); - if(type === 'string') { - this.str = cfiFrom; - return core.extend(this, this.parse(cfiFrom)); - } else if (type === 'range') { - return core.extend(this, this.fromRange(cfiFrom, this.base, ignoreClass)); - } else if (type === 'node') { - return core.extend(this, this.fromNode(cfiFrom, this.base, ignoreClass)); - } else if (type === 'EpubCFI' && cfiFrom.path) { - return cfiFrom; - } else if (!cfiFrom) { - return this; - } else { - throw new TypeError('not a valid argument for EpubCFI'); - } + if(type === 'string') { + this.str = cfiFrom; + return core.extend(this, this.parse(cfiFrom)); + } else if (type === 'range') { + return core.extend(this, this.fromRange(cfiFrom, this.base, ignoreClass)); + } else if (type === 'node') { + return core.extend(this, this.fromNode(cfiFrom, this.base, ignoreClass)); + } else if (type === 'EpubCFI' && cfiFrom.path) { + return cfiFrom; + } else if (!cfiFrom) { + return this; + } else { + throw new TypeError('not a valid argument for EpubCFI'); + } }; EpubCFI.prototype.checkType = function(cfi) { - if (this.isCfiString(cfi)) { - return 'string'; - // Is a range object - } else if (typeof cfi === 'object' && core.type(cfi) === "Range"){ - return 'range'; - } else if (typeof cfi === 'object' && typeof(cfi.nodeType) != "undefined" ){ // || typeof cfi === 'function' - return 'node'; - } else if (typeof cfi === 'object' && cfi instanceof EpubCFI){ - return 'EpubCFI'; - } else { - return false; - } + if (this.isCfiString(cfi)) { + return 'string'; + // Is a range object + } else if (typeof cfi === 'object' && core.type(cfi) === "Range"){ + return 'range'; + } else if (typeof cfi === 'object' && typeof(cfi.nodeType) != "undefined" ){ // || typeof cfi === 'function' + return 'node'; + } else if (typeof cfi === 'object' && cfi instanceof EpubCFI){ + return 'EpubCFI'; + } else { + return false; + } }; EpubCFI.prototype.parse = function(cfiStr) { - var cfi = { - spinePos: -1, - range: false, - base: {}, - path: {}, - start: null, - end: null - }; - var baseComponent, pathComponent, range; + var cfi = { + spinePos: -1, + range: false, + base: {}, + path: {}, + start: null, + end: null + }; + var baseComponent, pathComponent, range; - if(typeof cfiStr !== "string") { - return {spinePos: -1}; - } + if(typeof cfiStr !== "string") { + return {spinePos: -1}; + } - if(cfiStr.indexOf("epubcfi(") === 0 && cfiStr[cfiStr.length-1] === ")") { - // Remove intial epubcfi( and ending ) - cfiStr = cfiStr.slice(8, cfiStr.length-1); - } + if(cfiStr.indexOf("epubcfi(") === 0 && cfiStr[cfiStr.length-1] === ")") { + // Remove intial epubcfi( and ending ) + cfiStr = cfiStr.slice(8, cfiStr.length-1); + } - baseComponent = this.getChapterComponent(cfiStr); + baseComponent = this.getChapterComponent(cfiStr); - // Make sure this is a valid cfi or return - if(!baseComponent) { - return {spinePos: -1}; - } + // Make sure this is a valid cfi or return + if(!baseComponent) { + return {spinePos: -1}; + } - cfi.base = this.parseComponent(baseComponent); + cfi.base = this.parseComponent(baseComponent); - pathComponent = this.getPathComponent(cfiStr); - cfi.path = this.parseComponent(pathComponent); + pathComponent = this.getPathComponent(cfiStr); + cfi.path = this.parseComponent(pathComponent); - range = this.getRange(cfiStr); + range = this.getRange(cfiStr); - if(range) { - cfi.range = true; - cfi.start = this.parseComponent(range[0]); - cfi.end = this.parseComponent(range[1]); - } + if(range) { + cfi.range = true; + cfi.start = this.parseComponent(range[0]); + cfi.end = this.parseComponent(range[1]); + } - // Get spine node position - // cfi.spineSegment = cfi.base.steps[1]; + // Get spine node position + // cfi.spineSegment = cfi.base.steps[1]; - // Chapter segment is always the second step - cfi.spinePos = cfi.base.steps[1].index; + // Chapter segment is always the second step + cfi.spinePos = cfi.base.steps[1].index; - return cfi; + return cfi; }; EpubCFI.prototype.parseComponent = function(componentStr){ - var component = { - steps: [], - terminal: { - offset: null, - assertion: null - } - }; - var parts = componentStr.split(':'); - var steps = parts[0].split('/'); - var terminal; + var component = { + steps: [], + terminal: { + offset: null, + assertion: null + } + }; + var parts = componentStr.split(':'); + var steps = parts[0].split('/'); + var terminal; - if(parts.length > 1) { - terminal = parts[1]; - component.terminal = this.parseTerminal(terminal); - } + if(parts.length > 1) { + terminal = parts[1]; + component.terminal = this.parseTerminal(terminal); + } - if (steps[0] === '') { - steps.shift(); // Ignore the first slash - } + if (steps[0] === '') { + steps.shift(); // Ignore the first slash + } - component.steps = steps.map(function(step){ - return this.parseStep(step); - }.bind(this)); + component.steps = steps.map(function(step){ + return this.parseStep(step); + }.bind(this)); - return component; + return component; }; EpubCFI.prototype.parseStep = function(stepStr){ - var type, num, index, has_brackets, id; + var type, num, index, has_brackets, id; - has_brackets = stepStr.match(/\[(.*)\]/); - if(has_brackets && has_brackets[1]){ - id = has_brackets[1]; - } + has_brackets = stepStr.match(/\[(.*)\]/); + if(has_brackets && has_brackets[1]){ + id = has_brackets[1]; + } - //-- Check if step is a text node or element - num = parseInt(stepStr); + //-- Check if step is a text node or element + num = parseInt(stepStr); - if(isNaN(num)) { - return; - } + if(isNaN(num)) { + return; + } - if(num % 2 === 0) { // Even = is an element - type = "element"; - index = num / 2 - 1; - } else { - type = "text"; - index = (num - 1 ) / 2; - } + if(num % 2 === 0) { // Even = is an element + type = "element"; + index = num / 2 - 1; + } else { + type = "text"; + index = (num - 1 ) / 2; + } - return { - "type" : type, - 'index' : index, - 'id' : id || null - }; + return { + "type" : type, + 'index' : index, + 'id' : id || null + }; }; EpubCFI.prototype.parseTerminal = function(termialStr){ - var characterOffset, textLocationAssertion; - var assertion = termialStr.match(/\[(.*)\]/); + var characterOffset, textLocationAssertion; + var assertion = termialStr.match(/\[(.*)\]/); - if(assertion && assertion[1]){ - characterOffset = parseInt(termialStr.split('[')[0]) || null; - textLocationAssertion = assertion[1]; - } else { - characterOffset = parseInt(termialStr) || null; - } + if(assertion && assertion[1]){ + characterOffset = parseInt(termialStr.split('[')[0]) || null; + textLocationAssertion = assertion[1]; + } else { + characterOffset = parseInt(termialStr) || null; + } - return { - 'offset': characterOffset, - 'assertion': textLocationAssertion - }; + return { + 'offset': characterOffset, + 'assertion': textLocationAssertion + }; }; EpubCFI.prototype.getChapterComponent = function(cfiStr) { - var indirection = cfiStr.split("!"); + var indirection = cfiStr.split("!"); - return indirection[0]; + return indirection[0]; }; EpubCFI.prototype.getPathComponent = function(cfiStr) { - var indirection = cfiStr.split("!"); + var indirection = cfiStr.split("!"); - if(indirection[1]) { - ranges = indirection[1].split(','); - return ranges[0]; - } + if(indirection[1]) { + ranges = indirection[1].split(','); + return ranges[0]; + } }; EpubCFI.prototype.getRange = function(cfiStr) { - var ranges = cfiStr.split(","); + var ranges = cfiStr.split(","); - if(ranges.length === 3){ - return [ - ranges[1], - ranges[2] - ]; - } + if(ranges.length === 3){ + return [ + ranges[1], + ranges[2] + ]; + } - return false; + return false; }; EpubCFI.prototype.getCharecterOffsetComponent = function(cfiStr) { - var splitStr = cfiStr.split(":"); - return splitStr[1] || ''; + var splitStr = cfiStr.split(":"); + return splitStr[1] || ''; }; EpubCFI.prototype.joinSteps = function(steps) { - if(!steps) { - return ""; - } - - return steps.map(function(part){ - var segment = ''; + if(!steps) { + return ""; + } - if(part.type === 'element') { - segment += (part.index + 1) * 2; - } + return steps.map(function(part){ + var segment = ''; - if(part.type === 'text') { - segment += 1 + (2 * part.index); // TODO: double check that this is odd - } + if(part.type === 'element') { + segment += (part.index + 1) * 2; + } - if(part.id) { - segment += "[" + part.id + "]"; - } + if(part.type === 'text') { + segment += 1 + (2 * part.index); // TODO: double check that this is odd + } - return segment; + if(part.id) { + segment += "[" + part.id + "]"; + } - }).join('/'); + return segment; + + }).join('/'); }; EpubCFI.prototype.segmentString = function(segment) { - var segmentString = '/'; + var segmentString = '/'; - segmentString += this.joinSteps(segment.steps); + segmentString += this.joinSteps(segment.steps); - if(segment.terminal && segment.terminal.offset != null){ - segmentString += ':' + segment.terminal.offset; - } + if(segment.terminal && segment.terminal.offset != null){ + segmentString += ':' + segment.terminal.offset; + } - if(segment.terminal && segment.terminal.assertion != null){ - segmentString += '[' + segment.terminal.assertion + ']'; - } + if(segment.terminal && segment.terminal.assertion != null){ + segmentString += '[' + segment.terminal.assertion + ']'; + } - return segmentString; + return segmentString; }; EpubCFI.prototype.toString = function() { - var cfiString = 'epubcfi('; + var cfiString = 'epubcfi('; - cfiString += this.segmentString(this.base); + cfiString += this.segmentString(this.base); - cfiString += '!'; - cfiString += this.segmentString(this.path); + cfiString += '!'; + cfiString += this.segmentString(this.path); - // Add Range, if present - if(this.start) { - cfiString += ','; - cfiString += this.segmentString(this.start); - } + // Add Range, if present + if(this.start) { + cfiString += ','; + cfiString += this.segmentString(this.start); + } - if(this.end) { - cfiString += ','; - cfiString += this.segmentString(this.end); - } + if(this.end) { + cfiString += ','; + cfiString += this.segmentString(this.end); + } - cfiString += ")"; + cfiString += ")"; - return cfiString; + return cfiString; }; EpubCFI.prototype.compare = function(cfiOne, cfiTwo) { - if(typeof cfiOne === 'string') { - cfiOne = new EpubCFI(cfiOne); - } - if(typeof cfiTwo === 'string') { - cfiTwo = new EpubCFI(cfiTwo); - } - // Compare Spine Positions - if(cfiOne.spinePos > cfiTwo.spinePos) { - return 1; - } - if(cfiOne.spinePos < cfiTwo.spinePos) { - return -1; - } + if(typeof cfiOne === 'string') { + cfiOne = new EpubCFI(cfiOne); + } + if(typeof cfiTwo === 'string') { + cfiTwo = new EpubCFI(cfiTwo); + } + // Compare Spine Positions + if(cfiOne.spinePos > cfiTwo.spinePos) { + return 1; + } + if(cfiOne.spinePos < cfiTwo.spinePos) { + return -1; + } - // Compare Each Step in the First item - for (var i = 0; i < cfiOne.path.steps.length; i++) { - if(!cfiTwo.path.steps[i]) { - return 1; - } - if(cfiOne.path.steps[i].index > cfiTwo.path.steps[i].index) { - return 1; - } - if(cfiOne.path.steps[i].index < cfiTwo.path.steps[i].index) { - return -1; - } - // Otherwise continue checking - } + // Compare Each Step in the First item + for (var i = 0; i < cfiOne.path.steps.length; i++) { + if(!cfiTwo.path.steps[i]) { + return 1; + } + if(cfiOne.path.steps[i].index > cfiTwo.path.steps[i].index) { + return 1; + } + if(cfiOne.path.steps[i].index < cfiTwo.path.steps[i].index) { + return -1; + } + // Otherwise continue checking + } - // All steps in First equal to Second and First is Less Specific - if(cfiOne.path.steps.length < cfiTwo.path.steps.length) { - return 1; - } + // All steps in First equal to Second and First is Less Specific + if(cfiOne.path.steps.length < cfiTwo.path.steps.length) { + return 1; + } - // Compare the charecter offset of the text node - if(cfiOne.path.terminal.offset > cfiTwo.path.terminal.offset) { - return 1; - } - if(cfiOne.path.terminal.offset < cfiTwo.path.terminal.offset) { - return -1; - } + // Compare the charecter offset of the text node + if(cfiOne.path.terminal.offset > cfiTwo.path.terminal.offset) { + return 1; + } + if(cfiOne.path.terminal.offset < cfiTwo.path.terminal.offset) { + return -1; + } - // TODO: compare ranges + // TODO: compare ranges - // CFI's are equal - return 0; + // CFI's are equal + return 0; }; EpubCFI.prototype.step = function(node) { - var nodeType = (node.nodeType === Node.TEXT_NODE) ? 'text' : 'element'; + var nodeType = (node.nodeType === Node.TEXT_NODE) ? 'text' : 'element'; - return { - 'id' : node.id, - 'tagName' : node.tagName, - 'type' : nodeType, - 'index' : this.position(node) - }; + return { + 'id' : node.id, + 'tagName' : node.tagName, + 'type' : nodeType, + 'index' : this.position(node) + }; }; EpubCFI.prototype.filteredStep = function(node, ignoreClass) { - var filteredNode = this.filter(node, ignoreClass); - var nodeType; + var filteredNode = this.filter(node, ignoreClass); + var nodeType; - // Node filtered, so ignore - if (!filteredNode) { - return; - } + // Node filtered, so ignore + if (!filteredNode) { + return; + } - // Otherwise add the filter node in - nodeType = (filteredNode.nodeType === Node.TEXT_NODE) ? 'text' : 'element'; + // Otherwise add the filter node in + nodeType = (filteredNode.nodeType === Node.TEXT_NODE) ? 'text' : 'element'; - return { - 'id' : filteredNode.id, - 'tagName' : filteredNode.tagName, - 'type' : nodeType, - 'index' : this.filteredPosition(filteredNode, ignoreClass) - }; + return { + 'id' : filteredNode.id, + 'tagName' : filteredNode.tagName, + 'type' : nodeType, + 'index' : this.filteredPosition(filteredNode, ignoreClass) + }; }; EpubCFI.prototype.pathTo = function(node, offset, ignoreClass) { - var segment = { - steps: [], - terminal: { - offset: null, - assertion: null - } - }; - var currentNode = node; - var step; + var segment = { + steps: [], + terminal: { + offset: null, + assertion: null + } + }; + var currentNode = node; + var step; - while(currentNode && currentNode.parentNode && - currentNode.parentNode.nodeType != Node.DOCUMENT_NODE) { + while(currentNode && currentNode.parentNode && + currentNode.parentNode.nodeType != Node.DOCUMENT_NODE) { - if (ignoreClass) { - step = this.filteredStep(currentNode, ignoreClass); - } else { - step = this.step(currentNode); - } + if (ignoreClass) { + step = this.filteredStep(currentNode, ignoreClass); + } else { + step = this.step(currentNode); + } - if (step) { - segment.steps.unshift(step); - } + if (step) { + segment.steps.unshift(step); + } - currentNode = currentNode.parentNode; + currentNode = currentNode.parentNode; - } + } - if (offset != null && offset >= 0) { + if (offset != null && offset >= 0) { - segment.terminal.offset = offset; + segment.terminal.offset = offset; - // Make sure we are getting to a textNode if there is an offset - if(segment.steps[segment.steps.length-1].type != "text") { - segment.steps.push({ - 'type' : "text", - 'index' : 0 - }); - } + // Make sure we are getting to a textNode if there is an offset + if(segment.steps[segment.steps.length-1].type != "text") { + segment.steps.push({ + 'type' : "text", + 'index' : 0 + }); + } - } + } - return segment; + return segment; } EpubCFI.prototype.equalStep = function(stepA, stepB) { - if (!stepA || !stepB) { - return false; - } + if (!stepA || !stepB) { + return false; + } - if(stepA.index === stepB.index && - stepA.id === stepB.id && - stepA.type === stepB.type) { - return true; - } + if(stepA.index === stepB.index && + stepA.id === stepB.id && + stepA.type === stepB.type) { + return true; + } - return false; + return false; }; EpubCFI.prototype.fromRange = function(range, base, ignoreClass) { - var cfi = { - range: false, - base: {}, - path: {}, - start: null, - end: null - }; + var cfi = { + range: false, + base: {}, + path: {}, + start: null, + end: null + }; - var start = range.startContainer; - var end = range.endContainer; + var start = range.startContainer; + var end = range.endContainer; - var startOffset = range.startOffset; - var endOffset = range.endOffset; + var startOffset = range.startOffset; + var endOffset = range.endOffset; - var needsIgnoring = false; + var needsIgnoring = false; - if (ignoreClass) { - // Tell pathTo if / what to ignore - needsIgnoring = (start.ownerDocument.querySelector('.' + ignoreClass) != null); - } + if (ignoreClass) { + // Tell pathTo if / what to ignore + needsIgnoring = (start.ownerDocument.querySelector('.' + ignoreClass) != null); + } - if (typeof base === 'string') { - cfi.base = this.parseComponent(base); - cfi.spinePos = cfi.base.steps[1].index; - } else if (typeof base === 'object') { - cfi.base = base; - } + if (typeof base === 'string') { + cfi.base = this.parseComponent(base); + cfi.spinePos = cfi.base.steps[1].index; + } else if (typeof base === 'object') { + cfi.base = base; + } - if (range.collapsed) { - if (needsIgnoring) { - startOffset = this.patchOffset(start, startOffset, ignoreClass); - } - cfi.path = this.pathTo(start, startOffset, ignoreClass); - } else { - cfi.range = true; + if (range.collapsed) { + if (needsIgnoring) { + startOffset = this.patchOffset(start, startOffset, ignoreClass); + } + cfi.path = this.pathTo(start, startOffset, ignoreClass); + } else { + cfi.range = true; - if (needsIgnoring) { - startOffset = this.patchOffset(start, startOffset, ignoreClass); - } + if (needsIgnoring) { + startOffset = this.patchOffset(start, startOffset, ignoreClass); + } - cfi.start = this.pathTo(start, startOffset, ignoreClass); + cfi.start = this.pathTo(start, startOffset, ignoreClass); - if (needsIgnoring) { - endOffset = this.patchOffset(end, endOffset, ignoreClass); - } + if (needsIgnoring) { + endOffset = this.patchOffset(end, endOffset, ignoreClass); + } - cfi.end = this.pathTo(end, endOffset, ignoreClass); + cfi.end = this.pathTo(end, endOffset, ignoreClass); - // Create a new empty path - cfi.path = { - steps: [], - terminal: null - }; + // Create a new empty path + cfi.path = { + steps: [], + terminal: null + }; - // Push steps that are shared between start and end to the common path - var len = cfi.start.steps.length; - var i; + // Push steps that are shared between start and end to the common path + var len = cfi.start.steps.length; + var i; - for (i = 0; i < len; i++) { - if (this.equalStep(cfi.start.steps[i], cfi.end.steps[i])) { - if(i == len-1) { - // Last step is equal, check terminals - if(cfi.start.terminal === cfi.end.terminal) { - // CFI's are equal - cfi.path.steps.push(cfi.start.steps[i]); - // Not a range - cfi.range = false; - } - } else { - cfi.path.steps.push(cfi.start.steps[i]); - } + for (i = 0; i < len; i++) { + if (this.equalStep(cfi.start.steps[i], cfi.end.steps[i])) { + if(i == len-1) { + // Last step is equal, check terminals + if(cfi.start.terminal === cfi.end.terminal) { + // CFI's are equal + cfi.path.steps.push(cfi.start.steps[i]); + // Not a range + cfi.range = false; + } + } else { + cfi.path.steps.push(cfi.start.steps[i]); + } - } else { - break; - } - }; + } else { + break; + } + }; - cfi.start.steps = cfi.start.steps.slice(cfi.path.steps.length); - cfi.end.steps = cfi.end.steps.slice(cfi.path.steps.length); + cfi.start.steps = cfi.start.steps.slice(cfi.path.steps.length); + cfi.end.steps = cfi.end.steps.slice(cfi.path.steps.length); - // TODO: Add Sanity check to make sure that the end if greater than the start - } + // TODO: Add Sanity check to make sure that the end if greater than the start + } - return cfi; + return cfi; } EpubCFI.prototype.fromNode = function(anchor, base, ignoreClass) { - var cfi = { - range: false, - base: {}, - path: {}, - start: null, - end: null - }; + var cfi = { + range: false, + base: {}, + path: {}, + start: null, + end: null + }; - var needsIgnoring = false; + var needsIgnoring = false; - if (ignoreClass) { - // Tell pathTo if / what to ignore - needsIgnoring = (anchor.ownerDocument.querySelector('.' + ignoreClass) != null); - } + if (ignoreClass) { + // Tell pathTo if / what to ignore + needsIgnoring = (anchor.ownerDocument.querySelector('.' + ignoreClass) != null); + } - if (typeof base === 'string') { - cfi.base = this.parseComponent(base); - cfi.spinePos = cfi.base.steps[1].index; - } else if (typeof base === 'object') { - cfi.base = base; - } + if (typeof base === 'string') { + cfi.base = this.parseComponent(base); + cfi.spinePos = cfi.base.steps[1].index; + } else if (typeof base === 'object') { + cfi.base = base; + } - cfi.path = this.pathTo(anchor, null, ignoreClass); + cfi.path = this.pathTo(anchor, null, ignoreClass); - return cfi; + return cfi; }; EpubCFI.prototype.filter = function(anchor, ignoreClass) { - var needsIgnoring; - var sibling; // to join with - var parent, prevSibling, nextSibling; - var isText = false; + var needsIgnoring; + var sibling; // to join with + var parent, prevSibling, nextSibling; + var isText = false; - if (anchor.nodeType === Node.TEXT_NODE) { - isText = true; - parent = anchor.parentNode; - needsIgnoring = anchor.parentNode.classList.contains(ignoreClass); - } else { - isText = false; - needsIgnoring = anchor.classList.contains(ignoreClass); - } + if (anchor.nodeType === Node.TEXT_NODE) { + isText = true; + parent = anchor.parentNode; + needsIgnoring = anchor.parentNode.classList.contains(ignoreClass); + } else { + isText = false; + needsIgnoring = anchor.classList.contains(ignoreClass); + } - if (needsIgnoring && isText) { - previousSibling = parent.previousSibling; - nextSibling = parent.nextSibling; + if (needsIgnoring && isText) { + previousSibling = parent.previousSibling; + nextSibling = parent.nextSibling; - // If the sibling is a text node, join the nodes - if (previousSibling && previousSibling.nodeType === Node.TEXT_NODE) { - sibling = previousSibling; - } else if (nextSibling && nextSibling.nodeType === Node.TEXT_NODE) { - sibling = nextSibling; - } + // If the sibling is a text node, join the nodes + if (previousSibling && previousSibling.nodeType === Node.TEXT_NODE) { + sibling = previousSibling; + } else if (nextSibling && nextSibling.nodeType === Node.TEXT_NODE) { + sibling = nextSibling; + } - if (sibling) { - return sibling; - } else { - // Parent will be ignored on next step - return anchor; - } + if (sibling) { + return sibling; + } else { + // Parent will be ignored on next step + return anchor; + } - } else if (needsIgnoring && !isText) { - // Otherwise just skip the element node - return false; - } else { - // No need to filter - return anchor; - } + } else if (needsIgnoring && !isText) { + // Otherwise just skip the element node + return false; + } else { + // No need to filter + return anchor; + } }; EpubCFI.prototype.patchOffset = function(anchor, offset, ignoreClass) { - var needsIgnoring; - var sibling; + var needsIgnoring; + var sibling; - if (anchor.nodeType != Node.TEXT_NODE) { - console.error("Anchor must be a text node"); - return; - } + if (anchor.nodeType != Node.TEXT_NODE) { + console.error("Anchor must be a text node"); + return; + } - var curr = anchor; - var totalOffset = offset; + var curr = anchor; + var totalOffset = offset; - // If the parent is a ignored node, get offset from it's start - if (anchor.parentNode.classList.contains(ignoreClass)) { - curr = anchor.parentNode; - } + // If the parent is a ignored node, get offset from it's start + if (anchor.parentNode.classList.contains(ignoreClass)) { + curr = anchor.parentNode; + } - while (curr.previousSibling) { - if(curr.previousSibling.nodeType === Node.ELEMENT_NODE) { - // Originally a text node, so join - if(curr.previousSibling.classList.contains(ignoreClass)){ - totalOffset += curr.previousSibling.textContent.length; - } else { - break; // Normal node, dont join - } - } else { - // If the previous sibling is a text node, join the nodes - totalOffset += curr.previousSibling.textContent.length; - } + while (curr.previousSibling) { + if(curr.previousSibling.nodeType === Node.ELEMENT_NODE) { + // Originally a text node, so join + if(curr.previousSibling.classList.contains(ignoreClass)){ + totalOffset += curr.previousSibling.textContent.length; + } else { + break; // Normal node, dont join + } + } else { + // If the previous sibling is a text node, join the nodes + totalOffset += curr.previousSibling.textContent.length; + } - curr = curr.previousSibling; - } + curr = curr.previousSibling; + } - return totalOffset; + return totalOffset; }; EpubCFI.prototype.normalizedMap = function(children, nodeType, ignoreClass) { - var output = {}; - var prevIndex = -1; - var i, len = children.length; - var currNodeType; - var prevNodeType; + var output = {}; + var prevIndex = -1; + var i, len = children.length; + var currNodeType; + var prevNodeType; - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) { - currNodeType = children[i].nodeType; + currNodeType = children[i].nodeType; - // Check if needs ignoring - if (currNodeType === Node.ELEMENT_NODE && - children[i].classList.contains(ignoreClass)) { - currNodeType = Node.TEXT_NODE; - } + // Check if needs ignoring + if (currNodeType === Node.ELEMENT_NODE && + children[i].classList.contains(ignoreClass)) { + currNodeType = Node.TEXT_NODE; + } - if (i > 0 && - currNodeType === Node.TEXT_NODE && - prevNodeType === Node.TEXT_NODE) { - // join text nodes - output[i] = prevIndex; - } else if (nodeType === currNodeType){ - prevIndex = prevIndex + 1; - output[i] = prevIndex; - } + if (i > 0 && + currNodeType === Node.TEXT_NODE && + prevNodeType === Node.TEXT_NODE) { + // join text nodes + output[i] = prevIndex; + } else if (nodeType === currNodeType){ + prevIndex = prevIndex + 1; + output[i] = prevIndex; + } - prevNodeType = currNodeType; + prevNodeType = currNodeType; - } + } - return output; + return output; }; EpubCFI.prototype.position = function(anchor) { - var children, index, map; + var children, index, map; - if (anchor.nodeType === Node.ELEMENT_NODE) { - children = anchor.parentNode.children; - index = Array.prototype.indexOf.call(children, anchor); - } else { - children = this.textNodes(anchor.parentNode); - index = children.indexOf(anchor); - } + if (anchor.nodeType === Node.ELEMENT_NODE) { + children = anchor.parentNode.children; + index = Array.prototype.indexOf.call(children, anchor); + } else { + children = this.textNodes(anchor.parentNode); + index = children.indexOf(anchor); + } - return index; + return index; }; EpubCFI.prototype.filteredPosition = function(anchor, ignoreClass) { - var children, index, map; + var children, index, map; - if (anchor.nodeType === Node.ELEMENT_NODE) { - children = anchor.parentNode.children; - map = this.normalizedMap(children, Node.ELEMENT_NODE, ignoreClass); - } else { - children = anchor.parentNode.childNodes; - // Inside an ignored node - if(anchor.parentNode.classList.contains(ignoreClass)) { - anchor = anchor.parentNode; - children = anchor.parentNode.childNodes; - } - map = this.normalizedMap(children, Node.TEXT_NODE, ignoreClass); - } + if (anchor.nodeType === Node.ELEMENT_NODE) { + children = anchor.parentNode.children; + map = this.normalizedMap(children, Node.ELEMENT_NODE, ignoreClass); + } else { + children = anchor.parentNode.childNodes; + // Inside an ignored node + if(anchor.parentNode.classList.contains(ignoreClass)) { + anchor = anchor.parentNode; + children = anchor.parentNode.childNodes; + } + map = this.normalizedMap(children, Node.TEXT_NODE, ignoreClass); + } - index = Array.prototype.indexOf.call(children, anchor); + index = Array.prototype.indexOf.call(children, anchor); - return map[index]; + return map[index]; }; EpubCFI.prototype.stepsToXpath = function(steps) { - var xpath = [".", "*"]; + var xpath = [".", "*"]; - steps.forEach(function(step){ - var position = step.index + 1; + steps.forEach(function(step){ + var position = step.index + 1; - if(step.id){ - xpath.push("*[position()=" + position + " and @id='" + step.id + "']"); - } else if(step.type === "text") { - xpath.push("text()[" + position + "]"); - } else { - xpath.push("*[" + position + "]"); - } - }); + if(step.id){ + xpath.push("*[position()=" + position + " and @id='" + step.id + "']"); + } else if(step.type === "text") { + xpath.push("text()[" + position + "]"); + } else { + xpath.push("*[" + position + "]"); + } + }); - return xpath.join("/"); + return xpath.join("/"); }; @@ -741,198 +741,198 @@ query = this.stepsToQuery(steps); startContainerParent = doc.querySelector(query); // Find the text node within that element if(startContainerParent && lastStep.type == "text") { - container = startContainerParent.childNodes[lastStep.index]; + container = startContainerParent.childNodes[lastStep.index]; } */ EpubCFI.prototype.stepsToQuerySelector = function(steps) { - var query = ["html"]; + var query = ["html"]; - steps.forEach(function(step){ - var position = step.index + 1; + steps.forEach(function(step){ + var position = step.index + 1; - if(step.id){ - query.push("#" + step.id); - } else if(step.type === "text") { - // unsupported in querySelector - // query.push("text()[" + position + "]"); - } else { - query.push("*:nth-child(" + position + ")"); - } - }); + if(step.id){ + query.push("#" + step.id); + } else if(step.type === "text") { + // unsupported in querySelector + // query.push("text()[" + position + "]"); + } else { + query.push("*:nth-child(" + position + ")"); + } + }); - return query.join(">"); + return query.join(">"); }; EpubCFI.prototype.textNodes = function(container, ignoreClass) { - return Array.prototype.slice.call(container.childNodes). - filter(function (node) { - if (node.nodeType === Node.TEXT_NODE) { - return true; - } else if (ignoreClass && node.classList.contains(ignoreClass)) { - return true; - } - return false; - }); + return Array.prototype.slice.call(container.childNodes). + filter(function (node) { + if (node.nodeType === Node.TEXT_NODE) { + return true; + } else if (ignoreClass && node.classList.contains(ignoreClass)) { + return true; + } + return false; + }); }; EpubCFI.prototype.walkToNode = function(steps, _doc, ignoreClass) { - var doc = _doc || document; - var container = doc.documentElement; - var step; - var len = steps.length; - var i; + var doc = _doc || document; + var container = doc.documentElement; + var step; + var len = steps.length; + var i; - for (i = 0; i < len; i++) { - step = steps[i]; + for (i = 0; i < len; i++) { + step = steps[i]; - if(step.type === "element") { - container = container.children[step.index]; - } else if(step.type === "text"){ - container = this.textNodes(container, ignoreClass)[step.index]; - } + if(step.type === "element") { + container = container.children[step.index]; + } else if(step.type === "text"){ + container = this.textNodes(container, ignoreClass)[step.index]; + } - }; + }; - return container; + return container; }; EpubCFI.prototype.findNode = function(steps, _doc, ignoreClass) { - var doc = _doc || document; - var container; - var xpath; + var doc = _doc || document; + var container; + var xpath; - if(!ignoreClass && typeof doc.evaluate != 'undefined') { - xpath = this.stepsToXpath(steps); - container = doc.evaluate(xpath, doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; - } else if(ignoreClass) { - container = this.walkToNode(steps, doc, ignoreClass); - } else { - container = this.walkToNode(steps, doc); - } + if(!ignoreClass && typeof doc.evaluate != 'undefined') { + xpath = this.stepsToXpath(steps); + container = doc.evaluate(xpath, doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; + } else if(ignoreClass) { + container = this.walkToNode(steps, doc, ignoreClass); + } else { + container = this.walkToNode(steps, doc); + } - return container; + return container; }; EpubCFI.prototype.fixMiss = function(steps, offset, _doc, ignoreClass) { - var container = this.findNode(steps.slice(0,-1), _doc, ignoreClass); - var children = container.childNodes; - var map = this.normalizedMap(children, Node.TEXT_NODE, ignoreClass); - var i; - var child; - var len; - var childIndex; - var lastStepIndex = steps[steps.length-1].index; + var container = this.findNode(steps.slice(0,-1), _doc, ignoreClass); + var children = container.childNodes; + var map = this.normalizedMap(children, Node.TEXT_NODE, ignoreClass); + var i; + var child; + var len; + var childIndex; + var lastStepIndex = steps[steps.length-1].index; - for (var childIndex in map) { - if (!map.hasOwnProperty(childIndex)) return; + for (var childIndex in map) { + if (!map.hasOwnProperty(childIndex)) return; - if(map[childIndex] === lastStepIndex) { - child = children[childIndex]; - len = child.textContent.length; - if(offset > len) { - offset = offset - len; - } else { - if (child.nodeType === Node.ELEMENT_NODE) { - container = child.childNodes[0]; - } else { - container = child; - } - break; - } - } - } + if(map[childIndex] === lastStepIndex) { + child = children[childIndex]; + len = child.textContent.length; + if(offset > len) { + offset = offset - len; + } else { + if (child.nodeType === Node.ELEMENT_NODE) { + container = child.childNodes[0]; + } else { + container = child; + } + break; + } + } + } - return { - container: container, - offset: offset - }; + return { + container: container, + offset: offset + }; }; EpubCFI.prototype.toRange = function(_doc, ignoreClass) { - var doc = _doc || document; - var range = doc.createRange(); - var start, end, startContainer, endContainer; - var cfi = this; - var startSteps, endSteps; - var needsIgnoring = ignoreClass ? (doc.querySelector('.' + ignoreClass) != null) : false; - var missed; + var doc = _doc || document; + var range = doc.createRange(); + var start, end, startContainer, endContainer; + var cfi = this; + var startSteps, endSteps; + var needsIgnoring = ignoreClass ? (doc.querySelector('.' + ignoreClass) != null) : false; + var missed; - if (cfi.range) { - start = cfi.start; - startSteps = cfi.path.steps.concat(start.steps); - startContainer = this.findNode(startSteps, doc, needsIgnoring ? ignoreClass : null); - end = cfi.end; - endSteps = cfi.path.steps.concat(end.steps); - endContainer = this.findNode(endSteps, doc, needsIgnoring ? ignoreClass : null); - } else { - start = cfi.path; - startSteps = cfi.path.steps; - startContainer = this.findNode(cfi.path.steps, doc, needsIgnoring ? ignoreClass : null); - } + if (cfi.range) { + start = cfi.start; + startSteps = cfi.path.steps.concat(start.steps); + startContainer = this.findNode(startSteps, doc, needsIgnoring ? ignoreClass : null); + end = cfi.end; + endSteps = cfi.path.steps.concat(end.steps); + endContainer = this.findNode(endSteps, doc, needsIgnoring ? ignoreClass : null); + } else { + start = cfi.path; + startSteps = cfi.path.steps; + startContainer = this.findNode(cfi.path.steps, doc, needsIgnoring ? ignoreClass : null); + } - if(startContainer) { - try { + if(startContainer) { + try { - if(start.terminal.offset != null) { - range.setStart(startContainer, start.terminal.offset); - } else { - range.setStart(startContainer, 0); - } + if(start.terminal.offset != null) { + range.setStart(startContainer, start.terminal.offset); + } else { + range.setStart(startContainer, 0); + } - } catch (e) { - missed = this.fixMiss(startSteps, start.terminal.offset, doc, needsIgnoring ? ignoreClass : null); - range.setStart(missed.container, missed.offset); - } - } else { - // No start found - return null; - } + } catch (e) { + missed = this.fixMiss(startSteps, start.terminal.offset, doc, needsIgnoring ? ignoreClass : null); + range.setStart(missed.container, missed.offset); + } + } else { + // No start found + return null; + } - if (endContainer) { - try { + if (endContainer) { + try { - if(end.terminal.offset != null) { - range.setEnd(endContainer, end.terminal.offset); - } else { - range.setEnd(endContainer, 0); - } + if(end.terminal.offset != null) { + range.setEnd(endContainer, end.terminal.offset); + } else { + range.setEnd(endContainer, 0); + } - } catch (e) { - missed = this.fixMiss(endSteps, cfi.end.terminal.offset, doc, needsIgnoring ? ignoreClass : null); - range.setEnd(missed.container, missed.offset); - } - } + } catch (e) { + missed = this.fixMiss(endSteps, cfi.end.terminal.offset, doc, needsIgnoring ? ignoreClass : null); + range.setEnd(missed.container, missed.offset); + } + } - // doc.defaultView.getSelection().addRange(range); - return range; + // doc.defaultView.getSelection().addRange(range); + return range; }; // is a cfi string, should be wrapped with "epubcfi()" EpubCFI.prototype.isCfiString = function(str) { - if(typeof str === 'string' && - str.indexOf("epubcfi(") === 0 && - str[str.length-1] === ")") { - return true; - } + if(typeof str === 'string' && + str.indexOf("epubcfi(") === 0 && + str[str.length-1] === ")") { + return true; + } - return false; + return false; }; EpubCFI.prototype.generateChapterComponent = function(_spineNodeIndex, _pos, id) { - var pos = parseInt(_pos), - spineNodeIndex = _spineNodeIndex + 1, - cfi = '/'+spineNodeIndex+'/'; + var pos = parseInt(_pos), + spineNodeIndex = _spineNodeIndex + 1, + cfi = '/'+spineNodeIndex+'/'; - cfi += (pos + 1) * 2; + cfi += (pos + 1) * 2; - if(id) { - cfi += "[" + id + "]"; - } + if(id) { + cfi += "[" + id + "]"; + } - return cfi; + return cfi; }; module.exports = EpubCFI; diff --git a/src/hook.js b/src/hook.js index 9ed482d..b115e86 100644 --- a/src/hook.js +++ b/src/hook.js @@ -9,51 +9,51 @@ var RSVP = require('rsvp'); // this.content.trigger(args).then(function(){}); function Hook(context){ - this.context = context || this; - this.hooks = []; + this.context = context || this; + this.hooks = []; }; // Adds a function to be run before a hook completes Hook.prototype.register = function(){ - for(var i = 0; i < arguments.length; ++i) { - if (typeof arguments[i] === "function") { - this.hooks.push(arguments[i]); - } else { - // unpack array - for(var j = 0; j < arguments[i].length; ++j) { - this.hooks.push(arguments[i][j]); - } - } - } + for(var i = 0; i < arguments.length; ++i) { + if (typeof arguments[i] === "function") { + this.hooks.push(arguments[i]); + } else { + // unpack array + for(var j = 0; j < arguments[i].length; ++j) { + this.hooks.push(arguments[i][j]); + } + } + } }; // Triggers a hook to run all functions Hook.prototype.trigger = function(){ - var args = arguments; - var context = this.context; - var promises = []; + var args = arguments; + var context = this.context; + var promises = []; - this.hooks.forEach(function(task, i) { - var executing = task.apply(context, args); + this.hooks.forEach(function(task, i) { + var executing = task.apply(context, args); - if(executing && typeof executing["then"] === "function") { - // Task is a function that returns a promise - promises.push(executing); - } - // Otherwise Task resolves immediately, continue - }); + if(executing && typeof executing["then"] === "function") { + // Task is a function that returns a promise + promises.push(executing); + } + // Otherwise Task resolves immediately, continue + }); - return RSVP.all(promises); + return RSVP.all(promises); }; // Adds a function to be run before a hook completes Hook.prototype.list = function(){ - return this.hooks; + return this.hooks; }; Hook.prototype.clear = function(){ - return this.hooks = []; + return this.hooks = []; }; module.exports = Hook; diff --git a/src/layout.js b/src/layout.js index aa1559c..426cb98 100644 --- a/src/layout.js +++ b/src/layout.js @@ -2,120 +2,120 @@ var core = require('./core'); var RSVP = require('rsvp'); function Layout(settings){ - this.name = settings.layout || "reflowable"; - this._spread = (settings.spread === "none") ? false : true; - this._minSpreadWidth = settings.spread || 800; - this._evenSpreads = settings.evenSpreads || false; + this.name = settings.layout || "reflowable"; + this._spread = (settings.spread === "none") ? false : true; + this._minSpreadWidth = settings.spread || 800; + this._evenSpreads = settings.evenSpreads || false; - if (settings.flow === "scrolled-continuous" || - settings.flow === "scrolled-doc") { - this._flow = "scrolled"; - } else { - this._flow = "paginated"; - } + if (settings.flow === "scrolled-continuous" || + settings.flow === "scrolled-doc") { + this._flow = "scrolled"; + } else { + this._flow = "paginated"; + } - this.width = 0; - this.height = 0; - this.spreadWidth = 0; - this.delta = 0; + this.width = 0; + this.height = 0; + this.spreadWidth = 0; + this.delta = 0; - this.columnWidth = 0; - this.gap = 0; - this.divisor = 1; + this.columnWidth = 0; + this.gap = 0; + this.divisor = 1; }; // paginated | scrolled Layout.prototype.flow = function(flow) { - this._flow = (flow === "paginated") ? "paginated" : "scrolled"; + this._flow = (flow === "paginated") ? "paginated" : "scrolled"; } // true | false Layout.prototype.spread = function(spread, min) { - this._spread = (spread === "none") ? false : true; + this._spread = (spread === "none") ? false : true; - if (min >= 0) { - this._minSpreadWidth = min; - } + if (min >= 0) { + this._minSpreadWidth = min; + } } Layout.prototype.calculate = function(_width, _height, _gap){ - var divisor = 1; - var gap = _gap || 0; + var divisor = 1; + var gap = _gap || 0; - //-- Check the width and create even width columns - var fullWidth = Math.floor(_width); - var width = _width; + //-- Check the width and create even width columns + var fullWidth = Math.floor(_width); + var width = _width; - var section = Math.floor(width / 8); + var section = Math.floor(width / 8); - var colWidth; - var spreadWidth; - var delta; + var colWidth; + var spreadWidth; + var delta; - if (this._spread && width >= this._minSpreadWidth) { - divisor = 2; - } else { - divisor = 1; - } + if (this._spread && width >= this._minSpreadWidth) { + divisor = 2; + } else { + divisor = 1; + } - if (this.name === "reflowable" && this._flow === "paginated" && !(_gap >= 0)) { - gap = ((section % 2 === 0) ? section : section - 1); - } + if (this.name === "reflowable" && this._flow === "paginated" && !(_gap >= 0)) { + gap = ((section % 2 === 0) ? section : section - 1); + } - if (this.name === "pre-paginated" ) { - gap = 0; - } + if (this.name === "pre-paginated" ) { + gap = 0; + } - //-- Double Page - if(divisor > 1) { - colWidth = Math.floor((width - gap) / divisor); - } else { - colWidth = width; - } + //-- Double Page + if(divisor > 1) { + colWidth = Math.floor((width - gap) / divisor); + } else { + colWidth = width; + } - if (this.name === "pre-paginated" && divisor > 1) { - width = colWidth; - } + if (this.name === "pre-paginated" && divisor > 1) { + width = colWidth; + } - spreadWidth = colWidth * divisor; + spreadWidth = colWidth * divisor; - delta = (colWidth + gap) * divisor; + delta = (colWidth + gap) * divisor; - this.width = width; - this.height = _height; - this.spreadWidth = spreadWidth; - this.delta = delta; + this.width = width; + this.height = _height; + this.spreadWidth = spreadWidth; + this.delta = delta; - this.columnWidth = colWidth; - this.gap = gap; - this.divisor = divisor; + this.columnWidth = colWidth; + this.gap = gap; + this.divisor = divisor; }; Layout.prototype.format = function(contents){ - var formating; + var formating; - if (this.name === "pre-paginated") { - formating = contents.fit(this.columnWidth, this.height); - } else if (this._flow === "paginated") { - formating = contents.columns(this.width, this.height, this.columnWidth, this.gap); - } else { // scrolled - formating = contents.size(this.width, null); - } + if (this.name === "pre-paginated") { + formating = contents.fit(this.columnWidth, this.height); + } else if (this._flow === "paginated") { + formating = contents.columns(this.width, this.height, this.columnWidth, this.gap); + } else { // scrolled + formating = contents.size(this.width, null); + } - return formating; // might be a promise in some View Managers + return formating; // might be a promise in some View Managers }; Layout.prototype.count = function(totalWidth) { - // var totalWidth = contents.scrollWidth(); - var spreads = Math.ceil( totalWidth / this.spreadWidth); + // var totalWidth = contents.scrollWidth(); + var spreads = Math.ceil( totalWidth / this.spreadWidth); - return { - spreads : spreads, - pages : spreads * this.divisor - }; + return { + spreads : spreads, + pages : spreads * this.divisor + }; }; module.exports = Layout; diff --git a/src/locations.js b/src/locations.js index 041b0c9..7fc5ed4 100644 --- a/src/locations.js +++ b/src/locations.js @@ -4,114 +4,114 @@ var EpubCFI = require('./epubcfi'); var RSVP = require('rsvp'); function Locations(spine, request) { - this.spine = spine; - this.request = request; + this.spine = spine; + this.request = request; - this.q = new Queue(this); - this.epubcfi = new EpubCFI(); + this.q = new Queue(this); + this.epubcfi = new EpubCFI(); - this._locations = []; - this.total = 0; + this._locations = []; + this.total = 0; - this.break = 150; + this.break = 150; - this._current = 0; + this._current = 0; }; // Load all of sections in the book Locations.prototype.generate = function(chars) { - if (chars) { - this.break = chars; - } + if (chars) { + this.break = chars; + } - this.q.pause(); + this.q.pause(); - this.spine.each(function(section) { + this.spine.each(function(section) { - this.q.enqueue(this.process, section); + this.q.enqueue(this.process, section); - }.bind(this)); + }.bind(this)); - return this.q.run().then(function() { - this.total = this._locations.length-1; + return this.q.run().then(function() { + this.total = this._locations.length-1; - if (this._currentCfi) { - this.currentLocation = this._currentCfi; - } + if (this._currentCfi) { + this.currentLocation = this._currentCfi; + } - return this._locations; - // console.log(this.precentage(this.book.rendition.location.start), this.precentage(this.book.rendition.location.end)); - }.bind(this)); + return this._locations; + // console.log(this.precentage(this.book.rendition.location.start), this.precentage(this.book.rendition.location.end)); + }.bind(this)); }; Locations.prototype.process = function(section) { - return section.load(this.request) - .then(function(contents) { + return section.load(this.request) + .then(function(contents) { - var range; - var doc = contents.ownerDocument; - var counter = 0; + var range; + var doc = contents.ownerDocument; + var counter = 0; - this.sprint(contents, function(node) { - var len = node.length; - var dist; - var pos = 0; + this.sprint(contents, function(node) { + var len = node.length; + var dist; + var pos = 0; - // Start range - if (counter == 0) { - range = doc.createRange(); - range.setStart(node, 0); - } + // Start range + if (counter == 0) { + range = doc.createRange(); + range.setStart(node, 0); + } - dist = this.break - counter; + dist = this.break - counter; - // Node is smaller than a break - if(dist > len){ - counter += len; - pos = len; - } + // Node is smaller than a break + if(dist > len){ + counter += len; + pos = len; + } - while (pos < len) { - counter = this.break; - pos += this.break; + while (pos < len) { + counter = this.break; + pos += this.break; - // Gone over - if(pos >= len){ - // Continue counter for next node - counter = len - (pos - this.break); + // Gone over + if(pos >= len){ + // Continue counter for next node + counter = len - (pos - this.break); - // At End - } else { - // End the previous range - range.setEnd(node, pos); - cfi = section.cfiFromRange(range); - this._locations.push(cfi); - counter = 0; + // At End + } else { + // End the previous range + range.setEnd(node, pos); + cfi = section.cfiFromRange(range); + this._locations.push(cfi); + counter = 0; - // Start new range - pos += 1; - range = doc.createRange(); - range.setStart(node, pos); - } - } + // Start new range + pos += 1; + range = doc.createRange(); + range.setStart(node, pos); + } + } - }.bind(this)); + }.bind(this)); - // Close remaining - if (range) { - range.setEnd(prev, prev.length); - cfi = section.cfiFromRange(range); - this._locations.push(cfi) - counter = 0; - } + // Close remaining + if (range) { + range.setEnd(prev, prev.length); + cfi = section.cfiFromRange(range); + this._locations.push(cfi) + counter = 0; + } - }.bind(this)); + }.bind(this)); }; @@ -125,26 +125,26 @@ Locations.prototype.sprint = function(root, func) { }; Locations.prototype.locationFromCfi = function(cfi){ - // Check if the location has not been set yet + // Check if the location has not been set yet if(this._locations.length === 0) { return -1; } - return core.locationOf(cfi, this._locations, this.epubcfi.compare); + return core.locationOf(cfi, this._locations, this.epubcfi.compare); }; Locations.prototype.precentageFromCfi = function(cfi) { - // Find closest cfi - var loc = this.locationFromCfi(cfi); - // Get percentage in total - return this.precentageFromLocation(loc); + // Find closest cfi + var loc = this.locationFromCfi(cfi); + // Get percentage in total + return this.precentageFromLocation(loc); }; Locations.prototype.percentageFromLocation = function(loc) { - if (!loc || !this.total) { - return 0; - } - return (loc / this.total); + if (!loc || !this.total) { + return 0; + } + return (loc / this.total); }; Locations.prototype.cfiFromLocation = function(loc){ @@ -162,7 +162,7 @@ Locations.prototype.cfiFromLocation = function(loc){ }; Locations.prototype.cfiFromPercentage = function(value){ - var percentage = (value > 1) ? value / 100 : value; // Normalize value to 0-1 + var percentage = (value > 1) ? value / 100 : value; // Normalize value to 0-1 var loc = Math.ceil(this.total * percentage); return this.cfiFromLocation(loc); @@ -170,8 +170,8 @@ Locations.prototype.cfiFromPercentage = function(value){ Locations.prototype.load = function(locations){ this._locations = JSON.parse(locations); - this.total = this._locations.length-1; - return this._locations; + this.total = this._locations.length-1; + return this._locations; }; Locations.prototype.save = function(json){ @@ -183,39 +183,39 @@ Locations.prototype.getCurrent = function(json){ }; Locations.prototype.setCurrent = function(curr){ - var loc; + var loc; - if(typeof curr == "string"){ - this._currentCfi = curr; - } else if (typeof curr == "number") { - this._current = curr; - } else { - return; - } - - if(this._locations.length === 0) { - return; + if(typeof curr == "string"){ + this._currentCfi = curr; + } else if (typeof curr == "number") { + this._current = curr; + } else { + return; } - if(typeof curr == "string"){ - loc = this.locationFromCfi(curr); - this._current = loc; - } else { - loc = curr; - } + if(this._locations.length === 0) { + return; + } - this.trigger("changed", { - percentage: this.precentageFromLocation(loc) - }); + if(typeof curr == "string"){ + loc = this.locationFromCfi(curr); + this._current = loc; + } else { + loc = curr; + } + + this.trigger("changed", { + percentage: this.precentageFromLocation(loc) + }); }; Object.defineProperty(Locations.prototype, 'currentLocation', { - get: function () { - return this._current; - }, - set: function (curr) { - this.setCurrent(curr); - } + get: function () { + return this._current; + }, + set: function (curr) { + this.setCurrent(curr); + } }); RSVP.EventTarget.mixin(Locations.prototype); diff --git a/src/managers/continuous.js b/src/managers/continuous.js index a0899cc..0ae1c98 100644 --- a/src/managers/continuous.js +++ b/src/managers/continuous.js @@ -21,9 +21,9 @@ function ContinuousViewManager(options) { core.extend(this.settings, options.settings || {}); // Gap can be 0, byt defaults doesn't handle that - if (options.settings.gap != "undefined" && options.settings.gap === 0) { - this.settings.gap = options.settings.gap; - } + if (options.settings.gap != "undefined" && options.settings.gap === 0) { + this.settings.gap = options.settings.gap; + } // this.viewSettings.axis = this.settings.axis; this.viewSettings = { @@ -43,7 +43,7 @@ ContinuousViewManager.prototype = Object.create(SingleViewManager.prototype); ContinuousViewManager.prototype.constructor = ContinuousViewManager; ContinuousViewManager.prototype.display = function(section, target){ - return SingleViewManager.prototype.display.call(this, section, target) + return SingleViewManager.prototype.display.call(this, section, target) .then(function () { return this.fill(); }.bind(this)); @@ -64,8 +64,8 @@ ContinuousViewManager.prototype.fill = function(_full){ } ContinuousViewManager.prototype.moveTo = function(offset){ - // var bounds = this.stage.bounds(); - // var dist = Math.floor(offset.top / bounds.height) * bounds.height; + // var bounds = this.stage.bounds(); + // var dist = Math.floor(offset.top / bounds.height) * bounds.height; var distX = 0, distY = 0; @@ -80,10 +80,10 @@ ContinuousViewManager.prototype.moveTo = function(offset){ offsetX = distX+this.settings.offset; } - return this.check(offsetX, offsetY) + return this.check(offsetX, offsetY) .then(function(){ - this.scrollBy(distX, distY); - }.bind(this)); + this.scrollBy(distX, distY); + }.bind(this)); }; /* @@ -113,7 +113,7 @@ ContinuousViewManager.prototype.afterDisplayed = function(currView){ ContinuousViewManager.prototype.resize = function(width, height){ // Clear the queue - this.q.clear(); + this.q.clear(); this._stageSize = this.stage.size(width, height); this._bounds = this.bounds(); @@ -127,27 +127,27 @@ ContinuousViewManager.prototype.resize = function(width, height){ view.size(this._stageSize.width, this._stageSize.height); }.bind(this)); - this.updateLayout(); + this.updateLayout(); - // if(this.location) { - // this.rendition.display(this.location.start); - // } + // if(this.location) { + // this.rendition.display(this.location.start); + // } - this.trigger("resized", { - width: this.stage.width, - height: this.stage.height - }); + this.trigger("resized", { + width: this.stage.width, + height: this.stage.height + }); }; ContinuousViewManager.prototype.onResized = function(e) { - // this.views.clear(); + // this.views.clear(); - clearTimeout(this.resizeTimeout); - this.resizeTimeout = setTimeout(function(){ - this.resize(); - }.bind(this), 150); + clearTimeout(this.resizeTimeout); + this.resizeTimeout = setTimeout(function(){ + this.resize(); + }.bind(this), 150); }; ContinuousViewManager.prototype.afterResized = function(view){ @@ -220,34 +220,34 @@ ContinuousViewManager.prototype.update = function(_offset){ var promises = []; for (var i = 0; i < viewsLength; i++) { - view = views[i]; + view = views[i]; - isVisible = this.isVisible(view, offset, offset, container); + isVisible = this.isVisible(view, offset, offset, container); - if(isVisible === true) { + if(isVisible === true) { if (!view.displayed) { promises.push(view.display(this.request).then(function (view) { view.show(); })); } - visible.push(view); - } else { + visible.push(view); + } else { this.q.enqueue(view.destroy.bind(view)); clearTimeout(this.trimTimeout); this.trimTimeout = setTimeout(function(){ this.q.enqueue(this.trim.bind(this)); }.bind(this), 250); - } + } - } + } if(promises.length){ - return RSVP.all(promises); - } else { - updating.resolve(); - return updating.promise; - } + return RSVP.all(promises); + } else { + updating.resolve(); + return updating.promise; + } }; @@ -276,61 +276,61 @@ ContinuousViewManager.prototype.check = function(_offsetLeft, _offsetTop){ if (offset + visibleLength + delta >= contentLength) { last = this.views.last(); - next = last && last.section.next(); - if(next) { - newViews.push(this.append(next)); - } - } + next = last && last.section.next(); + if(next) { + newViews.push(this.append(next)); + } + } - if (offset - delta < 0 ) { + if (offset - delta < 0 ) { first = this.views.first(); - prev = first && first.section.prev(); - if(prev) { - newViews.push(this.prepend(prev)); - } - } + prev = first && first.section.prev(); + if(prev) { + newViews.push(this.prepend(prev)); + } + } - if(newViews.length){ - // RSVP.all(promises) - // .then(function() { - // Check to see if anything new is on screen after rendering - return this.q.enqueue(function(){ + if(newViews.length){ + // RSVP.all(promises) + // .then(function() { + // Check to see if anything new is on screen after rendering + return this.q.enqueue(function(){ return this.update(delta); }.bind(this)); - // }.bind(this)); + // }.bind(this)); - } else { - checking.resolve(false); + } else { + checking.resolve(false); return checking.promise; - } + } }; ContinuousViewManager.prototype.trim = function(){ - var task = new RSVP.defer(); - var displayed = this.views.displayed(); - var first = displayed[0]; - var last = displayed[displayed.length-1]; - var firstIndex = this.views.indexOf(first); - var lastIndex = this.views.indexOf(last); - var above = this.views.slice(0, firstIndex); - var below = this.views.slice(lastIndex+1); + var task = new RSVP.defer(); + var displayed = this.views.displayed(); + var first = displayed[0]; + var last = displayed[displayed.length-1]; + var firstIndex = this.views.indexOf(first); + var lastIndex = this.views.indexOf(last); + var above = this.views.slice(0, firstIndex); + var below = this.views.slice(lastIndex+1); - // Erase all but last above - for (var i = 0; i < above.length-1; i++) { - this.erase(above[i], above); - } + // Erase all but last above + for (var i = 0; i < above.length-1; i++) { + this.erase(above[i], above); + } - // Erase all except first below - for (var j = 1; j < below.length; j++) { - this.erase(below[j]); - } + // Erase all except first below + for (var j = 1; j < below.length; j++) { + this.erase(below[j]); + } - task.resolve(); - return task.promise; + task.resolve(); + return task.promise; }; ContinuousViewManager.prototype.erase = function(view, above){ //Trim @@ -339,12 +339,12 @@ ContinuousViewManager.prototype.erase = function(view, above){ //Trim var prevLeft; if(this.settings.height) { - prevTop = this.container.scrollTop; + prevTop = this.container.scrollTop; prevLeft = this.container.scrollLeft; - } else { - prevTop = window.scrollY; + } else { + prevTop = window.scrollY; prevLeft = window.scrollX; - } + } var bounds = view.bounds(); @@ -373,60 +373,60 @@ ContinuousViewManager.prototype.addEventListeners = function(stage){ }; ContinuousViewManager.prototype.addScrollListeners = function() { - var scroller; + var scroller; - this.tick = core.requestAnimationFrame; + this.tick = core.requestAnimationFrame; - if(this.settings.height) { - this.prevScrollTop = this.container.scrollTop; - this.prevScrollLeft = this.container.scrollLeft; - } else { - this.prevScrollTop = window.scrollY; + if(this.settings.height) { + this.prevScrollTop = this.container.scrollTop; + this.prevScrollLeft = this.container.scrollLeft; + } else { + this.prevScrollTop = window.scrollY; this.prevScrollLeft = window.scrollX; - } + } - this.scrollDeltaVert = 0; - this.scrollDeltaHorz = 0; + this.scrollDeltaVert = 0; + this.scrollDeltaHorz = 0; - if(this.settings.height) { - scroller = this.container; + if(this.settings.height) { + scroller = this.container; this.scrollTop = this.container.scrollTop; this.scrollLeft = this.container.scrollLeft; - } else { - scroller = window; + } else { + scroller = window; this.scrollTop = window.scrollY; this.scrollLeft = window.scrollX; - } + } - scroller.addEventListener("scroll", this.onScroll.bind(this)); + scroller.addEventListener("scroll", this.onScroll.bind(this)); - // this.tick.call(window, this.onScroll.bind(this)); + // this.tick.call(window, this.onScroll.bind(this)); - this.scrolled = false; + this.scrolled = false; }; ContinuousViewManager.prototype.onScroll = function(){ - // if(!this.ignore) { + // if(!this.ignore) { - if(this.settings.height) { - scrollTop = this.container.scrollTop; - scrollLeft = this.container.scrollLeft; - } else { - scrollTop = window.scrollY; + if(this.settings.height) { + scrollTop = this.container.scrollTop; + scrollLeft = this.container.scrollLeft; + } else { + scrollTop = window.scrollY; scrollLeft = window.scrollX; - } + } this.scrollTop = scrollTop; this.scrollLeft = scrollLeft; - if(!this.ignore) { + if(!this.ignore) { - if((this.scrollDeltaVert === 0 && - this.scrollDeltaHorz === 0) || - this.scrollDeltaVert > this.settings.offsetDelta || - this.scrollDeltaHorz > this.settings.offsetDelta) { + if((this.scrollDeltaVert === 0 && + this.scrollDeltaHorz === 0) || + this.scrollDeltaVert > this.settings.offsetDelta || + this.scrollDeltaHorz > this.settings.offsetDelta) { this.q.enqueue(function() { this.check(); @@ -434,44 +434,44 @@ ContinuousViewManager.prototype.onScroll = function(){ // this.check(); this.scrollDeltaVert = 0; - this.scrollDeltaHorz = 0; + this.scrollDeltaHorz = 0; this.trigger("scroll", { - top: scrollTop, - left: scrollLeft - }); + top: scrollTop, + left: scrollLeft + }); clearTimeout(this.afterScrolled); this.afterScrolled = setTimeout(function () { this.trigger("scrolled", { - top: this.scrollTop, - left: this.scrollLeft - }); + top: this.scrollTop, + left: this.scrollLeft + }); }.bind(this)); } } else { - this.ignore = false; + this.ignore = false; } - this.scrollDeltaVert += Math.abs(scrollTop-this.prevScrollTop); - this.scrollDeltaHorz += Math.abs(scrollLeft-this.prevScrollLeft); + this.scrollDeltaVert += Math.abs(scrollTop-this.prevScrollTop); + this.scrollDeltaHorz += Math.abs(scrollLeft-this.prevScrollLeft); this.prevScrollTop = scrollTop; this.prevScrollLeft = scrollLeft; - clearTimeout(this.scrollTimeout); + clearTimeout(this.scrollTimeout); this.scrollTimeout = setTimeout(function(){ this.scrollDeltaVert = 0; - this.scrollDeltaHorz = 0; + this.scrollDeltaHorz = 0; }.bind(this), 150); - this.scrolled = false; - // } + this.scrolled = false; + // } - // this.tick.call(window, this.onScroll.bind(this)); + // this.tick.call(window, this.onScroll.bind(this)); }; @@ -488,9 +488,9 @@ ContinuousViewManager.prototype.onScroll = function(){ ContinuousViewManager.prototype.currentLocation = function(){ - if (this.settings.axis === "vertical") { - this.location = this.scrolledLocation(); - } else { + if (this.settings.axis === "vertical") { + this.location = this.scrolledLocation(); + } else { this.location = this.paginatedLocation(); } @@ -499,104 +499,104 @@ ContinuousViewManager.prototype.currentLocation = function(){ ContinuousViewManager.prototype.scrolledLocation = function(){ - var visible = this.visible(); - var startPage, endPage; + var visible = this.visible(); + var startPage, endPage; - var container = this.container.getBoundingClientRect(); + var container = this.container.getBoundingClientRect(); - if(visible.length === 1) { - return this.mapping.page(visible[0].contents, visible[0].section.cfiBase); - } + if(visible.length === 1) { + return this.mapping.page(visible[0].contents, visible[0].section.cfiBase); + } - if(visible.length > 1) { + if(visible.length > 1) { - startPage = this.mapping.page(visible[0].contents, visible[0].section.cfiBase); - endPage = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase); + startPage = this.mapping.page(visible[0].contents, visible[0].section.cfiBase); + endPage = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase); - return { - start: startPage.start, - end: endPage.end - }; - } + return { + start: startPage.start, + end: endPage.end + }; + } }; ContinuousViewManager.prototype.paginatedLocation = function(){ - var visible = this.visible(); - var startA, startB, endA, endB; - var pageLeft, pageRight; - var container = this.container.getBoundingClientRect(); + var visible = this.visible(); + var startA, startB, endA, endB; + var pageLeft, pageRight; + var container = this.container.getBoundingClientRect(); - if(visible.length === 1) { - startA = container.left - visible[0].position().left; - endA = startA + this.layout.spreadWidth; + if(visible.length === 1) { + startA = container.left - visible[0].position().left; + endA = startA + this.layout.spreadWidth; - return this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA); - } + return this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA); + } - if(visible.length > 1) { + if(visible.length > 1) { - // Left Col - startA = container.left - visible[0].position().left; - endA = startA + this.layout.columnWidth; + // Left Col + startA = container.left - visible[0].position().left; + endA = startA + this.layout.columnWidth; - // Right Col - startB = container.left + this.layout.spreadWidth - visible[visible.length-1].position().left; - endB = startB + this.layout.columnWidth; + // Right Col + startB = container.left + this.layout.spreadWidth - visible[visible.length-1].position().left; + endB = startB + this.layout.columnWidth; - pageLeft = this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA); - pageRight = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase, startB, endB); + pageLeft = this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA); + pageRight = this.mapping.page(visible[visible.length-1].contents, visible[visible.length-1].section.cfiBase, startB, endB); - return { - start: pageLeft.start, - end: pageRight.end - }; - } + return { + start: pageLeft.start, + end: pageRight.end + }; + } }; /* Continuous.prototype.current = function(what){ - var view, top; - var container = this.container.getBoundingClientRect(); - var length = this.views.length - 1; + var view, top; + var container = this.container.getBoundingClientRect(); + var length = this.views.length - 1; - if(this.settings.axis === "horizontal") { + if(this.settings.axis === "horizontal") { - for (var i = length; i >= 0; i--) { - view = this.views[i]; - left = view.position().left; + for (var i = length; i >= 0; i--) { + view = this.views[i]; + left = view.position().left; - if(left < container.right) { + if(left < container.right) { - if(this._current == view) { - break; - } + if(this._current == view) { + break; + } - this._current = view; - break; - } - } + this._current = view; + break; + } + } - } else { + } else { - for (var i = length; i >= 0; i--) { - view = this.views[i]; - top = view.bounds().top; - if(top < container.bottom) { + for (var i = length; i >= 0; i--) { + view = this.views[i]; + top = view.bounds().top; + if(top < container.bottom) { - if(this._current == view) { - break; - } + if(this._current == view) { + break; + } - this._current = view; + this._current = view; - break; - } - } + break; + } + } - } + } - return this._current; + return this._current; }; */ @@ -626,7 +626,7 @@ ContinuousViewManager.prototype.updateLayout = function() { this.viewSettings.width = this.layout.width; this.viewSettings.height = this.layout.height; - this.setLayout(this.layout); + this.setLayout(this.layout); }; @@ -634,15 +634,15 @@ ContinuousViewManager.prototype.next = function(){ if(this.settings.axis === "horizontal") { - this.scrollLeft = this.container.scrollLeft; + this.scrollLeft = this.container.scrollLeft; - if(this.container.scrollLeft + - this.container.offsetWidth + - this.layout.delta < this.container.scrollWidth) { - this.scrollBy(this.layout.delta, 0); - } else { - this.scrollTo(this.container.scrollWidth - this.layout.delta, 0); - } + if(this.container.scrollLeft + + this.container.offsetWidth + + this.layout.delta < this.container.scrollWidth) { + this.scrollBy(this.layout.delta, 0); + } else { + this.scrollTo(this.container.scrollWidth - this.layout.delta, 0); + } } else { this.scrollBy(0, this.layout.height); @@ -651,7 +651,7 @@ ContinuousViewManager.prototype.next = function(){ ContinuousViewManager.prototype.prev = function(){ if(this.settings.axis === "horizontal") { - this.scrollBy(-this.layout.delta, 0); + this.scrollBy(-this.layout.delta, 0); } else { this.scrollBy(0, -this.layout.height); } @@ -672,7 +672,7 @@ ContinuousViewManager.prototype.updateFlow = function(flow){ if (this.settings.axis === "vertical") { this.settings.infinite = true; - } else { + } else { this.settings.infinite = false; } diff --git a/src/managers/single.js b/src/managers/single.js index 900a68c..11f034b 100644 --- a/src/managers/single.js +++ b/src/managers/single.js @@ -93,15 +93,15 @@ SingleViewManager.prototype.destroy = function(){ SingleViewManager.prototype.onResized = function(e) { clearTimeout(this.resizeTimeout); - this.resizeTimeout = setTimeout(function(){ - this.resize(); - }.bind(this), 150); + this.resizeTimeout = setTimeout(function(){ + this.resize(); + }.bind(this), 150); }; SingleViewManager.prototype.resize = function(width, height){ // Clear the queue - this.q.clear(); + this.q.clear(); this._stageSize = this.stage.size(width, height); this._bounds = this.bounds(); @@ -115,12 +115,12 @@ SingleViewManager.prototype.resize = function(width, height){ view.size(this._stageSize.width, this._stageSize.height); }.bind(this)); - this.updateLayout(); + this.updateLayout(); - this.trigger("resized", { - width: this.stage.width, - height: this.stage.height - }); + this.trigger("resized", { + width: this.stage.width, + height: this.stage.height + }); }; @@ -208,7 +208,7 @@ SingleViewManager.prototype.moveTo = function(offset){ } } - this.scrollTo(distX, distY); + this.scrollTo(distX, distY); }; SingleViewManager.prototype.add = function(section){ @@ -349,20 +349,20 @@ SingleViewManager.prototype.current = function(){ // Current is the last visible view return visible[visible.length-1]; } - return null; + return null; }; SingleViewManager.prototype.currentLocation = function(){ - var view; - var start, end; + var view; + var start, end; - if(this.views.length) { - view = this.views.first(); - start = container.left - view.position().left; - end = start + this.layout.spread; + if(this.views.length) { + view = this.views.first(); + start = container.left - view.position().left; + end = start + this.layout.spread; - return this.mapping.page(view, view.section.cfiBase); - } + return this.mapping.page(view, view.section.cfiBase); + } }; @@ -376,12 +376,12 @@ SingleViewManager.prototype.isVisible = function(view, offsetPrev, offsetNext, _ return true; - } else if(this.settings.axis === "vertical" && - position.bottom > container.top - offsetPrev && + } else if(this.settings.axis === "vertical" && + position.bottom > container.top - offsetPrev && position.top < container.bottom + offsetNext) { return true; - } + } return false; @@ -392,60 +392,60 @@ SingleViewManager.prototype.visible = function(){ var container = this.bounds(); var views = this.views.displayed(); var viewsLength = views.length; - var visible = []; - var isVisible; - var view; + var visible = []; + var isVisible; + var view; - for (var i = 0; i < viewsLength; i++) { - view = views[i]; - isVisible = this.isVisible(view, 0, 0, container); + for (var i = 0; i < viewsLength; i++) { + view = views[i]; + isVisible = this.isVisible(view, 0, 0, container); - if(isVisible === true) { - visible.push(view); - } + if(isVisible === true) { + visible.push(view); + } - } - return visible; + } + return visible; }; SingleViewManager.prototype.scrollBy = function(x, y, silent){ - if(silent) { - this.ignore = true; - } + if(silent) { + this.ignore = true; + } - if(this.settings.height) { + if(this.settings.height) { - if(x) this.container.scrollLeft += x; - if(y) this.container.scrollTop += y; + if(x) this.container.scrollLeft += x; + if(y) this.container.scrollTop += y; - } else { - window.scrollBy(x,y); - } - // console.log("scrollBy", x, y); - this.scrolled = true; + } else { + window.scrollBy(x,y); + } + // console.log("scrollBy", x, y); + this.scrolled = true; this.onScroll(); }; SingleViewManager.prototype.scrollTo = function(x, y, silent){ - if(silent) { - this.ignore = true; - } + if(silent) { + this.ignore = true; + } - if(this.settings.height) { - this.container.scrollLeft = x; - this.container.scrollTop = y; - } else { - window.scrollTo(x,y); - } - // console.log("scrollTo", x, y); - this.scrolled = true; + if(this.settings.height) { + this.container.scrollLeft = x; + this.container.scrollTop = y; + } else { + window.scrollTo(x,y); + } + // console.log("scrollTo", x, y); + this.scrolled = true; this.onScroll(); - // if(this.container.scrollLeft != x){ - // setTimeout(function() { - // this.scrollTo(x, y, silent); - // }.bind(this), 10); - // return; - // }; + // if(this.container.scrollLeft != x){ + // setTimeout(function() { + // this.scrollTo(x, y, silent); + // }.bind(this), 10); + // return; + // }; }; SingleViewManager.prototype.onScroll = function(){ @@ -466,7 +466,7 @@ SingleViewManager.prototype.applyLayout = function(layout) { this.updateLayout(); this.mapping = new Mapping(this.layout); - // this.manager.layout(this.layout.format); + // this.manager.layout(this.layout.format); }; SingleViewManager.prototype.updateLayout = function() { diff --git a/src/mapping.js b/src/mapping.js index a552315..143e10d 100644 --- a/src/mapping.js +++ b/src/mapping.js @@ -1,297 +1,297 @@ var EpubCFI = require('./epubcfi'); function Mapping(layout){ - this.layout = layout; + this.layout = layout; }; Mapping.prototype.section = function(view) { - var ranges = this.findRanges(view); - var map = this.rangeListToCfiList(view.section.cfiBase, ranges); + var ranges = this.findRanges(view); + var map = this.rangeListToCfiList(view.section.cfiBase, ranges); - return map; + return map; }; Mapping.prototype.page = function(contents, cfiBase, start, end) { - var root = contents && contents.document ? contents.document.body : false; + var root = contents && contents.document ? contents.document.body : false; - if (!root) { - return; - } + if (!root) { + return; + } - return this.rangePairToCfiPair(cfiBase, { - start: this.findStart(root, start, end), - end: this.findEnd(root, start, end) - }); + return this.rangePairToCfiPair(cfiBase, { + start: this.findStart(root, start, end), + end: this.findEnd(root, start, end) + }); }; Mapping.prototype.walk = function(root, func) { - //var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, null, false); - var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, { - acceptNode: function (node) { - if ( node.data.trim().length > 0 ) { - return NodeFilter.FILTER_ACCEPT; - } else { - return NodeFilter.FILTER_REJECT; - } - } - }, false); - var node; - var result; - while ((node = treeWalker.nextNode())) { - result = func(node); - if(result) break; - } + //var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, null, false); + var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, { + acceptNode: function (node) { + if ( node.data.trim().length > 0 ) { + return NodeFilter.FILTER_ACCEPT; + } else { + return NodeFilter.FILTER_REJECT; + } + } + }, false); + var node; + var result; + while ((node = treeWalker.nextNode())) { + result = func(node); + if(result) break; + } - return result; + return result; }; Mapping.prototype.findRanges = function(view){ - var columns = []; - var scrollWidth = view.contents.scrollWidth(); - var count = this.layout.count(scrollWidth); - var column = this.layout.column; - var gap = this.layout.gap; - var start, end; + var columns = []; + var scrollWidth = view.contents.scrollWidth(); + var count = this.layout.count(scrollWidth); + var column = this.layout.column; + var gap = this.layout.gap; + var start, end; - for (var i = 0; i < count.pages; i++) { - start = (column + gap) * i; - end = (column * (i+1)) + (gap * i); - columns.push({ - start: this.findStart(view.document.body, start, end), - end: this.findEnd(view.document.body, start, end) - }); - } + for (var i = 0; i < count.pages; i++) { + start = (column + gap) * i; + end = (column * (i+1)) + (gap * i); + columns.push({ + start: this.findStart(view.document.body, start, end), + end: this.findEnd(view.document.body, start, end) + }); + } - return columns; + return columns; }; Mapping.prototype.findStart = function(root, start, end){ - var stack = [root]; - var $el; - var found; - var $prev = root; - while (stack.length) { + var stack = [root]; + var $el; + var found; + var $prev = root; + while (stack.length) { - $el = stack.shift(); + $el = stack.shift(); - found = this.walk($el, function(node){ - var left, right; - var elPos; - var elRange; + found = this.walk($el, function(node){ + var left, right; + var elPos; + var elRange; - if(node.nodeType == Node.TEXT_NODE){ - elRange = document.createRange(); - elRange.selectNodeContents(node); - elPos = elRange.getBoundingClientRect(); - } else { - elPos = node.getBoundingClientRect(); - } + if(node.nodeType == Node.TEXT_NODE){ + elRange = document.createRange(); + elRange.selectNodeContents(node); + elPos = elRange.getBoundingClientRect(); + } else { + elPos = node.getBoundingClientRect(); + } - left = elPos.left; - right = elPos.right; + left = elPos.left; + right = elPos.right; - if( left >= start && left <= end ) { - return node; - } else if (right > start) { - return node; - } else { - $prev = node; - stack.push(node); - } + if( left >= start && left <= end ) { + return node; + } else if (right > start) { + return node; + } else { + $prev = node; + stack.push(node); + } - }); + }); - if(found) { - return this.findTextStartRange(found, start, end); - } + if(found) { + return this.findTextStartRange(found, start, end); + } - } + } - // Return last element - return this.findTextStartRange($prev, start, end); + // Return last element + return this.findTextStartRange($prev, start, end); }; Mapping.prototype.findEnd = function(root, start, end){ - var stack = [root]; - var $el; - var $prev = root; - var found; + var stack = [root]; + var $el; + var $prev = root; + var found; - while (stack.length) { + while (stack.length) { - $el = stack.shift(); + $el = stack.shift(); - found = this.walk($el, function(node){ + found = this.walk($el, function(node){ - var left, right; - var elPos; - var elRange; + var left, right; + var elPos; + var elRange; - if(node.nodeType == Node.TEXT_NODE){ - elRange = document.createRange(); - elRange.selectNodeContents(node); - elPos = elRange.getBoundingClientRect(); - } else { - elPos = node.getBoundingClientRect(); - } + if(node.nodeType == Node.TEXT_NODE){ + elRange = document.createRange(); + elRange.selectNodeContents(node); + elPos = elRange.getBoundingClientRect(); + } else { + elPos = node.getBoundingClientRect(); + } - left = elPos.left; - right = elPos.right; + left = elPos.left; + right = elPos.right; - if(left > end && $prev) { - return $prev; - } else if(right > end) { - return node; - } else { - $prev = node; - stack.push(node); - } + if(left > end && $prev) { + return $prev; + } else if(right > end) { + return node; + } else { + $prev = node; + stack.push(node); + } - }); + }); - if(found){ - return this.findTextEndRange(found, start, end); - } + if(found){ + return this.findTextEndRange(found, start, end); + } - } + } - // end of chapter - return this.findTextEndRange($prev, start, end); + // end of chapter + return this.findTextEndRange($prev, start, end); }; Mapping.prototype.findTextStartRange = function(node, start, end){ - var ranges = this.splitTextNodeIntoRanges(node); - var prev; - var range; - var pos; + var ranges = this.splitTextNodeIntoRanges(node); + var prev; + var range; + var pos; - for (var i = 0; i < ranges.length; i++) { - range = ranges[i]; + for (var i = 0; i < ranges.length; i++) { + range = ranges[i]; - pos = range.getBoundingClientRect(); + pos = range.getBoundingClientRect(); - if( pos.left >= start ) { - return range; - } + if( pos.left >= start ) { + return range; + } - prev = range; + prev = range; - } + } - return ranges[0]; + return ranges[0]; }; Mapping.prototype.findTextEndRange = function(node, start, end){ - var ranges = this.splitTextNodeIntoRanges(node); - var prev; - var range; - var pos; + var ranges = this.splitTextNodeIntoRanges(node); + var prev; + var range; + var pos; - for (var i = 0; i < ranges.length; i++) { - range = ranges[i]; + for (var i = 0; i < ranges.length; i++) { + range = ranges[i]; - pos = range.getBoundingClientRect(); + pos = range.getBoundingClientRect(); - if(pos.left > end && prev) { - return prev; - } else if(pos.right > end) { - return range; - } + if(pos.left > end && prev) { + return prev; + } else if(pos.right > end) { + return range; + } - prev = range; + prev = range; - } + } - // Ends before limit - return ranges[ranges.length-1]; + // Ends before limit + return ranges[ranges.length-1]; }; Mapping.prototype.splitTextNodeIntoRanges = function(node, _splitter){ - var ranges = []; - var textContent = node.textContent || ""; - var text = textContent.trim(); - var range; - var rect; - var list; - var doc = node.ownerDocument; - var splitter = _splitter || " "; + var ranges = []; + var textContent = node.textContent || ""; + var text = textContent.trim(); + var range; + var rect; + var list; + var doc = node.ownerDocument; + var splitter = _splitter || " "; - pos = text.indexOf(splitter); + pos = text.indexOf(splitter); - if(pos === -1 || node.nodeType != Node.TEXT_NODE) { - range = doc.createRange(); - range.selectNodeContents(node); - return [range]; - } + if(pos === -1 || node.nodeType != Node.TEXT_NODE) { + range = doc.createRange(); + range.selectNodeContents(node); + return [range]; + } - range = doc.createRange(); - range.setStart(node, 0); - range.setEnd(node, pos); - ranges.push(range); - range = false; + range = doc.createRange(); + range.setStart(node, 0); + range.setEnd(node, pos); + ranges.push(range); + range = false; - while ( pos != -1 ) { + while ( pos != -1 ) { - pos = text.indexOf(splitter, pos + 1); - if(pos > 0) { + pos = text.indexOf(splitter, pos + 1); + if(pos > 0) { - if(range) { - range.setEnd(node, pos); - ranges.push(range); - } + if(range) { + range.setEnd(node, pos); + ranges.push(range); + } - range = doc.createRange(); - range.setStart(node, pos+1); - } - } + range = doc.createRange(); + range.setStart(node, pos+1); + } + } - if(range) { - range.setEnd(node, text.length); - ranges.push(range); - } + if(range) { + range.setEnd(node, text.length); + ranges.push(range); + } - return ranges; + return ranges; }; Mapping.prototype.rangePairToCfiPair = function(cfiBase, rangePair){ - var startRange = rangePair.start; - var endRange = rangePair.end; + var startRange = rangePair.start; + var endRange = rangePair.end; - startRange.collapse(true); - endRange.collapse(true); + startRange.collapse(true); + endRange.collapse(true); - // startCfi = section.cfiFromRange(startRange); - // endCfi = section.cfiFromRange(endRange); - startCfi = new EpubCFI(startRange, cfiBase).toString(); - endCfi = new EpubCFI(endRange, cfiBase).toString(); + // startCfi = section.cfiFromRange(startRange); + // endCfi = section.cfiFromRange(endRange); + startCfi = new EpubCFI(startRange, cfiBase).toString(); + endCfi = new EpubCFI(endRange, cfiBase).toString(); - return { - start: startCfi, - end: endCfi - }; + return { + start: startCfi, + end: endCfi + }; }; Mapping.prototype.rangeListToCfiList = function(cfiBase, columns){ - var map = []; - var rangePair, cifPair; + var map = []; + var rangePair, cifPair; - for (var i = 0; i < columns.length; i++) { - cifPair = this.rangePairToCfiPair(cfiBase, columns[i]); + for (var i = 0; i < columns.length; i++) { + cifPair = this.rangePairToCfiPair(cfiBase, columns[i]); - map.push(cifPair); + map.push(cifPair); - } + } - return map; + return map; }; module.exports = Mapping; diff --git a/src/navigation.js b/src/navigation.js index cb92a71..e02843d 100644 --- a/src/navigation.js +++ b/src/navigation.js @@ -4,99 +4,99 @@ var RSVP = require('rsvp'); var URI = require('urijs'); function Navigation(_package, _request){ - var navigation = this; - var parse = new Parser(); - var request = _request || require('./request'); + var navigation = this; + var parse = new Parser(); + var request = _request || require('./request'); - this.package = _package; - this.toc = []; - this.tocByHref = {}; - this.tocById = {}; + this.package = _package; + this.toc = []; + this.tocByHref = {}; + this.tocById = {}; - if(_package.navPath) { - this.navUrl = URI(_package.navPath).absoluteTo(_package.baseUrl).toString(); - this.nav = {}; + if(_package.navPath) { + this.navUrl = URI(_package.navPath).absoluteTo(_package.baseUrl).toString(); + this.nav = {}; - this.nav.load = function(_request){ - var loading = new RSVP.defer(); - var loaded = loading.promise; + this.nav.load = function(_request){ + var loading = new RSVP.defer(); + var loaded = loading.promise; - request(navigation.navUrl, 'xml').then(function(xml){ - navigation.toc = parse.nav(xml); - navigation.loaded(navigation.toc); - loading.resolve(navigation.toc); - }); + request(navigation.navUrl, 'xml').then(function(xml){ + navigation.toc = parse.nav(xml); + navigation.loaded(navigation.toc); + loading.resolve(navigation.toc); + }); - return loaded; - }; + return loaded; + }; - } + } - if(_package.ncxPath) { - this.ncxUrl = URI(_package.ncxPath).absoluteTo(_package.baseUrl).toString(); - this.ncx = {}; + if(_package.ncxPath) { + this.ncxUrl = URI(_package.ncxPath).absoluteTo(_package.baseUrl).toString(); + this.ncx = {}; - this.ncx.load = function(_request){ - var loading = new RSVP.defer(); - var loaded = loading.promise; + this.ncx.load = function(_request){ + var loading = new RSVP.defer(); + var loaded = loading.promise; - request(navigation.ncxUrl, 'xml').then(function(xml){ - navigation.toc = parse.toc(xml); - navigation.loaded(navigation.toc); - loading.resolve(navigation.toc); - }); + request(navigation.ncxUrl, 'xml').then(function(xml){ + navigation.toc = parse.toc(xml); + navigation.loaded(navigation.toc); + loading.resolve(navigation.toc); + }); - return loaded; - }; + return loaded; + }; - } + } }; // Load the navigation Navigation.prototype.load = function(_request) { - var request = _request || require('./request'); - var loading, loaded; + var request = _request || require('./request'); + var loading, loaded; - if(this.nav) { - loading = this.nav.load(); - } else if(this.ncx) { - loading = this.ncx.load(); - } else { - loaded = new RSVP.defer(); - loaded.resolve([]); - loading = loaded.promise; - } + if(this.nav) { + loading = this.nav.load(); + } else if(this.ncx) { + loading = this.ncx.load(); + } else { + loaded = new RSVP.defer(); + loaded.resolve([]); + loading = loaded.promise; + } - return loading; + return loading; }; Navigation.prototype.loaded = function(toc) { - var item; + var item; - for (var i = 0; i < toc.length; i++) { - item = toc[i]; - this.tocByHref[item.href] = i; - this.tocById[item.id] = i; - } + for (var i = 0; i < toc.length; i++) { + item = toc[i]; + this.tocByHref[item.href] = i; + this.tocById[item.id] = i; + } }; // Get an item from the navigation Navigation.prototype.get = function(target) { - var index; + var index; - if(!target) { - return this.toc; - } + if(!target) { + return this.toc; + } - if(target.indexOf("#") === 0) { - index = this.tocById[target.substring(1)]; - } else if(target in this.tocByHref){ - index = this.tocByHref[target]; - } + if(target.indexOf("#") === 0) { + index = this.tocById[target.substring(1)]; + } else if(target in this.tocByHref){ + index = this.tocByHref[target]; + } - return this.toc[index]; + return this.toc[index]; }; module.exports = Navigation; diff --git a/src/parser.js b/src/parser.js index 6e8e400..f7cd4cd 100644 --- a/src/parser.js +++ b/src/parser.js @@ -6,120 +6,120 @@ var EpubCFI = require('./epubcfi'); function Parser(){}; Parser.prototype.container = function(containerXml){ - //-- - var rootfile, fullpath, folder, encoding; + //-- + var rootfile, fullpath, folder, encoding; - if(!containerXml) { - console.error("Container File Not Found"); - return; - } + if(!containerXml) { + console.error("Container File Not Found"); + return; + } - rootfile = core.qs(containerXml, "rootfile"); + rootfile = core.qs(containerXml, "rootfile"); - if(!rootfile) { - console.error("No RootFile Found"); - return; - } + if(!rootfile) { + console.error("No RootFile Found"); + return; + } - fullpath = rootfile.getAttribute('full-path'); - folder = URI(fullpath).directory(); - encoding = containerXml.xmlEncoding; + fullpath = rootfile.getAttribute('full-path'); + folder = URI(fullpath).directory(); + encoding = containerXml.xmlEncoding; - //-- Now that we have the path we can parse the contents - return { - 'packagePath' : fullpath, - 'basePath' : folder, - 'encoding' : encoding - }; + //-- Now that we have the path we can parse the contents + return { + 'packagePath' : fullpath, + 'basePath' : folder, + 'encoding' : encoding + }; }; Parser.prototype.identifier = function(packageXml){ - var metadataNode; + var metadataNode; - if(!packageXml) { - console.error("Package File Not Found"); - return; - } + if(!packageXml) { + console.error("Package File Not Found"); + return; + } - metadataNode = core.qs(packageXml, "metadata"); + metadataNode = core.qs(packageXml, "metadata"); - if(!metadataNode) { - console.error("No Metadata Found"); - return; - } + if(!metadataNode) { + console.error("No Metadata Found"); + return; + } - return this.getElementText(metadataNode, "identifier"); + return this.getElementText(metadataNode, "identifier"); }; Parser.prototype.packageContents = function(packageXml){ - var parse = this; - var metadataNode, manifestNode, spineNode; - var manifest, navPath, ncxPath, coverPath; - var spineNodeIndex; - var spine; - var spineIndexByURL; - var metadata; + var parse = this; + var metadataNode, manifestNode, spineNode; + var manifest, navPath, ncxPath, coverPath; + var spineNodeIndex; + var spine; + var spineIndexByURL; + var metadata; - if(!packageXml) { - console.error("Package File Not Found"); - return; - } + if(!packageXml) { + console.error("Package File Not Found"); + return; + } - metadataNode = core.qs(packageXml, "metadata"); - if(!metadataNode) { - console.error("No Metadata Found"); - return; - } + metadataNode = core.qs(packageXml, "metadata"); + if(!metadataNode) { + console.error("No Metadata Found"); + return; + } - manifestNode = core.qs(packageXml, "manifest"); - if(!manifestNode) { - console.error("No Manifest Found"); - return; - } + manifestNode = core.qs(packageXml, "manifest"); + if(!manifestNode) { + console.error("No Manifest Found"); + return; + } - spineNode = core.qs(packageXml, "spine"); - if(!spineNode) { - console.error("No Spine Found"); - return; - } + spineNode = core.qs(packageXml, "spine"); + if(!spineNode) { + console.error("No Spine Found"); + return; + } - manifest = parse.manifest(manifestNode); - navPath = parse.findNavPath(manifestNode); - ncxPath = parse.findNcxPath(manifestNode, spineNode); - coverPath = parse.findCoverPath(packageXml); + manifest = parse.manifest(manifestNode); + navPath = parse.findNavPath(manifestNode); + ncxPath = parse.findNcxPath(manifestNode, spineNode); + coverPath = parse.findCoverPath(packageXml); - spineNodeIndex = Array.prototype.indexOf.call(spineNode.parentNode.childNodes, spineNode); + spineNodeIndex = Array.prototype.indexOf.call(spineNode.parentNode.childNodes, spineNode); - spine = parse.spine(spineNode, manifest); + spine = parse.spine(spineNode, manifest); - metadata = parse.metadata(metadataNode); + metadata = parse.metadata(metadataNode); metadata.direction = spineNode.getAttribute("page-progression-direction"); - return { - 'metadata' : metadata, - 'spine' : spine, - 'manifest' : manifest, - 'navPath' : navPath, - 'ncxPath' : ncxPath, - 'coverPath': coverPath, - 'spineNodeIndex' : spineNodeIndex - }; + return { + 'metadata' : metadata, + 'spine' : spine, + 'manifest' : manifest, + 'navPath' : navPath, + 'ncxPath' : ncxPath, + 'coverPath': coverPath, + 'spineNodeIndex' : spineNodeIndex + }; }; //-- Find TOC NAV Parser.prototype.findNavPath = function(manifestNode){ // Find item with property 'nav' // Should catch nav irregardless of order - // var node = manifestNode.querySelector("item[properties$='nav'], item[properties^='nav '], item[properties*=' nav ']"); - var node = core.qsp(manifestNode, "item", {"properties":"nav"}); - return node ? node.getAttribute('href') : false; + // var node = manifestNode.querySelector("item[properties$='nav'], item[properties^='nav '], item[properties*=' nav ']"); + var node = core.qsp(manifestNode, "item", {"properties":"nav"}); + return node ? node.getAttribute('href') : false; }; //-- Find TOC NCX: media-type="application/x-dtbncx+xml" href="toc.ncx" Parser.prototype.findNcxPath = function(manifestNode, spineNode){ // var node = manifestNode.querySelector("item[media-type='application/x-dtbncx+xml']"); - var node = core.qsp(manifestNode, "item", {"media-type":"application/x-dtbncx+xml"}); + var node = core.qsp(manifestNode, "item", {"media-type":"application/x-dtbncx+xml"}); var tocId; // If we can't find the toc by media-type then try to look for id of the item in the spine attributes as @@ -129,7 +129,7 @@ Parser.prototype.findNcxPath = function(manifestNode, spineNode){ tocId = spineNode.getAttribute("toc"); if(tocId) { // node = manifestNode.querySelector("item[id='" + tocId + "']"); - node = manifestNode.getElementById(tocId); + node = manifestNode.getElementById(tocId); } } @@ -138,36 +138,36 @@ Parser.prototype.findNcxPath = function(manifestNode, spineNode){ //-- Expanded to match Readium web components Parser.prototype.metadata = function(xml){ - var metadata = {}, - p = this; + var metadata = {}, + p = this; - metadata.title = p.getElementText(xml, 'title'); - metadata.creator = p.getElementText(xml, 'creator'); - metadata.description = p.getElementText(xml, 'description'); + metadata.title = p.getElementText(xml, 'title'); + metadata.creator = p.getElementText(xml, 'creator'); + metadata.description = p.getElementText(xml, 'description'); - metadata.pubdate = p.getElementText(xml, 'date'); + metadata.pubdate = p.getElementText(xml, 'date'); - metadata.publisher = p.getElementText(xml, 'publisher'); + metadata.publisher = p.getElementText(xml, 'publisher'); - metadata.identifier = p.getElementText(xml, "identifier"); - metadata.language = p.getElementText(xml, "language"); - metadata.rights = p.getElementText(xml, "rights"); + metadata.identifier = p.getElementText(xml, "identifier"); + metadata.language = p.getElementText(xml, "language"); + metadata.rights = p.getElementText(xml, "rights"); - metadata.modified_date = p.getPropertyText(xml, 'dcterms:modified'); + metadata.modified_date = p.getPropertyText(xml, 'dcterms:modified'); - metadata.layout = p.getPropertyText(xml, "rendition:layout"); - metadata.orientation = p.getPropertyText(xml, 'rendition:orientation'); - metadata.flow = p.getPropertyText(xml, 'rendition:flow'); - metadata.viewport = p.getPropertyText(xml, 'rendition:viewport'); - // metadata.page_prog_dir = packageXml.querySelector("spine").getAttribute("page-progression-direction"); + metadata.layout = p.getPropertyText(xml, "rendition:layout"); + metadata.orientation = p.getPropertyText(xml, 'rendition:orientation'); + metadata.flow = p.getPropertyText(xml, 'rendition:flow'); + metadata.viewport = p.getPropertyText(xml, 'rendition:viewport'); + // metadata.page_prog_dir = packageXml.querySelector("spine").getAttribute("page-progression-direction"); - return metadata; + return metadata; }; //-- Find Cover: //-- Fallback for Epub 2.0 Parser.prototype.findCoverPath = function(packageXml){ - var pkg = core.qs(packageXml, "package"); + var pkg = core.qs(packageXml, "package"); var epubVersion = pkg.getAttribute('version'); if (epubVersion === '2.0') { @@ -175,7 +175,7 @@ Parser.prototype.findCoverPath = function(packageXml){ if (metaCover) { var coverId = metaCover.getAttribute('content'); // var cover = packageXml.querySelector("item[id='" + coverId + "']"); - var cover = packageXml.getElementById(coverId); + var cover = packageXml.getElementById(coverId); return cover ? cover.getAttribute('href') : false; } else { @@ -183,113 +183,113 @@ Parser.prototype.findCoverPath = function(packageXml){ } } else { - // var node = packageXml.querySelector("item[properties='cover-image']"); - var node = core.qsp(packageXml, 'item', {'properties':'cover-image'}); + // var node = packageXml.querySelector("item[properties='cover-image']"); + var node = core.qsp(packageXml, 'item', {'properties':'cover-image'}); return node ? node.getAttribute('href') : false; } }; Parser.prototype.getElementText = function(xml, tag){ - var found = xml.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", tag), - el; + var found = xml.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", tag), + el; - if(!found || found.length === 0) return ''; + if(!found || found.length === 0) return ''; - el = found[0]; + el = found[0]; - if(el.childNodes.length){ - return el.childNodes[0].nodeValue; - } + if(el.childNodes.length){ + return el.childNodes[0].nodeValue; + } - return ''; + return ''; }; Parser.prototype.getPropertyText = function(xml, property){ - var el = core.qsp(xml, "meta", {"property":property}); + var el = core.qsp(xml, "meta", {"property":property}); - if(el && el.childNodes.length){ - return el.childNodes[0].nodeValue; - } + if(el && el.childNodes.length){ + return el.childNodes[0].nodeValue; + } - return ''; + return ''; }; Parser.prototype.querySelectorText = function(xml, q){ - var el = xml.querySelector(q); + var el = xml.querySelector(q); - if(el && el.childNodes.length){ - return el.childNodes[0].nodeValue; - } + if(el && el.childNodes.length){ + return el.childNodes[0].nodeValue; + } - return ''; + return ''; }; Parser.prototype.manifest = function(manifestXml){ - var manifest = {}; + var manifest = {}; - //-- Turn items into an array - // var selected = manifestXml.querySelectorAll("item"); - var selected = core.qsa(manifestXml, "item"); - var items = Array.prototype.slice.call(selected); + //-- Turn items into an array + // var selected = manifestXml.querySelectorAll("item"); + var selected = core.qsa(manifestXml, "item"); + var items = Array.prototype.slice.call(selected); - //-- Create an object with the id as key - items.forEach(function(item){ - var id = item.getAttribute('id'), - href = item.getAttribute('href') || '', - type = item.getAttribute('media-type') || '', - properties = item.getAttribute('properties') || ''; + //-- Create an object with the id as key + items.forEach(function(item){ + var id = item.getAttribute('id'), + href = item.getAttribute('href') || '', + type = item.getAttribute('media-type') || '', + properties = item.getAttribute('properties') || ''; - manifest[id] = { - 'href' : href, - // 'url' : href, - 'type' : type, - 'properties' : properties.length ? properties.split(' ') : [] - }; + manifest[id] = { + 'href' : href, + // 'url' : href, + 'type' : type, + 'properties' : properties.length ? properties.split(' ') : [] + }; - }); + }); - return manifest; + return manifest; }; Parser.prototype.spine = function(spineXml, manifest){ - var spine = []; + var spine = []; - var selected = spineXml.getElementsByTagName("itemref"), - items = Array.prototype.slice.call(selected); + var selected = spineXml.getElementsByTagName("itemref"), + items = Array.prototype.slice.call(selected); - var epubcfi = new EpubCFI(); + var epubcfi = new EpubCFI(); - //-- Add to array to mantain ordering and cross reference with manifest - items.forEach(function(item, index){ - var idref = item.getAttribute('idref'); - // var cfiBase = epubcfi.generateChapterComponent(spineNodeIndex, index, Id); - var props = item.getAttribute('properties') || ''; - var propArray = props.length ? props.split(' ') : []; - // var manifestProps = manifest[Id].properties; - // var manifestPropArray = manifestProps.length ? manifestProps.split(' ') : []; + //-- Add to array to mantain ordering and cross reference with manifest + items.forEach(function(item, index){ + var idref = item.getAttribute('idref'); + // var cfiBase = epubcfi.generateChapterComponent(spineNodeIndex, index, Id); + var props = item.getAttribute('properties') || ''; + var propArray = props.length ? props.split(' ') : []; + // var manifestProps = manifest[Id].properties; + // var manifestPropArray = manifestProps.length ? manifestProps.split(' ') : []; - var itemref = { - 'idref' : idref, - 'linear' : item.getAttribute('linear') || '', - 'properties' : propArray, - // 'href' : manifest[Id].href, - // 'url' : manifest[Id].url, - 'index' : index - // 'cfiBase' : cfiBase - }; - spine.push(itemref); - }); + var itemref = { + 'idref' : idref, + 'linear' : item.getAttribute('linear') || '', + 'properties' : propArray, + // 'href' : manifest[Id].href, + // 'url' : manifest[Id].url, + 'index' : index + // 'cfiBase' : cfiBase + }; + spine.push(itemref); + }); - return spine; + return spine; }; Parser.prototype.querySelectorByType = function(html, element, type){ - var query; - if (typeof html.querySelector != "undefined") { - query = html.querySelector(element+'[*|type="'+type+'"]'); - } + var query; + if (typeof html.querySelector != "undefined") { + query = html.querySelector(element+'[*|type="'+type+'"]'); + } // Handle IE not supporting namespaced epub:type in querySelector if(!query || query.length === 0) { query = core.qsa(html, element); @@ -305,7 +305,7 @@ Parser.prototype.querySelectorByType = function(html, element, type){ Parser.prototype.nav = function(navHtml, spineIndexByURL, bookSpine){ var navElement = this.querySelectorByType(navHtml, "nav", "toc"); - // var navItems = navElement ? navElement.querySelectorAll("ol li") : []; + // var navItems = navElement ? navElement.querySelectorAll("ol li") : []; var navItems = navElement ? core.qsa(navElement, "li") : []; var length = navItems.length; var i; @@ -332,7 +332,7 @@ Parser.prototype.nav = function(navHtml, spineIndexByURL, bookSpine){ Parser.prototype.navItem = function(item, spineIndexByURL, bookSpine){ var id = item.getAttribute('id') || false, // content = item.querySelector("a, span"), - content = core.qs(item, "a"), + content = core.qs(item, "a"), src = content.getAttribute('href') || '', text = content.textContent || "", // split = src.split("#"), @@ -348,7 +348,7 @@ Parser.prototype.navItem = function(item, spineIndexByURL, bookSpine){ parent = parentNode.getAttribute('id'); } - /* + /* if(!id) { if(spinePos) { spineItem = bookSpine[spinePos]; @@ -359,7 +359,7 @@ Parser.prototype.navItem = function(item, spineIndexByURL, bookSpine){ item.setAttribute('id', id); } } - */ + */ return { "id": id, @@ -372,7 +372,7 @@ Parser.prototype.navItem = function(item, spineIndexByURL, bookSpine){ Parser.prototype.ncx = function(tocXml, spineIndexByURL, bookSpine){ // var navPoints = tocXml.querySelectorAll("navMap navPoint"); - var navPoints = core.qsa(tocXml, "navPoint"); + var navPoints = core.qsa(tocXml, "navPoint"); var length = navPoints.length; var i; var toc = {}; @@ -400,8 +400,8 @@ Parser.prototype.ncxItem = function(item, spineIndexByURL, bookSpine){ // content = item.querySelector("content"), content = core.qs(item, "content"), src = content.getAttribute('src'), - // navLabel = item.querySelector("navLabel"), - navLabel = core.qs(item, "navLabel"), + // navLabel = item.querySelector("navLabel"), + navLabel = core.qs(item, "navLabel"), text = navLabel.textContent ? navLabel.textContent : "", // split = src.split("#"), // baseUrl = split[0], @@ -416,7 +416,7 @@ Parser.prototype.ncxItem = function(item, spineIndexByURL, bookSpine){ parent = parentNode.getAttribute('id'); } - /* + /* if(!id) { if(spinePos) { spineItem = bookSpine[spinePos]; @@ -427,7 +427,7 @@ Parser.prototype.ncxItem = function(item, spineIndexByURL, bookSpine){ item.setAttribute('id', id); } } - */ + */ return { "id": id, @@ -440,7 +440,7 @@ Parser.prototype.ncxItem = function(item, spineIndexByURL, bookSpine){ Parser.prototype.pageList = function(navHtml, spineIndexByURL, bookSpine){ var navElement = this.querySelectorByType(navHtml, "nav", "page-list"); - // var navItems = navElement ? navElement.querySelectorAll("ol li") : []; + // var navItems = navElement ? navElement.querySelectorAll("ol li") : []; var navItems = navElement ? core.qsa(navElement, "li") : []; var length = navItems.length; var i; @@ -461,7 +461,7 @@ Parser.prototype.pageList = function(navHtml, spineIndexByURL, bookSpine){ Parser.prototype.pageListItem = function(item, spineIndexByURL, bookSpine){ var id = item.getAttribute('id') || false, // content = item.querySelector("a"), - content = core.qs(item, "a"), + content = core.qs(item, "a"), href = content.getAttribute('href') || '', text = content.textContent || "", page = parseInt(text), diff --git a/src/queue.js b/src/queue.js index 03d5ab0..f48d0da 100644 --- a/src/queue.js +++ b/src/queue.js @@ -2,191 +2,191 @@ var RSVP = require('rsvp'); var core = require('./core'); function Queue(_context){ - this._q = []; - this.context = _context; - this.tick = core.requestAnimationFrame; - this.running = false; - this.paused = false; + this._q = []; + this.context = _context; + this.tick = core.requestAnimationFrame; + this.running = false; + this.paused = false; }; // Add an item to the queue Queue.prototype.enqueue = function() { - var deferred, promise; - var queued; - var task = [].shift.call(arguments); - var args = arguments; + var deferred, promise; + var queued; + var task = [].shift.call(arguments); + var args = arguments; - // Handle single args without context - // if(args && !Array.isArray(args)) { - // args = [args]; - // } - if(!task) { - return console.error("No Task Provided"); - } + // Handle single args without context + // if(args && !Array.isArray(args)) { + // args = [args]; + // } + if(!task) { + return console.error("No Task Provided"); + } - if(typeof task === "function"){ + if(typeof task === "function"){ - deferred = new RSVP.defer(); - promise = deferred.promise; + deferred = new RSVP.defer(); + promise = deferred.promise; - queued = { - "task" : task, - "args" : args, - //"context" : context, - "deferred" : deferred, - "promise" : promise - }; + queued = { + "task" : task, + "args" : args, + //"context" : context, + "deferred" : deferred, + "promise" : promise + }; - } else { - // Task is a promise - queued = { - "promise" : task - }; + } else { + // Task is a promise + queued = { + "promise" : task + }; - } + } - this._q.push(queued); + this._q.push(queued); - // Wait to start queue flush - if (this.paused == false && !this.running) { - // setTimeout(this.flush.bind(this), 0); - // this.tick.call(window, this.run.bind(this)); - this.run(); - } + // Wait to start queue flush + if (this.paused == false && !this.running) { + // setTimeout(this.flush.bind(this), 0); + // this.tick.call(window, this.run.bind(this)); + this.run(); + } - return queued.promise; + return queued.promise; }; // Run one item Queue.prototype.dequeue = function(){ - var inwait, task, result; + var inwait, task, result; - if(this._q.length) { - inwait = this._q.shift(); - task = inwait.task; - if(task){ - // console.log(task) + if(this._q.length) { + inwait = this._q.shift(); + task = inwait.task; + if(task){ + // console.log(task) - result = task.apply(this.context, inwait.args); + result = task.apply(this.context, inwait.args); - if(result && typeof result["then"] === "function") { - // Task is a function that returns a promise - return result.then(function(){ - inwait.deferred.resolve.apply(this.context, arguments); - }.bind(this)); - } else { - // Task resolves immediately - inwait.deferred.resolve.apply(this.context, result); - return inwait.promise; - } + if(result && typeof result["then"] === "function") { + // Task is a function that returns a promise + return result.then(function(){ + inwait.deferred.resolve.apply(this.context, arguments); + }.bind(this)); + } else { + // Task resolves immediately + inwait.deferred.resolve.apply(this.context, result); + return inwait.promise; + } - } else if(inwait.promise) { - // Task is a promise - return inwait.promise; - } + } else if(inwait.promise) { + // Task is a promise + return inwait.promise; + } - } else { - inwait = new RSVP.defer(); - inwait.deferred.resolve(); - return inwait.promise; - } + } else { + inwait = new RSVP.defer(); + inwait.deferred.resolve(); + return inwait.promise; + } }; // Run All Immediately Queue.prototype.dump = function(){ - while(this._q.length) { - this.dequeue(); - } + while(this._q.length) { + this.dequeue(); + } }; // Run all sequentially, at convince Queue.prototype.run = function(){ - if(!this.running){ - this.running = true; - this.defered = new RSVP.defer(); - } + if(!this.running){ + this.running = true; + this.defered = new RSVP.defer(); + } - this.tick.call(window, function() { + this.tick.call(window, function() { - if(this._q.length) { + if(this._q.length) { - this.dequeue() - .then(function(){ - this.run(); - }.bind(this)); + this.dequeue() + .then(function(){ + this.run(); + }.bind(this)); - } else { - this.defered.resolve(); - this.running = undefined; - } + } else { + this.defered.resolve(); + this.running = undefined; + } - }.bind(this)); + }.bind(this)); - // Unpause - if(this.paused == true) { - this.paused = false; - } + // Unpause + if(this.paused == true) { + this.paused = false; + } - return this.defered.promise; + return this.defered.promise; }; // Flush all, as quickly as possible Queue.prototype.flush = function(){ - if(this.running){ - return this.running; - } + if(this.running){ + return this.running; + } - if(this._q.length) { - this.running = this.dequeue() - .then(function(){ - this.running = undefined; - return this.flush(); - }.bind(this)); + if(this._q.length) { + this.running = this.dequeue() + .then(function(){ + this.running = undefined; + return this.flush(); + }.bind(this)); - return this.running; - } + return this.running; + } }; // Clear all items in wait Queue.prototype.clear = function(){ - this._q = []; - this.running = false; + this._q = []; + this.running = false; }; Queue.prototype.length = function(){ - return this._q.length; + return this._q.length; }; Queue.prototype.pause = function(){ - this.paused = true; + this.paused = true; }; // Create a new task from a callback function Task(task, args, context){ - return function(){ - var toApply = arguments || []; + return function(){ + var toApply = arguments || []; - return new RSVP.Promise(function(resolve, reject) { - var callback = function(value){ - resolve(value); - }; - // Add the callback to the arguments list - toApply.push(callback); + return new RSVP.Promise(function(resolve, reject) { + var callback = function(value){ + resolve(value); + }; + // Add the callback to the arguments list + toApply.push(callback); - // Apply all arguments to the functions - task.apply(this, toApply); + // Apply all arguments to the functions + task.apply(this, toApply); - }.bind(this)); + }.bind(this)); - }; + }; }; diff --git a/src/rendition.js b/src/rendition.js index 5a3551f..d27e0b8 100644 --- a/src/rendition.js +++ b/src/rendition.js @@ -49,7 +49,7 @@ function Rendition(book, options) { // this.hooks.display.register(this.afterDisplay.bind(this)); - this.epubcfi = new EpubCFI(); + this.epubcfi = new EpubCFI(); this.q = new Queue(this); @@ -83,7 +83,7 @@ Rendition.prototype.requireManager = function(manager) { viewManager = manager } - return viewManager; + return viewManager; }; Rendition.prototype.requireView = function(view) { @@ -96,7 +96,7 @@ Rendition.prototype.requireView = function(view) { View = view } - return View; + return View; }; Rendition.prototype.start = function(){ @@ -362,24 +362,24 @@ Rendition.prototype.spread = function(spread, min){ Rendition.prototype.reportLocation = function(){ - return this.q.enqueue(function(){ - var location = this.manager.currentLocation(); + return this.q.enqueue(function(){ + var location = this.manager.currentLocation(); if (location && location.then && typeof location.then === 'function') { location.then(function(result) { this.location = result; - this.trigger("locationChanged", this.location); + this.trigger("locationChanged", this.location); }.bind(this)); } else if (location) { this.location = location; - this.trigger("locationChanged", this.location); + this.trigger("locationChanged", this.location); } - }.bind(this)); + }.bind(this)); }; Rendition.prototype.destroy = function(){ - // Clear the queue + // Clear the queue this.q.clear(); this.views.clear(); @@ -394,7 +394,7 @@ Rendition.prototype.destroy = function(){ }; Rendition.prototype.passViewEvents = function(view){ - view.contents.listenedEvents.forEach(function(e){ + view.contents.listenedEvents.forEach(function(e){ view.on(e, this.triggerViewEvent.bind(this)); }.bind(this)); @@ -402,11 +402,11 @@ Rendition.prototype.passViewEvents = function(view){ }; Rendition.prototype.triggerViewEvent = function(e){ - this.trigger(e.type, e); + this.trigger(e.type, e); }; Rendition.prototype.triggerSelectedEvent = function(cfirange){ - this.trigger("selected", cfirange); + this.trigger("selected", cfirange); }; Rendition.prototype.replacements = function(){ @@ -414,27 +414,27 @@ Rendition.prototype.replacements = function(){ // return this.q.enqueue(function () { // Get thes books manifest var manifest = this.book.package.manifest; - var manifestArray = Object.keys(manifest). - map(function (key){ - return manifest[key]; - }); + var manifestArray = Object.keys(manifest). + map(function (key){ + return manifest[key]; + }); - // Exclude HTML - var items = manifestArray. - filter(function (item){ - if (item.type != "application/xhtml+xml" && - item.type != "text/html") { - return true; - } - }); + // Exclude HTML + var items = manifestArray. + filter(function (item){ + if (item.type != "application/xhtml+xml" && + item.type != "text/html") { + return true; + } + }); - // Only CSS - var css = items. - filter(function (item){ - if (item.type === "text/css") { - return true; - } - }); + // Only CSS + var css = items. + filter(function (item){ + if (item.type === "text/css") { + return true; + } + }); // Css Urls var cssUrls = css.map(function(item) { @@ -442,18 +442,18 @@ Rendition.prototype.replacements = function(){ }); // All Assets Urls - var urls = items. - map(function(item) { - return item.href; - }.bind(this)); + var urls = items. + map(function(item) { + return item.href; + }.bind(this)); // Create blob urls for all the assets - var processing = urls. - map(function(url) { + var processing = urls. + map(function(url) { var absolute = URI(url).absoluteTo(this.book.baseUrl).toString(); // Full url from archive base - return this.book.unarchived.createUrl(absolute, {"base64": this.settings.useBase64}); - }.bind(this)); + return this.book.unarchived.createUrl(absolute, {"base64": this.settings.useBase64}); + }.bind(this)); var replacementUrls; @@ -467,11 +467,11 @@ Rendition.prototype.replacements = function(){ // Replace Asset Urls in the text of all css files cssUrls.forEach(function(href) { replaced.push(this.replaceCss(href, urls, replacementUrls)); - }.bind(this)); + }.bind(this)); return RSVP.all(replaced); - }.bind(this)) + }.bind(this)) .then(function () { // Replace Asset Urls in chapters // by registering a hook after the sections contents has been serialized @@ -483,8 +483,8 @@ Rendition.prototype.replacements = function(){ }.bind(this)) .catch(function(reason){ - console.error(reason); - }); + console.error(reason); + }); // }.bind(this)); }; @@ -545,31 +545,31 @@ Rendition.prototype.replaceAssets = function(section, urls, replacementUrls){ }; Rendition.prototype.range = function(_cfi, ignoreClass){ - var cfi = new EpubCFI(_cfi); - var found = this.visible().filter(function (view) { + var cfi = new EpubCFI(_cfi); + var found = this.visible().filter(function (view) { if(cfi.spinePos === view.index) return true; }); // Should only every return 1 item - if (found.length) { - return found[0].range(cfi, ignoreClass); - } + if (found.length) { + return found[0].range(cfi, ignoreClass); + } }; Rendition.prototype.adjustImages = function(view) { - view.addStylesheetRules([ - ["img", - ["max-width", (view.layout.spreadWidth) + "px"], - ["max-height", (view.layout.height) + "px"] - ] - ]); - return new RSVP.Promise(function(resolve, reject){ - // Wait to apply - setTimeout(function() { - resolve(); - }, 1); - }); + view.addStylesheetRules([ + ["img", + ["max-width", (view.layout.spreadWidth) + "px"], + ["max-height", (view.layout.height) + "px"] + ] + ]); + return new RSVP.Promise(function(resolve, reject){ + // Wait to apply + setTimeout(function() { + resolve(); + }, 1); + }); }; //-- Enable binding events to Renderer diff --git a/src/replacements.js b/src/replacements.js index 0e87a13..8d4e6a2 100644 --- a/src/replacements.js +++ b/src/replacements.js @@ -2,69 +2,69 @@ var URI = require('urijs'); var core = require('./core'); function base(doc, section){ - var base; - var head; + var base; + var head; - if(!doc){ - return; - } + if(!doc){ + return; + } - // head = doc.querySelector("head"); - // base = head.querySelector("base"); - head = core.qs(doc, "head"); - base = core.qs(head, "base"); + // head = doc.querySelector("head"); + // base = head.querySelector("base"); + head = core.qs(doc, "head"); + base = core.qs(head, "base"); - if(!base) { - base = doc.createElement("base"); - head.insertBefore(base, head.firstChild); - } + if(!base) { + base = doc.createElement("base"); + head.insertBefore(base, head.firstChild); + } - base.setAttribute("href", section.url); + base.setAttribute("href", section.url); } function canonical(doc, section){ - var head; - var link; - var url = section.url; // window.location.origin + window.location.pathname + "?loc=" + encodeURIComponent(section.url); + var head; + var link; + var url = section.url; // window.location.origin + window.location.pathname + "?loc=" + encodeURIComponent(section.url); - if(!doc){ - return; - } + if(!doc){ + return; + } - head = core.qs(doc, "head"); - link = core.qs(head, "link[rel='canonical']"); + head = core.qs(doc, "head"); + link = core.qs(head, "link[rel='canonical']"); - if (link) { - link.setAttribute("href", url); - } else { - link = doc.createElement("link"); - link.setAttribute("rel", "canonical"); - link.setAttribute("href", url); - head.appendChild(link); - } + if (link) { + link.setAttribute("href", url); + } else { + link = doc.createElement("link"); + link.setAttribute("rel", "canonical"); + link.setAttribute("href", url); + head.appendChild(link); + } } function links(view, renderer) { - var links = view.document.querySelectorAll("a[href]"); - var replaceLinks = function(link){ - var href = link.getAttribute("href"); + var links = view.document.querySelectorAll("a[href]"); + var replaceLinks = function(link){ + var href = link.getAttribute("href"); - if(href.indexOf("mailto:") === 0){ - return; - } + if(href.indexOf("mailto:") === 0){ + return; + } - var linkUri = URI(href); - var absolute = linkUri.absoluteTo(view.section.url); - var relative = absolute.relativeTo(this.book.baseUrl).toString(); + var linkUri = URI(href); + var absolute = linkUri.absoluteTo(view.section.url); + var relative = absolute.relativeTo(this.book.baseUrl).toString(); - if(linkUri.protocol()){ + if(linkUri.protocol()){ - link.setAttribute("target", "_blank"); + link.setAttribute("target", "_blank"); - }else{ - /* - if(baseDirectory) { + }else{ + /* + if(baseDirectory) { // We must ensure that the file:// protocol is preserved for // local file links, as in certain contexts (such as under // Titanium), file links without the file:// protocol will not @@ -77,38 +77,38 @@ function links(view, renderer) { } else { relative = href; } - */ + */ - if(linkUri.fragment()) { - // do nothing with fragment yet - } else { - link.onclick = function(){ - renderer.display(relative); - return false; - }; - } + if(linkUri.fragment()) { + // do nothing with fragment yet + } else { + link.onclick = function(){ + renderer.display(relative); + return false; + }; + } - } - }.bind(this); + } + }.bind(this); - for (var i = 0; i < links.length; i++) { - replaceLinks(links[i]); - } + for (var i = 0; i < links.length; i++) { + replaceLinks(links[i]); + } }; function substitute(content, urls, replacements) { - urls.forEach(function(url, i){ - if (url && replacements[i]) { - content = content.replace(new RegExp(url, 'g'), replacements[i]); - } - }); - return content; + urls.forEach(function(url, i){ + if (url && replacements[i]) { + content = content.replace(new RegExp(url, 'g'), replacements[i]); + } + }); + return content; } module.exports = { - 'base': base, - 'canonical' : canonical, - 'links': links, - 'substitute': substitute + 'base': base, + 'canonical' : canonical, + 'links': links, + 'substitute': substitute }; diff --git a/src/request.js b/src/request.js index 5fb6247..b1eb004 100644 --- a/src/request.js +++ b/src/request.js @@ -3,55 +3,55 @@ var URI = require('urijs'); var core = require('./core'); function request(url, type, withCredentials, headers) { - var supportsURL = (typeof window != "undefined") ? window.URL : false; // TODO: fallback for url if window isn't defined - var BLOB_RESPONSE = supportsURL ? "blob" : "arraybuffer"; - var uri; + var supportsURL = (typeof window != "undefined") ? window.URL : false; // TODO: fallback for url if window isn't defined + var BLOB_RESPONSE = supportsURL ? "blob" : "arraybuffer"; + var uri; - var deferred = new RSVP.defer(); + var deferred = new RSVP.defer(); - var xhr = new XMLHttpRequest(); + var xhr = new XMLHttpRequest(); - //-- Check from PDF.js: - // https://github.com/mozilla/pdf.js/blob/master/web/compatibility.js - var xhrPrototype = XMLHttpRequest.prototype; + //-- Check from PDF.js: + // https://github.com/mozilla/pdf.js/blob/master/web/compatibility.js + var xhrPrototype = XMLHttpRequest.prototype; - var header; + var header; - if (!('overrideMimeType' in xhrPrototype)) { - // IE10 might have response, but not overrideMimeType - Object.defineProperty(xhrPrototype, 'overrideMimeType', { - value: function xmlHttpRequestOverrideMimeType(mimeType) {} - }); - } - if(withCredentials) { - xhr.withCredentials = true; - } + if (!('overrideMimeType' in xhrPrototype)) { + // IE10 might have response, but not overrideMimeType + Object.defineProperty(xhrPrototype, 'overrideMimeType', { + value: function xmlHttpRequestOverrideMimeType(mimeType) {} + }); + } + if(withCredentials) { + xhr.withCredentials = true; + } - xhr.onreadystatechange = handler; - xhr.onerror = err; + xhr.onreadystatechange = handler; + xhr.onerror = err; - xhr.open("GET", url, true); + xhr.open("GET", url, true); - for(header in headers) { - xhr.setRequestHeader(header, headers[header]); - } + for(header in headers) { + xhr.setRequestHeader(header, headers[header]); + } - if(type == "json") { - xhr.setRequestHeader("Accept", "application/json"); - } + if(type == "json") { + xhr.setRequestHeader("Accept", "application/json"); + } - // If type isn't set, determine it from the file extension + // If type isn't set, determine it from the file extension if(!type) { uri = URI(url); type = uri.suffix(); } - if(type == 'blob'){ - xhr.responseType = BLOB_RESPONSE; - } + if(type == 'blob'){ + xhr.responseType = BLOB_RESPONSE; + } - if(core.isXml(type)) { + if(core.isXml(type)) { // xhr.responseType = "document"; xhr.overrideMimeType('text/xml'); // for OPF parsing } @@ -62,89 +62,89 @@ function request(url, type, withCredentials, headers) { if(type == 'html' || type == 'htm') { // xhr.responseType = "document"; - } + } - if(type == "binary") { - xhr.responseType = "arraybuffer"; - } + if(type == "binary") { + xhr.responseType = "arraybuffer"; + } - xhr.send(); + xhr.send(); - function err(e) { - console.error(e); - deferred.reject(e); - } + function err(e) { + console.error(e); + deferred.reject(e); + } - function handler() { - if (this.readyState === XMLHttpRequest.DONE) { + function handler() { + if (this.readyState === XMLHttpRequest.DONE) { - if (this.status === 200 || this.responseXML ) { //-- Firefox is reporting 0 for blob urls - var r; + if (this.status === 200 || this.responseXML ) { //-- Firefox is reporting 0 for blob urls + var r; - if (!this.response && !this.responseXML) { - deferred.reject({ - status: this.status, - message : "Empty Response", - stack : new Error().stack - }); - return deferred.promise; - } + if (!this.response && !this.responseXML) { + deferred.reject({ + status: this.status, + message : "Empty Response", + stack : new Error().stack + }); + return deferred.promise; + } - if (this.status === 403) { - deferred.reject({ - status: this.status, - response: this.response, - message : "Forbidden", - stack : new Error().stack - }); - return deferred.promise; - } + if (this.status === 403) { + deferred.reject({ + status: this.status, + response: this.response, + message : "Forbidden", + stack : new Error().stack + }); + return deferred.promise; + } - if((this.responseType == '' || this.responseType == 'document') - && this.responseXML){ - r = this.responseXML; - } else - if(core.isXml(type)){ - // xhr.overrideMimeType('text/xml'); // for OPF parsing - // If this.responseXML wasn't set, try to parse using a DOMParser from text - r = core.parse(this.response, "text/xml"); - }else - if(type == 'xhtml'){ - r = core.parse(this.response, "application/xhtml+xml"); - }else - if(type == 'html' || type == 'htm'){ - r = core.parse(this.response, "text/html"); - }else - if(type == 'json'){ - r = JSON.parse(this.response); - }else - if(type == 'blob'){ + if((this.responseType == '' || this.responseType == 'document') + && this.responseXML){ + r = this.responseXML; + } else + if(core.isXml(type)){ + // xhr.overrideMimeType('text/xml'); // for OPF parsing + // If this.responseXML wasn't set, try to parse using a DOMParser from text + r = core.parse(this.response, "text/xml"); + }else + if(type == 'xhtml'){ + r = core.parse(this.response, "application/xhtml+xml"); + }else + if(type == 'html' || type == 'htm'){ + r = core.parse(this.response, "text/html"); + }else + if(type == 'json'){ + r = JSON.parse(this.response); + }else + if(type == 'blob'){ - if(supportsURL) { - r = this.response; - } else { - //-- Safari doesn't support responseType blob, so create a blob from arraybuffer - r = new Blob([this.response]); - } + if(supportsURL) { + r = this.response; + } else { + //-- Safari doesn't support responseType blob, so create a blob from arraybuffer + r = new Blob([this.response]); + } - }else{ - r = this.response; - } + }else{ + r = this.response; + } - deferred.resolve(r); - } else { + deferred.resolve(r); + } else { - deferred.reject({ - status: this.status, - message : this.response, - stack : new Error().stack - }); + deferred.reject({ + status: this.status, + message : this.response, + stack : new Error().stack + }); - } - } - } + } + } + } - return deferred.promise; + return deferred.promise; }; module.exports = request; diff --git a/src/section.js b/src/section.js index f79fc73..1715f03 100644 --- a/src/section.js +++ b/src/section.js @@ -5,110 +5,110 @@ var EpubCFI = require('./epubcfi'); var Hook = require('./hook'); function Section(item, hooks){ - this.idref = item.idref; - this.linear = item.linear; - this.properties = item.properties; - this.index = item.index; - this.href = item.href; - this.url = item.url; - this.next = item.next; - this.prev = item.prev; + this.idref = item.idref; + this.linear = item.linear; + this.properties = item.properties; + this.index = item.index; + this.href = item.href; + this.url = item.url; + this.next = item.next; + this.prev = item.prev; - this.cfiBase = item.cfiBase; + this.cfiBase = item.cfiBase; - if (hooks) { - this.hooks = hooks; - } else { - this.hooks = {}; - this.hooks.serialize = new Hook(this); - this.hooks.content = new Hook(this); - } + if (hooks) { + this.hooks = hooks; + } else { + this.hooks = {}; + this.hooks.serialize = new Hook(this); + this.hooks.content = new Hook(this); + } }; Section.prototype.load = function(_request){ - var request = _request || this.request || require('./request'); - var loading = new RSVP.defer(); - var loaded = loading.promise; + var request = _request || this.request || require('./request'); + var loading = new RSVP.defer(); + var loaded = loading.promise; - if(this.contents) { - loading.resolve(this.contents); - } else { - request(this.url) - .then(function(xml){ - var base; - var directory = URI(this.url).directory(); + if(this.contents) { + loading.resolve(this.contents); + } else { + request(this.url) + .then(function(xml){ + var base; + var directory = URI(this.url).directory(); - this.document = xml; - this.contents = xml.documentElement; + this.document = xml; + this.contents = xml.documentElement; - return this.hooks.content.trigger(this.document, this); - }.bind(this)) - .then(function(){ - loading.resolve(this.contents); - }.bind(this)) - .catch(function(error){ - loading.reject(error); - }); - } + return this.hooks.content.trigger(this.document, this); + }.bind(this)) + .then(function(){ + loading.resolve(this.contents); + }.bind(this)) + .catch(function(error){ + loading.reject(error); + }); + } - return loaded; + return loaded; }; Section.prototype.base = function(_document){ - var task = new RSVP.defer(); - var base = _document.createElement("base"); // TODO: check if exists - var head; - console.log(window.location.origin + "/" +this.url); + var task = new RSVP.defer(); + var base = _document.createElement("base"); // TODO: check if exists + var head; + console.log(window.location.origin + "/" +this.url); - base.setAttribute("href", window.location.origin + "/" +this.url); + base.setAttribute("href", window.location.origin + "/" +this.url); - if(_document) { - head = _document.querySelector("head"); - } - if(head) { - head.insertBefore(base, head.firstChild); - task.resolve(); - } else { - task.reject(new Error("No head to insert into")); - } + if(_document) { + head = _document.querySelector("head"); + } + if(head) { + head.insertBefore(base, head.firstChild); + task.resolve(); + } else { + task.reject(new Error("No head to insert into")); + } - return task.promise; + return task.promise; }; Section.prototype.beforeSectionLoad = function(){ - // Stub for a hook - replace me for now + // Stub for a hook - replace me for now }; Section.prototype.render = function(_request){ - var rendering = new RSVP.defer(); - var rendered = rendering.promise; - this.output; // TODO: better way to return this from hooks? + var rendering = new RSVP.defer(); + var rendered = rendering.promise; + this.output; // TODO: better way to return this from hooks? - this.load(_request). - then(function(contents){ - var serializer; + this.load(_request). + then(function(contents){ + var serializer; - if (typeof XMLSerializer === "undefined") { - XMLSerializer = require('xmldom').XMLSerializer; - } - serializer = new XMLSerializer(); - this.output = serializer.serializeToString(contents); - return this.output; - }.bind(this)). - then(function(){ - return this.hooks.serialize.trigger(this.output, this); - }.bind(this)). - then(function(){ - rendering.resolve(this.output); - }.bind(this)) - .catch(function(error){ - rendering.reject(error); - }); + if (typeof XMLSerializer === "undefined") { + XMLSerializer = require('xmldom').XMLSerializer; + } + serializer = new XMLSerializer(); + this.output = serializer.serializeToString(contents); + return this.output; + }.bind(this)). + then(function(){ + return this.hooks.serialize.trigger(this.output, this); + }.bind(this)). + then(function(){ + rendering.resolve(this.output); + }.bind(this)) + .catch(function(error){ + rendering.reject(error); + }); - return rendered; + return rendered; }; Section.prototype.find = function(_query){ @@ -122,35 +122,35 @@ Section.prototype.find = function(_query){ * Returns: Object with layout properties */ Section.prototype.reconcileLayoutSettings = function(global){ - //-- Get the global defaults - var settings = { - layout : global.layout, - spread : global.spread, - orientation : global.orientation - }; + //-- Get the global defaults + var settings = { + layout : global.layout, + spread : global.spread, + orientation : global.orientation + }; - //-- Get the chapter's display type - this.properties.forEach(function(prop){ - var rendition = prop.replace("rendition:", ''); - var split = rendition.indexOf("-"); - var property, value; + //-- Get the chapter's display type + this.properties.forEach(function(prop){ + var rendition = prop.replace("rendition:", ''); + var split = rendition.indexOf("-"); + var property, value; - if(split != -1){ - property = rendition.slice(0, split); - value = rendition.slice(split+1); + if(split != -1){ + property = rendition.slice(0, split); + value = rendition.slice(split+1); - settings[property] = value; - } - }); + settings[property] = value; + } + }); return settings; }; Section.prototype.cfiFromRange = function(_range) { - return new EpubCFI(_range, this.cfiBase).toString(); + return new EpubCFI(_range, this.cfiBase).toString(); }; Section.prototype.cfiFromElement = function(el) { - return new EpubCFI(el, this.cfiBase).toString(); + return new EpubCFI(el, this.cfiBase).toString(); }; module.exports = Section; diff --git a/src/spine.js b/src/spine.js index f244d27..b8f5d96 100644 --- a/src/spine.js +++ b/src/spine.js @@ -6,64 +6,64 @@ var Section = require('./section'); var replacements = require('./replacements'); function Spine(_request){ - this.request = _request; - this.spineItems = []; - this.spineByHref = {}; - this.spineById = {}; + this.request = _request; + this.spineItems = []; + this.spineByHref = {}; + this.spineById = {}; - this.hooks = {}; - this.hooks.serialize = new Hook(); - this.hooks.content = new Hook(); + this.hooks = {}; + this.hooks.serialize = new Hook(); + this.hooks.content = new Hook(); - // Register replacements - this.hooks.content.register(replacements.base); - this.hooks.content.register(replacements.canonical); + // Register replacements + this.hooks.content.register(replacements.base); + this.hooks.content.register(replacements.canonical); - this.epubcfi = new EpubCFI(); + this.epubcfi = new EpubCFI(); - this.loaded = false; + this.loaded = false; }; Spine.prototype.load = function(_package) { - this.items = _package.spine; - this.manifest = _package.manifest; - this.spineNodeIndex = _package.spineNodeIndex; - this.baseUrl = _package.baseUrl || ''; - this.length = this.items.length; + this.items = _package.spine; + this.manifest = _package.manifest; + this.spineNodeIndex = _package.spineNodeIndex; + this.baseUrl = _package.baseUrl || ''; + this.length = this.items.length; - this.items.forEach(function(item, index){ - var href, url; - var manifestItem = this.manifest[item.idref]; - var spineItem; + this.items.forEach(function(item, index){ + var href, url; + var manifestItem = this.manifest[item.idref]; + var spineItem; - item.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.idref); + item.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.idref); - if(manifestItem) { - item.href = manifestItem.href; - item.url = this.baseUrl + item.href; + if(manifestItem) { + item.href = manifestItem.href; + item.url = this.baseUrl + item.href; - if(manifestItem.properties.length){ - item.properties.push.apply(item.properties, manifestItem.properties); - } - } + if(manifestItem.properties.length){ + item.properties.push.apply(item.properties, manifestItem.properties); + } + } - // if(index > 0) { - item.prev = function(){ return this.get(index-1); }.bind(this); - // } + // if(index > 0) { + item.prev = function(){ return this.get(index-1); }.bind(this); + // } - // if(index+1 < this.items.length) { - item.next = function(){ return this.get(index+1); }.bind(this); - // } + // if(index+1 < this.items.length) { + item.next = function(){ return this.get(index+1); }.bind(this); + // } - spineItem = new Section(item, this.hooks); + spineItem = new Section(item, this.hooks); - this.append(spineItem); + this.append(spineItem); - }.bind(this)); + }.bind(this)); - this.loaded = true; + this.loaded = true; }; // book.spine.get(); @@ -71,47 +71,47 @@ Spine.prototype.load = function(_package) { // book.spine.get("chap1.html"); // book.spine.get("#id1234"); Spine.prototype.get = function(target) { - var index = 0; + var index = 0; - if(this.epubcfi.isCfiString(target)) { - cfi = new EpubCFI(target); - index = cfi.spinePos; - } else if(target && (typeof target === "number" || isNaN(target) === false)){ - index = target; - } else if(target && target.indexOf("#") === 0) { - index = this.spineById[target.substring(1)]; - } else if(target) { - // Remove fragments - target = target.split("#")[0]; - index = this.spineByHref[target]; - } + if(this.epubcfi.isCfiString(target)) { + cfi = new EpubCFI(target); + index = cfi.spinePos; + } else if(target && (typeof target === "number" || isNaN(target) === false)){ + index = target; + } else if(target && target.indexOf("#") === 0) { + index = this.spineById[target.substring(1)]; + } else if(target) { + // Remove fragments + target = target.split("#")[0]; + index = this.spineByHref[target]; + } - return this.spineItems[index] || null; + return this.spineItems[index] || null; }; Spine.prototype.append = function(section) { - var index = this.spineItems.length; - section.index = index; + var index = this.spineItems.length; + section.index = index; - this.spineItems.push(section); + this.spineItems.push(section); - this.spineByHref[section.href] = index; - this.spineById[section.idref] = index; + this.spineByHref[section.href] = index; + this.spineById[section.idref] = index; - return index; + return index; }; Spine.prototype.prepend = function(section) { - var index = this.spineItems.unshift(section); - this.spineByHref[section.href] = 0; - this.spineById[section.idref] = 0; + var index = this.spineItems.unshift(section); + this.spineByHref[section.href] = 0; + this.spineById[section.idref] = 0; - // Re-index - this.spineItems.forEach(function(item, index){ - item.index = index; - }); + // Re-index + this.spineItems.forEach(function(item, index){ + item.index = index; + }); - return 0; + return 0; }; Spine.prototype.insert = function(section, index) { @@ -119,14 +119,14 @@ Spine.prototype.insert = function(section, index) { }; Spine.prototype.remove = function(section) { - var index = this.spineItems.indexOf(section); + var index = this.spineItems.indexOf(section); - if(index > -1) { - delete this.spineByHref[section.href]; - delete this.spineById[section.idref]; + if(index > -1) { + delete this.spineByHref[section.href]; + delete this.spineById[section.idref]; - return this.spineItems.splice(index, 1); - } + return this.spineItems.splice(index, 1); + } }; Spine.prototype.each = function() { diff --git a/src/stage.js b/src/stage.js index 479f748..2e167ba 100644 --- a/src/stage.js +++ b/src/stage.js @@ -20,7 +20,7 @@ Stage.prototype.create = function(options){ var height = options.height;// !== false ? options.height : "100%"; var width = options.width;// !== false ? options.width : "100%"; var overflow = options.overflow || false; - var axis = options.axis || "vertical"; + var axis = options.axis || "vertical"; if(options.height && core.isNumber(options.height)) { height = options.height + "px"; @@ -223,7 +223,7 @@ Stage.prototype.addStyleRules = function(selector, rulesArray){ } }) - this.sheet.insertRule(scope + selector + " {" + rules + "}", 0); + this.sheet.insertRule(scope + selector + " {" + rules + "}", 0); } diff --git a/src/unarchive.js b/src/unarchive.js index d081301..039adda 100644 --- a/src/unarchive.js +++ b/src/unarchive.js @@ -6,100 +6,100 @@ var mime = require('../libs/mime/mime'); function Unarchive() { - this.checkRequirements(); - this.urlCache = {}; + this.checkRequirements(); + this.urlCache = {}; } Unarchive.prototype.checkRequirements = function(callback){ - try { - if (typeof JSZip !== 'undefined') { - this.zip = new JSZip(); - } else { - JSZip = require('jszip'); - this.zip = new JSZip(); - } - } catch (e) { - console.error("JSZip lib not loaded"); - } + try { + if (typeof JSZip !== 'undefined') { + this.zip = new JSZip(); + } else { + JSZip = require('jszip'); + this.zip = new JSZip(); + } + } catch (e) { + console.error("JSZip lib not loaded"); + } }; Unarchive.prototype.open = function(zipUrl, isBase64){ if (zipUrl instanceof ArrayBuffer || isBase64) { - return this.zip.loadAsync(zipUrl, {"base64": isBase64}); + return this.zip.loadAsync(zipUrl, {"base64": isBase64}); } else { return request(zipUrl, "binary") - .then(function(data){ - return this.zip.loadAsync(data); - }.bind(this)); + .then(function(data){ + return this.zip.loadAsync(data); + }.bind(this)); } }; Unarchive.prototype.request = function(url, type){ - var deferred = new RSVP.defer(); - var response; - var r; + var deferred = new RSVP.defer(); + var response; + var r; - // If type isn't set, determine it from the file extension + // If type isn't set, determine it from the file extension if(!type) { uri = URI(url); type = uri.suffix(); } - if(type == 'blob'){ - response = this.getBlob(url); - } else { - response = this.getText(url); - } + if(type == 'blob'){ + response = this.getBlob(url); + } else { + response = this.getText(url); + } - if (response) { - response.then(function (r) { - result = this.handleResponse(r, type); - deferred.resolve(result); - }.bind(this)); - } else { - deferred.reject({ - message : "File not found in the epub: " + url, - stack : new Error().stack - }); - } - return deferred.promise; + if (response) { + response.then(function (r) { + result = this.handleResponse(r, type); + deferred.resolve(result); + }.bind(this)); + } else { + deferred.reject({ + message : "File not found in the epub: " + url, + stack : new Error().stack + }); + } + return deferred.promise; }; Unarchive.prototype.handleResponse = function(response, type){ - var r; + var r; - if(type == "json") { - r = JSON.parse(response); - } - else - if(core.isXml(type)) { - r = core.parse(response, "text/xml"); + if(type == "json") { + r = JSON.parse(response); } - else + else + if(core.isXml(type)) { + r = core.parse(response, "text/xml"); + } + else if(type == 'xhtml') { - r = core.parse(response, "application/xhtml+xml"); + r = core.parse(response, "application/xhtml+xml"); } - else + else if(type == 'html' || type == 'htm') { - r = core.parse(response, "text/html"); - } else { - r = response; - } + r = core.parse(response, "text/html"); + } else { + r = response; + } - return r; + return r; }; Unarchive.prototype.getBlob = function(url, _mimeType){ var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash var entry = this.zip.file(decodededUrl); - var mimeType; + var mimeType; if(entry) { - mimeType = _mimeType || mime.lookup(entry.name); - return entry.async("uint8array").then(function(uint8array) { - return new Blob([uint8array], {type : mimeType}); - }); + mimeType = _mimeType || mime.lookup(entry.name); + return entry.async("uint8array").then(function(uint8array) { + return new Blob([uint8array], {type : mimeType}); + }); } }; @@ -108,22 +108,22 @@ Unarchive.prototype.getText = function(url, encoding){ var entry = this.zip.file(decodededUrl); if(entry) { - return entry.async("string").then(function(text) { - return text; - }); + return entry.async("string").then(function(text) { + return text; + }); } }; Unarchive.prototype.getBase64 = function(url, _mimeType){ var decodededUrl = window.decodeURIComponent(url.substr(1)); // Remove first slash var entry = this.zip.file(decodededUrl); - var mimeType; + var mimeType; if(entry) { - mimeType = _mimeType || mime.lookup(entry.name); - return entry.async("base64").then(function(data) { - return "data:" + mimeType + ";base64," + data; - }); + mimeType = _mimeType || mime.lookup(entry.name); + return entry.async("base64").then(function(data) { + return "data:" + mimeType + ";base64," + data; + }); } }; @@ -131,51 +131,51 @@ Unarchive.prototype.createUrl = function(url, options){ var deferred = new RSVP.defer(); var _URL = window.URL || window.webkitURL || window.mozURL; var tempUrl; - var blob; + var blob; var response; - var useBase64 = options && options.base64; + var useBase64 = options && options.base64; if(url in this.urlCache) { deferred.resolve(this.urlCache[url]); return deferred.promise; } - if (useBase64) { - response = this.getBase64(url); + if (useBase64) { + response = this.getBase64(url); - if (response) { - response.then(function(tempUrl) { + if (response) { + response.then(function(tempUrl) { - this.urlCache[url] = tempUrl; - deferred.resolve(tempUrl); + this.urlCache[url] = tempUrl; + deferred.resolve(tempUrl); - }.bind(this)); + }.bind(this)); - } + } - } else { + } else { - response = this.getBlob(url); + response = this.getBlob(url); - if (response) { - response.then(function(blob) { + if (response) { + response.then(function(blob) { - tempUrl = _URL.createObjectURL(blob); - this.urlCache[url] = tempUrl; - deferred.resolve(tempUrl); + tempUrl = _URL.createObjectURL(blob); + this.urlCache[url] = tempUrl; + deferred.resolve(tempUrl); - }.bind(this)); + }.bind(this)); - } - } + } + } - if (!response) { - deferred.reject({ - message : "File not found in the epub: " + url, - stack : new Error().stack - }); - } + if (!response) { + deferred.reject({ + message : "File not found in the epub: " + url, + stack : new Error().stack + }); + } return deferred.promise; }; diff --git a/src/views.js b/src/views.js index d8124a8..7549885 100644 --- a/src/views.js +++ b/src/views.js @@ -1,8 +1,8 @@ function Views(container) { - this.container = container; - this._views = []; - this.length = 0; - this.hidden = false; + this.container = container; + this._views = []; + this.length = 0; + this.hidden = false; }; Views.prototype.all = function() { @@ -31,35 +31,35 @@ Views.prototype.get = function(i) { Views.prototype.append = function(view){ this._views.push(view); - if(this.container){ - this.container.appendChild(view.element); - } - this.length++; - return view; + if(this.container){ + this.container.appendChild(view.element); + } + this.length++; + return view; }; Views.prototype.prepend = function(view){ this._views.unshift(view); - if(this.container){ - this.container.insertBefore(view.element, this.container.firstChild); - } - this.length++; - return view; + if(this.container){ + this.container.insertBefore(view.element, this.container.firstChild); + } + this.length++; + return view; }; Views.prototype.insert = function(view, index) { this._views.splice(index, 0, view); - if(this.container){ - if(index < this.container.children.length){ - this.container.insertBefore(view.element, this.container.children[index]); - } else { - this.container.appendChild(view.element); - } - } + if(this.container){ + if(index < this.container.children.length){ + this.container.insertBefore(view.element, this.container.children[index]); + } else { + this.container.appendChild(view.element); + } + } - this.length++; - return view; + this.length++; + return view; }; Views.prototype.remove = function(view) { @@ -72,7 +72,7 @@ Views.prototype.remove = function(view) { this.destroy(view); - this.length--; + this.length--; }; Views.prototype.destroy = function(view) { @@ -82,9 +82,9 @@ Views.prototype.destroy = function(view) { view.destroy(); } - if(this.container){ - this.container.removeChild(view.element); - } + if(this.container){ + this.container.removeChild(view.element); + } view = null; }; @@ -96,72 +96,72 @@ Views.prototype.each = function() { Views.prototype.clear = function(){ // Remove all views - var view; - var len = this.length; + var view; + var len = this.length; - if(!this.length) return; + if(!this.length) return; - for (var i = 0; i < len; i++) { - view = this._views[i]; + for (var i = 0; i < len; i++) { + view = this._views[i]; this.destroy(view); - } + } - this._views = []; - this.length = 0; + this._views = []; + this.length = 0; }; Views.prototype.find = function(section){ - var view; - var len = this.length; + var view; + var len = this.length; - for (var i = 0; i < len; i++) { - view = this._views[i]; + for (var i = 0; i < len; i++) { + view = this._views[i]; if(view.displayed && view.section.index == section.index) { return view; } - } + } }; Views.prototype.displayed = function(){ - var displayed = []; - var view; - var len = this.length; + var displayed = []; + var view; + var len = this.length; - for (var i = 0; i < len; i++) { - view = this._views[i]; - if(view.displayed){ - displayed.push(view); - } - } - return displayed; + for (var i = 0; i < len; i++) { + view = this._views[i]; + if(view.displayed){ + displayed.push(view); + } + } + return displayed; }; Views.prototype.show = function(){ - var view; - var len = this.length; + var view; + var len = this.length; - for (var i = 0; i < len; i++) { - view = this._views[i]; - if(view.displayed){ - view.show(); - } - } - this.hidden = false; + for (var i = 0; i < len; i++) { + view = this._views[i]; + if(view.displayed){ + view.show(); + } + } + this.hidden = false; }; Views.prototype.hide = function(){ - var view; - var len = this.length; + var view; + var len = this.length; - for (var i = 0; i < len; i++) { - view = this._views[i]; - if(view.displayed){ - view.hide(); - } - } - this.hidden = true; + for (var i = 0; i < len; i++) { + view = this._views[i]; + if(view.displayed){ + view.hide(); + } + } + this.hidden = true; }; module.exports = Views; diff --git a/src/views/iframe.js b/src/views/iframe.js index fdfba63..4bf59ab 100644 --- a/src/views/iframe.js +++ b/src/views/iframe.js @@ -4,110 +4,110 @@ var EpubCFI = require('../epubcfi'); var Contents = require('../contents'); function IframeView(section, options) { - this.settings = core.extend({ - ignoreClass : '', - axis: 'vertical', - width: 0, - height: 0, - layout: undefined, - globalLayoutProperties: {}, - }, options || {}); + this.settings = core.extend({ + ignoreClass : '', + axis: 'vertical', + width: 0, + height: 0, + layout: undefined, + globalLayoutProperties: {}, + }, options || {}); - this.id = "epubjs-view-" + core.uuid(); - this.section = section; - this.index = section.index; + this.id = "epubjs-view-" + core.uuid(); + this.section = section; + this.index = section.index; - this.element = this.container(this.settings.axis); + this.element = this.container(this.settings.axis); - this.added = false; - this.displayed = false; - this.rendered = false; + this.added = false; + this.displayed = false; + this.rendered = false; - this.width = this.settings.width; - this.height = this.settings.height; + this.width = this.settings.width; + this.height = this.settings.height; - this.fixedWidth = 0; - this.fixedHeight = 0; + this.fixedWidth = 0; + this.fixedHeight = 0; - // Blank Cfi for Parsing - this.epubcfi = new EpubCFI(); + // Blank Cfi for Parsing + this.epubcfi = new EpubCFI(); - this.layout = this.settings.layout; - // Dom events to listen for - // this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"]; + this.layout = this.settings.layout; + // Dom events to listen for + // this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"]; }; IframeView.prototype.container = function(axis) { - var element = document.createElement('div'); + var element = document.createElement('div'); - element.classList.add("epub-view"); + element.classList.add("epub-view"); - // this.element.style.minHeight = "100px"; - element.style.height = "0px"; - element.style.width = "0px"; - element.style.overflow = "hidden"; + // this.element.style.minHeight = "100px"; + element.style.height = "0px"; + element.style.width = "0px"; + element.style.overflow = "hidden"; - if(axis && axis == "horizontal"){ - element.style.display = "inline-block"; - } else { - element.style.display = "block"; - } + if(axis && axis == "horizontal"){ + element.style.display = "inline-block"; + } else { + element.style.display = "block"; + } - return element; + return element; }; IframeView.prototype.create = function() { - if(this.iframe) { - return this.iframe; - } + if(this.iframe) { + return this.iframe; + } - if(!this.element) { - this.element = this.createContainer(); - } + if(!this.element) { + this.element = this.createContainer(); + } - this.iframe = document.createElement('iframe'); - this.iframe.id = this.id; - this.iframe.scrolling = "no"; // Might need to be removed: breaks ios width calculations - this.iframe.style.overflow = "hidden"; - this.iframe.seamless = "seamless"; - // Back up if seamless isn't supported - this.iframe.style.border = "none"; + this.iframe = document.createElement('iframe'); + this.iframe.id = this.id; + this.iframe.scrolling = "no"; // Might need to be removed: breaks ios width calculations + this.iframe.style.overflow = "hidden"; + this.iframe.seamless = "seamless"; + // Back up if seamless isn't supported + this.iframe.style.border = "none"; - this.resizing = true; + this.resizing = true; - // this.iframe.style.display = "none"; - this.element.style.visibility = "hidden"; - this.iframe.style.visibility = "hidden"; + // this.iframe.style.display = "none"; + this.element.style.visibility = "hidden"; + this.iframe.style.visibility = "hidden"; - this.iframe.style.width = "0"; - this.iframe.style.height = "0"; - this._width = 0; - this._height = 0; + this.iframe.style.width = "0"; + this.iframe.style.height = "0"; + this._width = 0; + this._height = 0; - this.element.appendChild(this.iframe); - this.added = true; + this.element.appendChild(this.iframe); + this.added = true; - this.elementBounds = core.bounds(this.element); + this.elementBounds = core.bounds(this.element); - // if(width || height){ - // this.resize(width, height); - // } else if(this.width && this.height){ - // this.resize(this.width, this.height); - // } else { - // this.iframeBounds = core.bounds(this.iframe); - // } + // if(width || height){ + // this.resize(width, height); + // } else if(this.width && this.height){ + // this.resize(this.width, this.height); + // } else { + // this.iframeBounds = core.bounds(this.iframe); + // } - // Firefox has trouble with baseURI and srcdoc - // TODO: Disable for now in firefox + // Firefox has trouble with baseURI and srcdoc + // TODO: Disable for now in firefox - if(!!("srcdoc" in this.iframe)) { - this.supportsSrcdoc = true; - } else { - this.supportsSrcdoc = false; - } + if(!!("srcdoc" in this.iframe)) { + this.supportsSrcdoc = true; + } else { + this.supportsSrcdoc = false; + } - return this.iframe; + return this.iframe; }; IframeView.prototype.render = function(request, show) { @@ -116,11 +116,11 @@ IframeView.prototype.render = function(request, show) { this.create(); // Fit to size of the container, apply padding - this.size(); + this.size(); - if(!this.sectionRender) { - this.sectionRender = this.section.render(request); - } + if(!this.sectionRender) { + this.sectionRender = this.section.render(request); + } // Render Chain return this.sectionRender @@ -142,14 +142,14 @@ IframeView.prototype.render = function(request, show) { // }.bind(this)) .then(function(){ - // apply the layout function to the contents - this.settings.layout.format(this.contents); + // apply the layout function to the contents + this.settings.layout.format(this.contents); - // Expand the iframe to the full size of the content - this.expand(); + // Expand the iframe to the full size of the content + this.expand(); - // Listen for events that require an expansion of the iframe - this.addListeners(); + // Listen for events that require an expansion of the iframe + this.addListeners(); if(show !== false) { //this.q.enqueue(function(view){ @@ -169,12 +169,12 @@ IframeView.prototype.render = function(request, show) { // Determine locks base on settings IframeView.prototype.size = function(_width, _height) { - var width = _width || this.settings.width; - var height = _height || this.settings.height; + var width = _width || this.settings.width; + var height = _height || this.settings.height; - if(this.layout.name === "pre-paginated") { - this.lock("both", width, height); - } else if(this.settings.axis === "horizontal") { + if(this.layout.name === "pre-paginated") { + this.lock("both", width, height); + } else if(this.settings.axis === "horizontal") { this.lock("height", width, height); } else { this.lock("width", width, height); @@ -184,41 +184,41 @@ IframeView.prototype.size = function(_width, _height) { // Lock an axis to element dimensions, taking borders into account IframeView.prototype.lock = function(what, width, height) { - var elBorders = core.borders(this.element); - var iframeBorders; + var elBorders = core.borders(this.element); + var iframeBorders; - if(this.iframe) { - iframeBorders = core.borders(this.iframe); - } else { - iframeBorders = {width: 0, height: 0}; - } + if(this.iframe) { + iframeBorders = core.borders(this.iframe); + } else { + iframeBorders = {width: 0, height: 0}; + } - if(what == "width" && core.isNumber(width)){ - this.lockedWidth = width - elBorders.width - iframeBorders.width; - this.resize(this.lockedWidth, width); // width keeps ratio correct - } + if(what == "width" && core.isNumber(width)){ + this.lockedWidth = width - elBorders.width - iframeBorders.width; + this.resize(this.lockedWidth, width); // width keeps ratio correct + } - if(what == "height" && core.isNumber(height)){ - this.lockedHeight = height - elBorders.height - iframeBorders.height; - this.resize(width, this.lockedHeight); - } + if(what == "height" && core.isNumber(height)){ + this.lockedHeight = height - elBorders.height - iframeBorders.height; + this.resize(width, this.lockedHeight); + } - if(what === "both" && - core.isNumber(width) && - core.isNumber(height)){ + if(what === "both" && + core.isNumber(width) && + core.isNumber(height)){ - this.lockedWidth = width - elBorders.width - iframeBorders.width; - this.lockedHeight = height - elBorders.height - iframeBorders.height; + this.lockedWidth = width - elBorders.width - iframeBorders.width; + this.lockedHeight = height - elBorders.height - iframeBorders.height; - this.resize(this.lockedWidth, this.lockedHeight); - } + this.resize(this.lockedWidth, this.lockedHeight); + } - if(this.displayed && this.iframe) { + if(this.displayed && this.iframe) { - // this.contents.layout(); - this.expand(); + // this.contents.layout(); + this.expand(); - } + } @@ -226,209 +226,209 @@ IframeView.prototype.lock = function(what, width, height) { // Resize a single axis based on content dimensions IframeView.prototype.expand = function(force) { - var width = this.lockedWidth; - var height = this.lockedHeight; - var columns; + var width = this.lockedWidth; + var height = this.lockedHeight; + var columns; - var textWidth, textHeight; + var textWidth, textHeight; - if(!this.iframe || this._expanding) return; + if(!this.iframe || this._expanding) return; - this._expanding = true; + this._expanding = true; - // Expand Horizontally - // if(height && !width) { - if(this.settings.axis === "horizontal") { - // Get the width of the text - textWidth = this.contents.textWidth(); - // Check if the textWidth has changed - if(textWidth != this._textWidth){ - // Get the contentWidth by resizing the iframe - // Check with a min reset of the textWidth - width = this.contentWidth(textWidth); + // Expand Horizontally + // if(height && !width) { + if(this.settings.axis === "horizontal") { + // Get the width of the text + textWidth = this.contents.textWidth(); + // Check if the textWidth has changed + if(textWidth != this._textWidth){ + // Get the contentWidth by resizing the iframe + // Check with a min reset of the textWidth + width = this.contentWidth(textWidth); - columns = Math.ceil(width / (this.settings.layout.columnWidth + this.settings.layout.gap)); + columns = Math.ceil(width / (this.settings.layout.columnWidth + this.settings.layout.gap)); - if ( this.settings.layout.divisor > 1 && - this.settings.layout.name === "reflowable" && - (columns % 2 > 0)) { - // add a blank page - width += this.settings.layout.gap + this.settings.layout.columnWidth; - } + if ( this.settings.layout.divisor > 1 && + this.settings.layout.name === "reflowable" && + (columns % 2 > 0)) { + // add a blank page + width += this.settings.layout.gap + this.settings.layout.columnWidth; + } - // Save the textWdith - this._textWidth = textWidth; - // Save the contentWidth - this._contentWidth = width; - } else { - // Otherwise assume content height hasn't changed - width = this._contentWidth; - } - } // Expand Vertically - else if(this.settings.axis === "vertical") { - textHeight = this.contents.textHeight(); - if(textHeight != this._textHeight){ - height = this.contentHeight(textHeight); - this._textHeight = textHeight; - this._contentHeight = height; - } else { - height = this._contentHeight; - } + // Save the textWdith + this._textWidth = textWidth; + // Save the contentWidth + this._contentWidth = width; + } else { + // Otherwise assume content height hasn't changed + width = this._contentWidth; + } + } // Expand Vertically + else if(this.settings.axis === "vertical") { + textHeight = this.contents.textHeight(); + if(textHeight != this._textHeight){ + height = this.contentHeight(textHeight); + this._textHeight = textHeight; + this._contentHeight = height; + } else { + height = this._contentHeight; + } - } + } - // Only Resize if dimensions have changed or - // if Frame is still hidden, so needs reframing - if(this._needsReframe || width != this._width || height != this._height){ - this.resize(width, height); - } + // Only Resize if dimensions have changed or + // if Frame is still hidden, so needs reframing + if(this._needsReframe || width != this._width || height != this._height){ + this.resize(width, height); + } - this._expanding = false; + this._expanding = false; }; IframeView.prototype.contentWidth = function(min) { - var prev; - var width; + var prev; + var width; - // Save previous width - prev = this.iframe.style.width; - // Set the iframe size to min, width will only ever be greater - // Will preserve the aspect ratio - this.iframe.style.width = (min || 0) + "px"; - // Get the scroll overflow width - width = this.contents.scrollWidth(); - // Reset iframe size back - this.iframe.style.width = prev; - return width; + // Save previous width + prev = this.iframe.style.width; + // Set the iframe size to min, width will only ever be greater + // Will preserve the aspect ratio + this.iframe.style.width = (min || 0) + "px"; + // Get the scroll overflow width + width = this.contents.scrollWidth(); + // Reset iframe size back + this.iframe.style.width = prev; + return width; }; IframeView.prototype.contentHeight = function(min) { - var prev; - var height; + var prev; + var height; - prev = this.iframe.style.height; - this.iframe.style.height = (min || 0) + "px"; - height = this.contents.scrollHeight(); + prev = this.iframe.style.height; + this.iframe.style.height = (min || 0) + "px"; + height = this.contents.scrollHeight(); - this.iframe.style.height = prev; - return height; + this.iframe.style.height = prev; + return height; }; IframeView.prototype.resize = function(width, height) { - if(!this.iframe) return; + if(!this.iframe) return; - if(core.isNumber(width)){ - this.iframe.style.width = width + "px"; - this._width = width; - } + if(core.isNumber(width)){ + this.iframe.style.width = width + "px"; + this._width = width; + } - if(core.isNumber(height)){ - this.iframe.style.height = height + "px"; - this._height = height; - } + if(core.isNumber(height)){ + this.iframe.style.height = height + "px"; + this._height = height; + } - this.iframeBounds = core.bounds(this.iframe); + this.iframeBounds = core.bounds(this.iframe); - this.reframe(this.iframeBounds.width, this.iframeBounds.height); + this.reframe(this.iframeBounds.width, this.iframeBounds.height); }; IframeView.prototype.reframe = function(width, height) { - var size; + var size; - // if(!this.displayed) { - // this._needsReframe = true; - // return; - // } - if(core.isNumber(width)){ - this.element.style.width = width + "px"; - } + // if(!this.displayed) { + // this._needsReframe = true; + // return; + // } + if(core.isNumber(width)){ + this.element.style.width = width + "px"; + } - if(core.isNumber(height)){ - this.element.style.height = height + "px"; - } + if(core.isNumber(height)){ + this.element.style.height = height + "px"; + } - this.prevBounds = this.elementBounds; + this.prevBounds = this.elementBounds; - this.elementBounds = core.bounds(this.element); + this.elementBounds = core.bounds(this.element); - size = { - width: this.elementBounds.width, - height: this.elementBounds.height, - widthDelta: this.elementBounds.width - this.prevBounds.width, - heightDelta: this.elementBounds.height - this.prevBounds.height, - }; + size = { + width: this.elementBounds.width, + height: this.elementBounds.height, + widthDelta: this.elementBounds.width - this.prevBounds.width, + heightDelta: this.elementBounds.height - this.prevBounds.height, + }; - this.onResize(this, size); + this.onResize(this, size); - this.trigger("resized", size); + this.trigger("resized", size); }; IframeView.prototype.load = function(contents) { - var loading = new RSVP.defer(); - var loaded = loading.promise; + var loading = new RSVP.defer(); + var loaded = loading.promise; - if(!this.iframe) { - loading.reject(new Error("No Iframe Available")); - return loaded; - } + if(!this.iframe) { + loading.reject(new Error("No Iframe Available")); + return loaded; + } - this.iframe.onload = function(event) { + this.iframe.onload = function(event) { - this.onLoad(event, loading); + this.onLoad(event, loading); - }.bind(this); + }.bind(this); - if(this.supportsSrcdoc){ - this.iframe.srcdoc = contents; - } else { + if(this.supportsSrcdoc){ + this.iframe.srcdoc = contents; + } else { - this.document = this.iframe.contentDocument; + this.document = this.iframe.contentDocument; - if(!this.document) { - loading.reject(new Error("No Document Available")); - return loaded; - } + if(!this.document) { + loading.reject(new Error("No Document Available")); + return loaded; + } - this.iframe.contentDocument.open(); - this.iframe.contentDocument.write(contents); - this.iframe.contentDocument.close(); + this.iframe.contentDocument.open(); + this.iframe.contentDocument.write(contents); + this.iframe.contentDocument.close(); - } + } - return loaded; + return loaded; }; IframeView.prototype.onLoad = function(event, promise) { - this.window = this.iframe.contentWindow; - this.document = this.iframe.contentDocument; + this.window = this.iframe.contentWindow; + this.document = this.iframe.contentDocument; - this.contents = new Contents(this.document, this.document.body, this.section.cfiBase); + this.contents = new Contents(this.document, this.document.body, this.section.cfiBase); - this.rendering = false; + this.rendering = false; - var link = this.document.querySelector("link[rel='canonical']"); - if (link) { - link.setAttribute("href", this.section.url); - } else { - link = this.document.createElement("link"); - link.setAttribute("rel", "canonical"); - link.setAttribute("href", this.section.url); - this.document.querySelector("head").appendChild(link); - } + var link = this.document.querySelector("link[rel='canonical']"); + if (link) { + link.setAttribute("href", this.section.url); + } else { + link = this.document.createElement("link"); + link.setAttribute("rel", "canonical"); + link.setAttribute("href", this.section.url); + this.document.querySelector("head").appendChild(link); + } - this.contents.on("expand", function () { - if(this.displayed && this.iframe) { - this.expand(); - } - }); + this.contents.on("expand", function () { + if(this.displayed && this.iframe) { + this.expand(); + } + }); - promise.resolve(this.contents); + promise.resolve(this.contents); }; @@ -455,118 +455,118 @@ IframeView.prototype.onLoad = function(event, promise) { // }; IframeView.prototype.setLayout = function(layout) { - this.layout = layout; + this.layout = layout; }; IframeView.prototype.setAxis = function(axis) { - this.settings.axis = axis; + this.settings.axis = axis; }; IframeView.prototype.resizeListenters = function() { - // Test size again - clearTimeout(this.expanding); - this.expanding = setTimeout(this.expand.bind(this), 350); + // Test size again + clearTimeout(this.expanding); + this.expanding = setTimeout(this.expand.bind(this), 350); }; IframeView.prototype.addListeners = function() { - //TODO: Add content listeners for expanding + //TODO: Add content listeners for expanding }; IframeView.prototype.removeListeners = function(layoutFunc) { - //TODO: remove content listeners for expanding + //TODO: remove content listeners for expanding }; IframeView.prototype.display = function(request) { - var displayed = new RSVP.defer(); + var displayed = new RSVP.defer(); - if (!this.displayed) { + if (!this.displayed) { - this.render(request).then(function () { + this.render(request).then(function () { - this.trigger("displayed", this); - this.onDisplayed(this); + this.trigger("displayed", this); + this.onDisplayed(this); - this.displayed = true; - displayed.resolve(this); + this.displayed = true; + displayed.resolve(this); - }.bind(this)); + }.bind(this)); - } else { - displayed.resolve(this); - } + } else { + displayed.resolve(this); + } - return displayed.promise; + return displayed.promise; }; IframeView.prototype.show = function() { - this.element.style.visibility = "visible"; + this.element.style.visibility = "visible"; - if(this.iframe){ - this.iframe.style.visibility = "visible"; - } + if(this.iframe){ + this.iframe.style.visibility = "visible"; + } - this.trigger("shown", this); + this.trigger("shown", this); }; IframeView.prototype.hide = function() { - // this.iframe.style.display = "none"; - this.element.style.visibility = "hidden"; - this.iframe.style.visibility = "hidden"; + // this.iframe.style.display = "none"; + this.element.style.visibility = "hidden"; + this.iframe.style.visibility = "hidden"; - this.stopExpanding = true; - this.trigger("hidden", this); + this.stopExpanding = true; + this.trigger("hidden", this); }; IframeView.prototype.position = function() { - return this.element.getBoundingClientRect(); + return this.element.getBoundingClientRect(); }; IframeView.prototype.locationOf = function(target) { - var parentPos = this.iframe.getBoundingClientRect(); - var targetPos = this.contents.locationOf(target, this.settings.ignoreClass); + var parentPos = this.iframe.getBoundingClientRect(); + var targetPos = this.contents.locationOf(target, this.settings.ignoreClass); - return { - "left": window.scrollX + parentPos.left + targetPos.left, - "top": window.scrollY + parentPos.top + targetPos.top - }; + return { + "left": window.scrollX + parentPos.left + targetPos.left, + "top": window.scrollY + parentPos.top + targetPos.top + }; }; IframeView.prototype.onDisplayed = function(view) { - // Stub, override with a custom functions + // Stub, override with a custom functions }; IframeView.prototype.onResize = function(view, e) { - // Stub, override with a custom functions + // Stub, override with a custom functions }; IframeView.prototype.bounds = function() { - if(!this.elementBounds) { - this.elementBounds = core.bounds(this.element); - } - return this.elementBounds; + if(!this.elementBounds) { + this.elementBounds = core.bounds(this.element); + } + return this.elementBounds; }; IframeView.prototype.destroy = function() { - if(this.displayed){ - this.displayed = false; + if(this.displayed){ + this.displayed = false; - this.removeListeners(); + this.removeListeners(); - this.stopExpanding = true; - this.element.removeChild(this.iframe); - this.displayed = false; - this.iframe = null; + this.stopExpanding = true; + this.element.removeChild(this.iframe); + this.displayed = false; + this.iframe = null; - this._textWidth = null; - this._textHeight = null; - this._width = null; - this._height = null; - } - // this.element.style.height = "0px"; - // this.element.style.width = "0px"; + this._textWidth = null; + this._textHeight = null; + this._width = null; + this._height = null; + } + // this.element.style.height = "0px"; + // this.element.style.width = "0px"; }; RSVP.EventTarget.mixin(IframeView.prototype); diff --git a/src/views/inline.js b/src/views/inline.js index d903d36..ade5a04 100644 --- a/src/views/inline.js +++ b/src/views/inline.js @@ -5,103 +5,103 @@ var Contents = require('../contents'); var URI = require('urijs'); function InlineView(section, options) { - this.settings = core.extend({ - ignoreClass : '', - axis: 'vertical', - width: 0, - height: 0, - layout: undefined, - globalLayoutProperties: {}, - }, options || {}); + this.settings = core.extend({ + ignoreClass : '', + axis: 'vertical', + width: 0, + height: 0, + layout: undefined, + globalLayoutProperties: {}, + }, options || {}); - this.id = "epubjs-view:" + core.uuid(); - this.section = section; - this.index = section.index; + this.id = "epubjs-view:" + core.uuid(); + this.section = section; + this.index = section.index; - this.element = this.container(this.settings.axis); + this.element = this.container(this.settings.axis); - this.added = false; - this.displayed = false; - this.rendered = false; + this.added = false; + this.displayed = false; + this.rendered = false; - this.width = this.settings.width; - this.height = this.settings.height; + this.width = this.settings.width; + this.height = this.settings.height; - this.fixedWidth = 0; - this.fixedHeight = 0; + this.fixedWidth = 0; + this.fixedHeight = 0; - // Blank Cfi for Parsing - this.epubcfi = new EpubCFI(); + // Blank Cfi for Parsing + this.epubcfi = new EpubCFI(); - this.layout = this.settings.layout; - // Dom events to listen for - // this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"]; + this.layout = this.settings.layout; + // Dom events to listen for + // this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"]; }; InlineView.prototype.container = function(axis) { - var element = document.createElement('div'); + var element = document.createElement('div'); - element.classList.add("epub-view"); + element.classList.add("epub-view"); - // if(this.settings.axis === "horizontal") { - // element.style.width = "auto"; - // element.style.height = "0"; + // if(this.settings.axis === "horizontal") { + // element.style.width = "auto"; + // element.style.height = "0"; // } else { - // element.style.width = "0"; - // element.style.height = "auto"; + // element.style.width = "0"; + // element.style.height = "auto"; // } - element.style.overflow = "hidden"; + element.style.overflow = "hidden"; - if(axis && axis == "horizontal"){ - element.style.display = "inline-block"; - } else { - element.style.display = "block"; - } + if(axis && axis == "horizontal"){ + element.style.display = "inline-block"; + } else { + element.style.display = "block"; + } - return element; + return element; }; InlineView.prototype.create = function() { - if(this.frame) { - return this.frame; - } - - if(!this.element) { - this.element = this.createContainer(); - } - - this.frame = document.createElement('div'); - this.frame.id = this.id; - this.frame.style.overflow = "hidden"; - this.frame.style.wordSpacing = "initial"; - this.frame.style.lineHeight = "initial"; - - this.resizing = true; - - // this.frame.style.display = "none"; - this.element.style.visibility = "hidden"; - this.frame.style.visibility = "hidden"; - - if(this.settings.axis === "horizontal") { - this.frame.style.width = "auto"; - this.frame.style.height = "0"; - } else { - this.frame.style.width = "0"; - this.frame.style.height = "auto"; + if(this.frame) { + return this.frame; } - this._width = 0; - this._height = 0; + if(!this.element) { + this.element = this.createContainer(); + } - this.element.appendChild(this.frame); - this.added = true; + this.frame = document.createElement('div'); + this.frame.id = this.id; + this.frame.style.overflow = "hidden"; + this.frame.style.wordSpacing = "initial"; + this.frame.style.lineHeight = "initial"; - this.elementBounds = core.bounds(this.element); + this.resizing = true; - return this.frame; + // this.frame.style.display = "none"; + this.element.style.visibility = "hidden"; + this.frame.style.visibility = "hidden"; + + if(this.settings.axis === "horizontal") { + this.frame.style.width = "auto"; + this.frame.style.height = "0"; + } else { + this.frame.style.width = "0"; + this.frame.style.height = "auto"; + } + + this._width = 0; + this._height = 0; + + this.element.appendChild(this.frame); + this.added = true; + + this.elementBounds = core.bounds(this.element); + + return this.frame; }; InlineView.prototype.render = function(request, show) { @@ -110,7 +110,7 @@ InlineView.prototype.render = function(request, show) { this.create(); // Fit to size of the container, apply padding - this.size(); + this.size(); // Render Chain return this.section.render(request) @@ -132,14 +132,14 @@ InlineView.prototype.render = function(request, show) { // }.bind(this)) .then(function(){ - // apply the layout function to the contents - this.settings.layout.format(this.contents); + // apply the layout function to the contents + this.settings.layout.format(this.contents); - // Expand the iframe to the full size of the content - // this.expand(); + // Expand the iframe to the full size of the content + // this.expand(); - // Listen for events that require an expansion of the iframe - this.addListeners(); + // Listen for events that require an expansion of the iframe + this.addListeners(); if(show !== false) { //this.q.enqueue(function(view){ @@ -159,13 +159,13 @@ InlineView.prototype.render = function(request, show) { // Determine locks base on settings InlineView.prototype.size = function(_width, _height) { - var width = _width || this.settings.width; - var height = _height || this.settings.height; + var width = _width || this.settings.width; + var height = _height || this.settings.height; - if(this.layout.name === "pre-paginated") { - // TODO: check if these are different than the size set in chapter - this.lock("both", width, height); - } else if(this.settings.axis === "horizontal") { + if(this.layout.name === "pre-paginated") { + // TODO: check if these are different than the size set in chapter + this.lock("both", width, height); + } else if(this.settings.axis === "horizontal") { this.lock("height", width, height); } else { this.lock("width", width, height); @@ -175,253 +175,253 @@ InlineView.prototype.size = function(_width, _height) { // Lock an axis to element dimensions, taking borders into account InlineView.prototype.lock = function(what, width, height) { - var elBorders = core.borders(this.element); - var iframeBorders; + var elBorders = core.borders(this.element); + var iframeBorders; - if(this.frame) { - iframeBorders = core.borders(this.frame); - } else { - iframeBorders = {width: 0, height: 0}; - } + if(this.frame) { + iframeBorders = core.borders(this.frame); + } else { + iframeBorders = {width: 0, height: 0}; + } - if(what == "width" && core.isNumber(width)){ - this.lockedWidth = width - elBorders.width - iframeBorders.width; - this.resize(this.lockedWidth, false); // width keeps ratio correct - } + if(what == "width" && core.isNumber(width)){ + this.lockedWidth = width - elBorders.width - iframeBorders.width; + this.resize(this.lockedWidth, false); // width keeps ratio correct + } - if(what == "height" && core.isNumber(height)){ - this.lockedHeight = height - elBorders.height - iframeBorders.height; - this.resize(false, this.lockedHeight); - } + if(what == "height" && core.isNumber(height)){ + this.lockedHeight = height - elBorders.height - iframeBorders.height; + this.resize(false, this.lockedHeight); + } - if(what === "both" && - core.isNumber(width) && - core.isNumber(height)){ + if(what === "both" && + core.isNumber(width) && + core.isNumber(height)){ - this.lockedWidth = width - elBorders.width - iframeBorders.width; - this.lockedHeight = height - elBorders.height - iframeBorders.height; + this.lockedWidth = width - elBorders.width - iframeBorders.width; + this.lockedHeight = height - elBorders.height - iframeBorders.height; - this.resize(this.lockedWidth, this.lockedHeight); - } + this.resize(this.lockedWidth, this.lockedHeight); + } }; // Resize a single axis based on content dimensions InlineView.prototype.expand = function(force) { - var width = this.lockedWidth; - var height = this.lockedHeight; + var width = this.lockedWidth; + var height = this.lockedHeight; - var textWidth, textHeight; + var textWidth, textHeight; - if(!this.frame || this._expanding) return; + if(!this.frame || this._expanding) return; - this._expanding = true; + this._expanding = true; - // Expand Horizontally - if(this.settings.axis === "horizontal") { - width = this.contentWidth(textWidth); - } // Expand Vertically - else if(this.settings.axis === "vertical") { - height = this.contentHeight(textHeight); - } + // Expand Horizontally + if(this.settings.axis === "horizontal") { + width = this.contentWidth(textWidth); + } // Expand Vertically + else if(this.settings.axis === "vertical") { + height = this.contentHeight(textHeight); + } - // Only Resize if dimensions have changed or - // if Frame is still hidden, so needs reframing - if(this._needsReframe || width != this._width || height != this._height){ - this.resize(width, height); - } + // Only Resize if dimensions have changed or + // if Frame is still hidden, so needs reframing + if(this._needsReframe || width != this._width || height != this._height){ + this.resize(width, height); + } - this._expanding = false; + this._expanding = false; }; InlineView.prototype.contentWidth = function(min) { - return this.frame.scrollWidth; + return this.frame.scrollWidth; }; InlineView.prototype.contentHeight = function(min) { - console.log(this.frame.scrollHeight); - return this.frame.scrollHeight; + console.log(this.frame.scrollHeight); + return this.frame.scrollHeight; }; InlineView.prototype.resize = function(width, height) { - if(!this.frame) return; + if(!this.frame) return; - if(core.isNumber(width)){ - this.frame.style.width = width + "px"; - this._width = width; - } + if(core.isNumber(width)){ + this.frame.style.width = width + "px"; + this._width = width; + } - if(core.isNumber(height)){ - this.frame.style.height = height + "px"; - this._height = height; - } + if(core.isNumber(height)){ + this.frame.style.height = height + "px"; + this._height = height; + } - this.prevBounds = this.elementBounds; + this.prevBounds = this.elementBounds; - this.elementBounds = core.bounds(this.element); + this.elementBounds = core.bounds(this.element); - size = { - width: this.elementBounds.width, - height: this.elementBounds.height, - widthDelta: this.elementBounds.width - this.prevBounds.width, - heightDelta: this.elementBounds.height - this.prevBounds.height, - }; + size = { + width: this.elementBounds.width, + height: this.elementBounds.height, + widthDelta: this.elementBounds.width - this.prevBounds.width, + heightDelta: this.elementBounds.height - this.prevBounds.height, + }; - this.onResize(this, size); + this.onResize(this, size); - this.trigger("resized", size); + this.trigger("resized", size); }; InlineView.prototype.load = function(contents) { - var loading = new RSVP.defer(); - var loaded = loading.promise; - var doc = core.parse(contents, "text/html"); - var body = core.qs(doc, "body"); + var loading = new RSVP.defer(); + var loaded = loading.promise; + var doc = core.parse(contents, "text/html"); + var body = core.qs(doc, "body"); - var srcs = doc.querySelectorAll("[src]"); - Array.prototype.slice.call(srcs) - .forEach(function(item) { - var src = item.getAttribute('src'); - var assetUri = URI(src); - var origin = assetUri.origin(); - var absoluteUri; + var srcs = doc.querySelectorAll("[src]"); + Array.prototype.slice.call(srcs) + .forEach(function(item) { + var src = item.getAttribute('src'); + var assetUri = URI(src); + var origin = assetUri.origin(); + var absoluteUri; - if (!origin) { - absoluteUri = assetUri.absoluteTo(this.section.url); - item.src = absoluteUri; - } - }.bind(this)); + if (!origin) { + absoluteUri = assetUri.absoluteTo(this.section.url); + item.src = absoluteUri; + } + }.bind(this)); - this.frame.innerHTML = body.innerHTML; + this.frame.innerHTML = body.innerHTML; - this.document = this.frame.ownerDocument; - this.window = this.document.defaultView; + this.document = this.frame.ownerDocument; + this.window = this.document.defaultView; - this.contents = new Contents(this.document, this.frame); + this.contents = new Contents(this.document, this.frame); - this.rendering = false; + this.rendering = false; - loading.resolve(this.contents); + loading.resolve(this.contents); - return loaded; + return loaded; }; InlineView.prototype.setLayout = function(layout) { - this.layout = layout; + this.layout = layout; }; InlineView.prototype.resizeListenters = function() { - // Test size again - // clearTimeout(this.expanding); - // this.expanding = setTimeout(this.expand.bind(this), 350); + // Test size again + // clearTimeout(this.expanding); + // this.expanding = setTimeout(this.expand.bind(this), 350); }; InlineView.prototype.addListeners = function() { - //TODO: Add content listeners for expanding + //TODO: Add content listeners for expanding }; InlineView.prototype.removeListeners = function(layoutFunc) { - //TODO: remove content listeners for expanding + //TODO: remove content listeners for expanding }; InlineView.prototype.display = function(request) { - var displayed = new RSVP.defer(); + var displayed = new RSVP.defer(); - if (!this.displayed) { + if (!this.displayed) { - this.render(request).then(function () { + this.render(request).then(function () { - this.trigger("displayed", this); - this.onDisplayed(this); + this.trigger("displayed", this); + this.onDisplayed(this); - this.displayed = true; + this.displayed = true; - displayed.resolve(this); + displayed.resolve(this); - }.bind(this)); + }.bind(this)); - } else { - displayed.resolve(this); - } + } else { + displayed.resolve(this); + } - return displayed.promise; + return displayed.promise; }; InlineView.prototype.show = function() { - this.element.style.visibility = "visible"; + this.element.style.visibility = "visible"; - if(this.frame){ - this.frame.style.visibility = "visible"; - } + if(this.frame){ + this.frame.style.visibility = "visible"; + } - this.trigger("shown", this); + this.trigger("shown", this); }; InlineView.prototype.hide = function() { - // this.frame.style.display = "none"; - this.element.style.visibility = "hidden"; - this.frame.style.visibility = "hidden"; + // this.frame.style.display = "none"; + this.element.style.visibility = "hidden"; + this.frame.style.visibility = "hidden"; - this.stopExpanding = true; - this.trigger("hidden", this); + this.stopExpanding = true; + this.trigger("hidden", this); }; InlineView.prototype.position = function() { - return this.element.getBoundingClientRect(); + return this.element.getBoundingClientRect(); }; InlineView.prototype.locationOf = function(target) { - var parentPos = this.frame.getBoundingClientRect(); - var targetPos = this.contents.locationOf(target, this.settings.ignoreClass); + var parentPos = this.frame.getBoundingClientRect(); + var targetPos = this.contents.locationOf(target, this.settings.ignoreClass); - return { - "left": window.scrollX + parentPos.left + targetPos.left, - "top": window.scrollY + parentPos.top + targetPos.top - }; + return { + "left": window.scrollX + parentPos.left + targetPos.left, + "top": window.scrollY + parentPos.top + targetPos.top + }; }; InlineView.prototype.onDisplayed = function(view) { - // Stub, override with a custom functions + // Stub, override with a custom functions }; InlineView.prototype.onResize = function(view, e) { - // Stub, override with a custom functions + // Stub, override with a custom functions }; InlineView.prototype.bounds = function() { - if(!this.elementBounds) { - this.elementBounds = core.bounds(this.element); - } - return this.elementBounds; + if(!this.elementBounds) { + this.elementBounds = core.bounds(this.element); + } + return this.elementBounds; }; InlineView.prototype.destroy = function() { - if(this.displayed){ - this.displayed = false; + if(this.displayed){ + this.displayed = false; - this.removeListeners(); + this.removeListeners(); - this.stopExpanding = true; - this.element.removeChild(this.frame); - this.displayed = false; - this.frame = null; + this.stopExpanding = true; + this.element.removeChild(this.frame); + this.displayed = false; + this.frame = null; - this._textWidth = null; - this._textHeight = null; - this._width = null; - this._height = null; - } - // this.element.style.height = "0px"; - // this.element.style.width = "0px"; + this._textWidth = null; + this._textHeight = null; + this._width = null; + this._height = null; + } + // this.element.style.height = "0px"; + // this.element.style.width = "0px"; }; RSVP.EventTarget.mixin(InlineView.prototype); diff --git a/test/epub.js b/test/epub.js index 0b2e076..f3e5365 100644 --- a/test/epub.js +++ b/test/epub.js @@ -4,36 +4,36 @@ var fs = require('fs'); describe('ePub', function() { - var ePub = require('../src/epub'); - var server; - before(function(){ - var packageContents = fs.readFileSync(__dirname + '/../books/moby-dick/OPS/package.opf', 'utf8'); - var tocContents = fs.readFileSync(__dirname + '/../books/moby-dick/OPS/toc.xhtml', 'utf8'); + var ePub = require('../src/epub'); + var server; + before(function(){ + var packageContents = fs.readFileSync(__dirname + '/../books/moby-dick/OPS/package.opf', 'utf8'); + var tocContents = fs.readFileSync(__dirname + '/../books/moby-dick/OPS/toc.xhtml', 'utf8'); - server = sinon.fakeServer.create(); - server.autoRespond = true; + server = sinon.fakeServer.create(); + server.autoRespond = true; - server.respondWith("moby-dick/OPS/package.opf", [200, { - "Content-Type": "text/xml" - }, packageContents]); + server.respondWith("moby-dick/OPS/package.opf", [200, { + "Content-Type": "text/xml" + }, packageContents]); - server.respondWith("moby-dick/OPS/toc.xhtml", [200, { - "Content-Type": "application/xhtml+xml" - }, tocContents]); + server.respondWith("moby-dick/OPS/toc.xhtml", [200, { + "Content-Type": "application/xhtml+xml" + }, tocContents]); - }); - after(function(){ - server.restore(); - }); + }); + after(function(){ + server.restore(); + }); - it('should open a epub', function(done) { - var book = ePub("moby-dick/OPS/package.opf"); + it('should open a epub', function(done) { + var book = ePub("moby-dick/OPS/package.opf"); - book.opened.then(function(){ - assert.equal( book.isOpen, true, "book is opened" ); - assert.equal( book.url, "moby-dick/OPS/package.opf", "book url is passed to new Book" ); - done(); - }); - }); + book.opened.then(function(){ + assert.equal( book.isOpen, true, "book is opened" ); + assert.equal( book.url, "moby-dick/OPS/package.opf", "book url is passed to new Book" ); + done(); + }); + }); }); diff --git a/test/epubcfi.js b/test/epubcfi.js index 033122d..df72d00 100644 --- a/test/epubcfi.js +++ b/test/epubcfi.js @@ -1,11 +1,11 @@ var assert = require('assert'); var fs = require('fs'); if (typeof DOMParser === "undefined") { - global.DOMParser = require('xmldom').DOMParser; + global.DOMParser = require('xmldom').DOMParser; } describe('EpubCFI', function() { - var EpubCFI = require('../src/epubcfi.js'); + var EpubCFI = require('../src/epubcfi.js'); it('parse a cfi on init', function() { var cfi = EpubCFI("epubcfi(/6/2[cover]!/6)"); @@ -19,58 +19,58 @@ describe('EpubCFI', function() { assert.equal( cfi.spinePos, 0, "base is ignored and spinePos is parsed as the first item" ); }); - describe('#parse()', function() { + describe('#parse()', function() { var cfi = new EpubCFI(); it('parse a cfi on init', function() { - var parsed = cfi.parse("epubcfi(/6/2[cover]!/6)"); + var parsed = cfi.parse("epubcfi(/6/2[cover]!/6)"); - assert.equal( parsed.spinePos, 0, "spinePos is parsed as the first item" ); - }); + assert.equal( parsed.spinePos, 0, "spinePos is parsed as the first item" ); + }); it('parse a cfi and ignore the base if present', function() { - var parsed = cfi.parse("epubcfi(/6/2[cover]!/6)", "/6/6[end]"); + var parsed = cfi.parse("epubcfi(/6/2[cover]!/6)", "/6/6[end]"); - assert.equal( parsed.spinePos, 0, "base is ignored and spinePos is parsed as the first item" ); - }); + assert.equal( parsed.spinePos, 0, "base is ignored and spinePos is parsed as the first item" ); + }); it('parse a cfi with a charecter offset', function() { - var parsed = cfi.parse("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)"); + var parsed = cfi.parse("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)"); - assert.equal( parsed.path.terminal.offset, 3, "Path has a terminal offset of 3" ); - }); + assert.equal( parsed.path.terminal.offset, 3, "Path has a terminal offset of 3" ); + }); it('parse a cfi with a range', function() { - var parsed = cfi.parse("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)"); + var parsed = cfi.parse("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)"); assert.equal( parsed.range, true, "Range is true" ); assert.equal( parsed.start.steps.length, 2, "Start steps are present" ); - assert.equal( parsed.end.steps.length, 1, "End steps are present" ); + assert.equal( parsed.end.steps.length, 1, "End steps are present" ); assert.equal( parsed.start.terminal.offset, 1, "Start has a terminal offset of 1" ); assert.equal( parsed.end.terminal.offset, 4, "End has a terminal offset of 4" ); - }); + }); - }); + }); describe('#toString()', function() { - it('parse a cfi and write it back', function() { + it('parse a cfi and write it back', function() { - assert.equal(EpubCFI("epubcfi(/6/2[cover]!/6)").toString(), "epubcfi(/6/2[cover]!/6)", "output cfi string is same as input" ); + assert.equal(EpubCFI("epubcfi(/6/2[cover]!/6)").toString(), "epubcfi(/6/2[cover]!/6)", "output cfi string is same as input" ); assert.equal(EpubCFI("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)").toString(), "epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)", "output cfi string is same as input" ); assert.equal(EpubCFI("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)").toString(), "epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)", "output cfi string is same as input" ); - }); - }); + }); + }); describe('#checkType()', function() { - it('determine the type of a cfi string', function() { + it('determine the type of a cfi string', function() { var cfi = new EpubCFI(); assert.equal( cfi.checkType('epubcfi(/6/2[cover]!/6)'), 'string' ); assert.equal( cfi.checkType('/6/2[cover]!/6'), false ); - }); + }); it('determine the type of a cfi', function() { var ogcfi = EpubCFI("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)"); @@ -96,10 +96,10 @@ describe('EpubCFI', function() { }); - }); + }); describe('#compare()', function() { - it('compare CFIs', function() { + it('compare CFIs', function() { var epubcfi = new EpubCFI(); // Spines @@ -131,272 +131,272 @@ describe('EpubCFI', function() { assert.equal(epubcfi.compare("epubcfi(/6/2[cover]!/4/8/5:1)", "epubcfi(/6/2[cover]!/4/6/15:2)"), 1, "First Element is greater"); assert.equal(epubcfi.compare("epubcfi(/6/2[cover]!/4/8/1:0)", "epubcfi(/6/2[cover]!/4/8/1:0)"), 0, "All Equal"); - }); - }); + }); + }); - describe('#fromNode()', function() { - var base = "/6/4[chap01ref]"; - var contents = fs.readFileSync(__dirname + '/fixtures/chapter1-highlights.xhtml', 'utf8'); - // var serializer = new XMLSerializer(); - // var doc = serializer.serializeToString(contents); - var doc = new DOMParser().parseFromString(contents, "application/xhtml+xml"); + describe('#fromNode()', function() { + var base = "/6/4[chap01ref]"; + var contents = fs.readFileSync(__dirname + '/fixtures/chapter1-highlights.xhtml', 'utf8'); + // var serializer = new XMLSerializer(); + // var doc = serializer.serializeToString(contents); + var doc = new DOMParser().parseFromString(contents, "application/xhtml+xml"); - it('get a cfi from a p node', function() { - var span = doc.getElementById('c001p0004'); - var cfi = new EpubCFI(span, base); + it('get a cfi from a p node', function() { + var span = doc.getElementById('c001p0004'); + var cfi = new EpubCFI(span, base); - assert.equal(span.nodeType, Node.ELEMENT_NODE, "provided a element node"); + assert.equal(span.nodeType, Node.ELEMENT_NODE, "provided a element node"); assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/10/2[c001p0004])" ); - }); + }); - it('get a cfi from a text node', function() { - var t = doc.getElementById('c001p0004').childNodes[0]; - var cfi = new EpubCFI(t, base); + it('get a cfi from a text node', function() { + var t = doc.getElementById('c001p0004').childNodes[0]; + var cfi = new EpubCFI(t, base); - assert.equal(t.nodeType, Node.TEXT_NODE, "provided a text node"); - assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/10/2[c001p0004]/1)" ); + assert.equal(t.nodeType, Node.TEXT_NODE, "provided a text node"); + assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/10/2[c001p0004]/1)" ); - }); + }); - it('get a cfi from a text node inside a highlight', function() { - var t = doc.getElementById('highlight-1').childNodes[0]; - var cfi = new EpubCFI(t, base, 'annotator-hl'); + it('get a cfi from a text node inside a highlight', function() { + var t = doc.getElementById('highlight-1').childNodes[0]; + var cfi = new EpubCFI(t, base, 'annotator-hl'); - assert.equal(t.nodeType, Node.TEXT_NODE, "provided a text node"); - assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/32/2[c001p0017]/1)" ); + assert.equal(t.nodeType, Node.TEXT_NODE, "provided a text node"); + assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/32/2[c001p0017]/1)" ); - }); + }); - it('get a cfi from a highlight node', function() { - var t = doc.getElementById('highlight-1'); - var cfi = new EpubCFI(t, base, 'annotator-hl'); + it('get a cfi from a highlight node', function() { + var t = doc.getElementById('highlight-1'); + var cfi = new EpubCFI(t, base, 'annotator-hl'); - assert.equal(t.nodeType, Node.ELEMENT_NODE, "provided a highlight node"); - assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/32/2[c001p0017])" ); + assert.equal(t.nodeType, Node.ELEMENT_NODE, "provided a highlight node"); + assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/32/2[c001p0017])" ); - }); + }); - }); + }); - describe('#fromRange()', function() { - var base = "/6/4[chap01ref]"; + describe('#fromRange()', function() { + var base = "/6/4[chap01ref]"; - var contentsClean = fs.readFileSync(__dirname + '/fixtures/chapter1.xhtml', 'utf8'); - var doc = new DOMParser().parseFromString(contentsClean, "application/xhtml+xml"); + var contentsClean = fs.readFileSync(__dirname + '/fixtures/chapter1.xhtml', 'utf8'); + var doc = new DOMParser().parseFromString(contentsClean, "application/xhtml+xml"); - var contentsHighlights = fs.readFileSync(__dirname + '/fixtures/chapter1-highlights.xhtml', 'utf8'); - var docHighlights = new DOMParser().parseFromString(contentsHighlights, "application/xhtml+xml"); + var contentsHighlights = fs.readFileSync(__dirname + '/fixtures/chapter1-highlights.xhtml', 'utf8'); + var docHighlights = new DOMParser().parseFromString(contentsHighlights, "application/xhtml+xml"); - var highlightContents = fs.readFileSync(__dirname + '/fixtures/highlight.xhtml', 'utf8'); - var docHighlightsAlice = new DOMParser().parseFromString(highlightContents, "application/xhtml+xml"); + var highlightContents = fs.readFileSync(__dirname + '/fixtures/highlight.xhtml', 'utf8'); + var docHighlightsAlice = new DOMParser().parseFromString(highlightContents, "application/xhtml+xml"); - it('get a cfi from a collapsed range', function() { - var t1 = doc.getElementById('c001p0004').childNodes[0]; - var t2 = doc.getElementById('c001p0007').childNodes[0]; - var range = doc.createRange(); - var cfi; + it('get a cfi from a collapsed range', function() { + var t1 = doc.getElementById('c001p0004').childNodes[0]; + var t2 = doc.getElementById('c001p0007').childNodes[0]; + var range = doc.createRange(); + var cfi; - range.setStart(t1, 6); + range.setStart(t1, 6); - cfi = new EpubCFI(range, base); + cfi = new EpubCFI(range, base); - assert.equal( cfi.range, false); - assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/10/2[c001p0004]/1:6)" ); + assert.equal( cfi.range, false); + assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/10/2[c001p0004]/1:6)" ); - }); + }); - it('get a cfi from a range', function() { - var t1 = doc.getElementById('c001p0004').childNodes[0]; - var t2 = doc.getElementById('c001p0007').childNodes[0]; - var range = doc.createRange(); - var cfi; + it('get a cfi from a range', function() { + var t1 = doc.getElementById('c001p0004').childNodes[0]; + var t2 = doc.getElementById('c001p0007').childNodes[0]; + var range = doc.createRange(); + var cfi; - range.setStart(t1, 6); - range.setEnd(t2, 27); + range.setStart(t1, 6); + range.setEnd(t2, 27); - cfi = new EpubCFI(range, base); + cfi = new EpubCFI(range, base); - assert.equal( cfi.range, true); - assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2,/10/2[c001p0004]/1:6,/16/2[c001p0007]/1:27)" ); + assert.equal( cfi.range, true); + assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2,/10/2[c001p0004]/1:6,/16/2[c001p0007]/1:27)" ); - }); + }); - it('get a cfi from a range with offset 0', function() { - var t1 = doc.getElementById('c001p0004').childNodes[0]; - var range = doc.createRange(); - var cfi; + it('get a cfi from a range with offset 0', function() { + var t1 = doc.getElementById('c001p0004').childNodes[0]; + var range = doc.createRange(); + var cfi; - range.setStart(t1, 0); - range.setEnd(t1, 1); + range.setStart(t1, 0); + range.setEnd(t1, 1); - cfi = new EpubCFI(range, base); + cfi = new EpubCFI(range, base); - assert.equal( cfi.range, true); - assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/10/2[c001p0004],/1:0,/1:1)" ); + assert.equal( cfi.range, true); + assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/10/2[c001p0004],/1:0,/1:1)" ); - }); + }); - it('get a cfi from a range inside a highlight', function() { - var t1 = docHighlights.getElementById('highlight-1').childNodes[0]; - var range = docHighlights.createRange(); - var cfi; + it('get a cfi from a range inside a highlight', function() { + var t1 = docHighlights.getElementById('highlight-1').childNodes[0]; + var range = docHighlights.createRange(); + var cfi; - range.setStart(t1, 6); + range.setStart(t1, 6); - cfi = new EpubCFI(range, base, 'annotator-hl'); + cfi = new EpubCFI(range, base, 'annotator-hl'); - assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/32/2[c001p0017]/1:43)" ); + assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/32/2[c001p0017]/1:43)" ); - }); - // TODO: might need to have double ranges in front - it('get a cfi from a range past a highlight', function() { - var t1 = docHighlights.getElementById('c001s0001').childNodes[1]; - var range = docHighlights.createRange(); - var cfi; + }); + // TODO: might need to have double ranges in front + it('get a cfi from a range past a highlight', function() { + var t1 = docHighlights.getElementById('c001s0001').childNodes[1]; + var range = docHighlights.createRange(); + var cfi; - range.setStart(t1, 25); + range.setStart(t1, 25); - cfi = new EpubCFI(range, base, 'annotator-hl'); + cfi = new EpubCFI(range, base, 'annotator-hl'); - assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/4/2[c001s0001]/1:41)" ); + assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/4/2[c001s0001]/1:41)" ); - }); + }); - it('get a cfi from a range inbetween two highlights', function() { - var t1 = docHighlightsAlice.getElementById('p2').childNodes[1]; - var range = docHighlightsAlice.createRange(); - var cfi; + it('get a cfi from a range inbetween two highlights', function() { + var t1 = docHighlightsAlice.getElementById('p2').childNodes[1]; + var range = docHighlightsAlice.createRange(); + var cfi; - range.setStart(t1, 4); + range.setStart(t1, 4); - cfi = new EpubCFI(range, base, 'annotator-hl'); + cfi = new EpubCFI(range, base, 'annotator-hl'); - assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/4[p2]/1:123)" ); + assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/4[p2]/1:123)" ); - }); + }); - it('correctly count text nodes, independent of any elements present inbetween', function() { - var t1 = docHighlightsAlice.getElementById('p3').childNodes[2]; - var range = docHighlightsAlice.createRange(); - var cfi; + it('correctly count text nodes, independent of any elements present inbetween', function() { + var t1 = docHighlightsAlice.getElementById('p3').childNodes[2]; + var range = docHighlightsAlice.createRange(); + var cfi; - range.setStart(t1, 4); + range.setStart(t1, 4); - cfi = new EpubCFI(range, base); + cfi = new EpubCFI(range, base); - assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/6[p3]/3:4)" ); + assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/6[p3]/3:4)" ); - }); + }); - }); + }); - describe('#toRange()', function() { - var base = "/6/4[chap01ref]"; - var contents = fs.readFileSync(__dirname + '/fixtures/chapter1-highlights.xhtml', 'utf8'); - var doc = new DOMParser().parseFromString(contents, "application/xhtml+xml"); + describe('#toRange()', function() { + var base = "/6/4[chap01ref]"; + var contents = fs.readFileSync(__dirname + '/fixtures/chapter1-highlights.xhtml', 'utf8'); + var doc = new DOMParser().parseFromString(contents, "application/xhtml+xml"); - // var serializer = new XMLSerializer(); - // console.log(serializer.serializeToString(doc)); + // var serializer = new XMLSerializer(); + // console.log(serializer.serializeToString(doc)); - it('get a range from a cfi', function() { - var t1 = doc.getElementById('c001p0004').childNodes[0]; - var t2 = doc.getElementById('c001p0007').childNodes[0]; - var ogRange = doc.createRange(); - var cfi; - var newRange; + it('get a range from a cfi', function() { + var t1 = doc.getElementById('c001p0004').childNodes[0]; + var t2 = doc.getElementById('c001p0007').childNodes[0]; + var ogRange = doc.createRange(); + var cfi; + var newRange; - ogRange.setStart(t1, 6); + ogRange.setStart(t1, 6); - cfi = new EpubCFI(ogRange, base); + cfi = new EpubCFI(ogRange, base); - // Check it was parse correctly - assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/10/2[c001p0004]/1:6)" ); + // Check it was parse correctly + assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/10/2[c001p0004]/1:6)" ); - // Check the range - newRange = cfi.toRange(doc); + // Check the range + newRange = cfi.toRange(doc); - assert.equal( newRange.startContainer, t1); - assert.equal( newRange.startOffset, 6); - assert.equal( newRange.collapsed, true); + assert.equal( newRange.startContainer, t1); + assert.equal( newRange.startOffset, 6); + assert.equal( newRange.collapsed, true); - }); + }); - it('get a range from a cfi with a range', function() { - var t1 = doc.getElementById('c001p0004').childNodes[0]; - var t2 = doc.getElementById('c001p0007').childNodes[0]; - var ogRange = doc.createRange(); - var cfi; - var newRange; + it('get a range from a cfi with a range', function() { + var t1 = doc.getElementById('c001p0004').childNodes[0]; + var t2 = doc.getElementById('c001p0007').childNodes[0]; + var ogRange = doc.createRange(); + var cfi; + var newRange; - ogRange.setStart(t1, 6); - ogRange.setEnd(t2, 27); + ogRange.setStart(t1, 6); + ogRange.setEnd(t2, 27); - cfi = new EpubCFI(ogRange, base); + cfi = new EpubCFI(ogRange, base); - // Check it was parse correctly - assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2,/10/2[c001p0004]/1:6,/16/2[c001p0007]/1:27)" ); + // Check it was parse correctly + assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2,/10/2[c001p0004]/1:6,/16/2[c001p0007]/1:27)" ); - // Check the range - newRange = cfi.toRange(doc); + // Check the range + newRange = cfi.toRange(doc); - assert.equal( newRange.startContainer, t1); - assert.equal( newRange.startOffset, 6); + assert.equal( newRange.startContainer, t1); + assert.equal( newRange.startOffset, 6); - assert.equal( newRange.endContainer, t2); - assert.equal( newRange.endOffset, 27); + assert.equal( newRange.endContainer, t2); + assert.equal( newRange.endOffset, 27); - assert.equal( newRange.collapsed, false); + assert.equal( newRange.collapsed, false); - }); + }); - it('get a cfi from a range inside a highlight', function() { - var t1 = doc.getElementById('highlight-1').childNodes[0]; - var ogRange = doc.createRange(); - var cfi; - var newRange; + it('get a cfi from a range inside a highlight', function() { + var t1 = doc.getElementById('highlight-1').childNodes[0]; + var ogRange = doc.createRange(); + var cfi; + var newRange; - ogRange.setStart(t1, 6); + ogRange.setStart(t1, 6); - cfi = new EpubCFI(ogRange, base, 'annotator-hl'); + cfi = new EpubCFI(ogRange, base, 'annotator-hl'); - assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/32/2[c001p0017]/1:43)" ); + assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/32/2[c001p0017]/1:43)" ); - // Check the range - newRange = cfi.toRange(doc, 'annotator-hl'); + // Check the range + newRange = cfi.toRange(doc, 'annotator-hl'); - assert.ok(newRange.startContainer); + assert.ok(newRange.startContainer); - assert.equal( newRange.startContainer, t1); - assert.equal( newRange.startOffset, 6); + assert.equal( newRange.startContainer, t1); + assert.equal( newRange.startOffset, 6); - }); + }); - it('get a cfi from a range inside a highlight range', function() { - var t1 = doc.getElementById('highlight-2').childNodes[0]; - var t2 = doc.getElementById('c001s0001').childNodes[1]; - var ogRange = doc.createRange(); - var cfi; - var newRange; + it('get a cfi from a range inside a highlight range', function() { + var t1 = doc.getElementById('highlight-2').childNodes[0]; + var t2 = doc.getElementById('c001s0001').childNodes[1]; + var ogRange = doc.createRange(); + var cfi; + var newRange; - ogRange.setStart(t1, 5); - ogRange.setEnd(t2, 25); + ogRange.setStart(t1, 5); + ogRange.setEnd(t2, 25); - cfi = new EpubCFI(ogRange, base, 'annotator-hl'); + cfi = new EpubCFI(ogRange, base, 'annotator-hl'); - assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/4/2[c001s0001],/1:5,/1:41)" ); + assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/4/2[c001s0001],/1:5,/1:41)" ); - // Check the range - newRange = cfi.toRange(doc, 'annotator-hl'); + // Check the range + newRange = cfi.toRange(doc, 'annotator-hl'); - assert.strictEqual( newRange.startContainer.textContent, t1.textContent); - // assert.strictEqual( newRange.startContainer, t1); - // assert.equal( newRange.startOffset, 5); + assert.strictEqual( newRange.startContainer.textContent, t1.textContent); + // assert.strictEqual( newRange.startContainer, t1); + // assert.equal( newRange.startOffset, 5); - }); + }); - }); + }); }); diff --git a/test/tests/epub.js b/test/tests/epub.js index 2455b46..8723114 100644 --- a/test/tests/epub.js +++ b/test/tests/epub.js @@ -3,102 +3,102 @@ var domain = window.location.origin; module('Core'); test("EPUBJS.core.resolveUrl", 1, function() { - var a = "http://example.com/fred/chasen/"; - var b = "/chasen/derf.html"; + var a = "http://example.com/fred/chasen/"; + var b = "/chasen/derf.html"; - var resolved = EPUBJS.core.resolveUrl(a, b); + var resolved = EPUBJS.core.resolveUrl(a, b); - equal( resolved, "http://example.com/fred/chasen/derf.html", "resolved" ); + equal( resolved, "http://example.com/fred/chasen/derf.html", "resolved" ); }); test("EPUBJS.core.resolveUrl ../", 1, function() { - var a = "http://example.com/fred/chasen/"; - var b = "../derf.html"; + var a = "http://example.com/fred/chasen/"; + var b = "../derf.html"; - var resolved = EPUBJS.core.resolveUrl(a, b); + var resolved = EPUBJS.core.resolveUrl(a, b); - equal( resolved, "http://example.com/fred/derf.html", "resolved" ); + equal( resolved, "http://example.com/fred/derf.html", "resolved" ); }); test("EPUBJS.core.resolveUrl folders", 1, function() { - var a = "/fred/chasen/"; - var b = "/fred/chasen/derf.html"; + var a = "/fred/chasen/"; + var b = "/fred/chasen/derf.html"; - var resolved = EPUBJS.core.resolveUrl(a, b); + var resolved = EPUBJS.core.resolveUrl(a, b); - equal( resolved, "/fred/chasen/derf.html", "resolved" ); + equal( resolved, "/fred/chasen/derf.html", "resolved" ); }); test("EPUBJS.core.resolveUrl ../folders", 1, function() { - var a = "/fred/chasen/"; - var b = "../../derf.html"; + var a = "/fred/chasen/"; + var b = "../../derf.html"; - var resolved = EPUBJS.core.resolveUrl(a, b); + var resolved = EPUBJS.core.resolveUrl(a, b); - equal( resolved, "/derf.html", "resolved" ); + equal( resolved, "/derf.html", "resolved" ); }); module('Create'); asyncTest("Create new ePub(/path/to/epub/)", 1, function() { - - var book = ePub("../books/moby-dick/"); - book.opened.then(function(){ - equal( book.url, "../books/moby-dick/OPS/", "book url is passed to new EPUBJS.Book" ); - start(); - }); + + var book = ePub("../books/moby-dick/"); + book.opened.then(function(){ + equal( book.url, "../books/moby-dick/OPS/", "book url is passed to new EPUBJS.Book" ); + start(); + }); }); asyncTest("Create new ePub(/path/to/epub/package.opf)", 1, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - equal( book.url, domain + "/books/moby-dick/OPS/", "bookPath is passed to new EPUBJS.Book" ); - start(); - }); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + equal( book.url, domain + "/books/moby-dick/OPS/", "bookPath is passed to new EPUBJS.Book" ); + start(); + }); }); asyncTest("Open using ePub(/path/to/epub/package.opf)", 1, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - equal( book.packageUrl, "../books/moby-dick/OPS/package.opf", "packageUrl is set" ); - start(); - }); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + equal( book.packageUrl, "../books/moby-dick/OPS/package.opf", "packageUrl is set" ); + start(); + }); }); asyncTest("Open Remote ePub", 1, function() { - var book = ePub("https://s3.amazonaws.com/moby-dick/"); - book.opened.then(function(){ - equal( book.packageUrl, "https://s3.amazonaws.com/moby-dick/OPS/package.opf", "packageUrl is set" ); - start(); - }); + var book = ePub("https://s3.amazonaws.com/moby-dick/"); + book.opened.then(function(){ + equal( book.packageUrl, "https://s3.amazonaws.com/moby-dick/OPS/package.opf", "packageUrl is set" ); + start(); + }); }); asyncTest("Open Remote ePub from Package", 1, function() { - var book = ePub("https://s3.amazonaws.com/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - equal( book.packageUrl, "https://s3.amazonaws.com/moby-dick/OPS/package.opf", "packageUrl is set" ); - start(); - }); + var book = ePub("https://s3.amazonaws.com/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + equal( book.packageUrl, "https://s3.amazonaws.com/moby-dick/OPS/package.opf", "packageUrl is set" ); + start(); + }); }); asyncTest("Find Epub Package", 1, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - equal( book.packageUrl, "../books/moby-dick/OPS/package.opf", "packageUrl is set" ); - start(); - }); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + equal( book.packageUrl, "../books/moby-dick/OPS/package.opf", "packageUrl is set" ); + start(); + }); }); @@ -108,43 +108,43 @@ module('Parse'); asyncTest("Manifest", 1, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - equal( Object.keys(book.package.manifest).length, 152, "Manifest is parsed" ); - start(); - }); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + equal( Object.keys(book.package.manifest).length, 152, "Manifest is parsed" ); + start(); + }); }); asyncTest("Metadata", 3, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - equal( book.package.metadata.creator, "Herman Melville", "Creator metadata is parsed" ); - equal( book.package.metadata.title, "Moby-Dick", "Title metadata is parsed" ); - equal( book.package.metadata.identifier, "code.google.com.epub-samples.moby-dick-basic", "Identifier metadata is parsed" ); - start(); - }); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + equal( book.package.metadata.creator, "Herman Melville", "Creator metadata is parsed" ); + equal( book.package.metadata.title, "Moby-Dick", "Title metadata is parsed" ); + equal( book.package.metadata.identifier, "code.google.com.epub-samples.moby-dick-basic", "Identifier metadata is parsed" ); + start(); + }); }); asyncTest("Spine", 1, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - equal( book.package.spine.length, 144, "Spine is parsed" ); - start(); - }); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + equal( book.package.spine.length, 144, "Spine is parsed" ); + start(); + }); }); asyncTest("Cover", 1, function() { - var book = ePub("../books/moby-dick/"); - book.opened.then(function(){ - equal( book.cover, "../books/moby-dick/OPS/images/9780316000000.jpg", "Cover is set" ); - start(); - }); + var book = ePub("../books/moby-dick/"); + book.opened.then(function(){ + equal( book.cover, "../books/moby-dick/OPS/images/9780316000000.jpg", "Cover is set" ); + start(); + }); }); @@ -152,74 +152,74 @@ module('Spine'); asyncTest("Length", 1, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - equal( book.spine.length, 144, "All spine items present" ); - start(); - }); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + equal( book.spine.length, 144, "All spine items present" ); + start(); + }); }); asyncTest("Items", 1, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - equal( book.spine.spineItems.length, 144, "All spine items added" ); - start(); - }); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + equal( book.spine.spineItems.length, 144, "All spine items added" ); + start(); + }); }); asyncTest("First Item", 2, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - var section = book.spine.get(0); - equal( section.href, "cover.xhtml", "First spine item href found" ); - equal( section.cfiBase, "/6/2[cover]", "First spine item cfi found" ); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + var section = book.spine.get(0); + equal( section.href, "cover.xhtml", "First spine item href found" ); + equal( section.cfiBase, "/6/2[cover]", "First spine item cfi found" ); - start(); - }); + start(); + }); }); asyncTest("Find Item by Href", 2, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - var section = book.spine.get("chapter_001.xhtml"); - equal( section.href, "chapter_001.xhtml", "chap 1 spine item href found" ); - equal( section.cfiBase, "/6/14[xchapter_001]", "chap 1 spine item cfi found" ); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + var section = book.spine.get("chapter_001.xhtml"); + equal( section.href, "chapter_001.xhtml", "chap 1 spine item href found" ); + equal( section.cfiBase, "/6/14[xchapter_001]", "chap 1 spine item cfi found" ); - start(); - }); + start(); + }); }); asyncTest("Find Item by ID", 2, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - var section = book.spine.get("#xchapter_050"); - equal( section.href, "chapter_050.xhtml", "chap 50 spine item href found" ); - equal( section.cfiBase, "/6/112[xchapter_050]", "chap 50 spine item cfi found" ); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + var section = book.spine.get("#xchapter_050"); + equal( section.href, "chapter_050.xhtml", "chap 50 spine item href found" ); + equal( section.cfiBase, "/6/112[xchapter_050]", "chap 50 spine item cfi found" ); - start(); - }); + start(); + }); }); asyncTest("Render Spine Item", 1, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - var section = book.spine.get("#xchapter_050"); - section.render().then(function(content){ - equal( content.substring(377, 429), "

Chapter 50. Ahab’s Boat and Crew. Fedallah.

", "Chapter text rendered as string" ); - }); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + var section = book.spine.get("#xchapter_050"); + section.render().then(function(content){ + equal( content.substring(377, 429), "

Chapter 50. Ahab’s Boat and Crew. Fedallah.

", "Chapter text rendered as string" ); + }); - start(); - }); + start(); + }); }); @@ -227,84 +227,84 @@ module('Navigation'); asyncTest("NCX & Nav", 2, function() { - var book = ePub("../books/moby-dick/"); - book.opened.then(function(){ - equal( book.navigation.navUrl, "../books/moby-dick/OPS/toc.xhtml", "Nav URL found" ); - equal( book.navigation.ncxUrl, "../books/moby-dick/OPS/toc.ncx", "NCX URL found" ); + var book = ePub("../books/moby-dick/"); + book.opened.then(function(){ + equal( book.navigation.navUrl, "../books/moby-dick/OPS/toc.xhtml", "Nav URL found" ); + equal( book.navigation.ncxUrl, "../books/moby-dick/OPS/toc.ncx", "NCX URL found" ); - start(); - }); + start(); + }); }); asyncTest("Load TOC Auto Pick", 1, function() { - var book = ePub("../books/moby-dick/"); - book.opened.then(function(){ - book.navigation.load().then(function(toc){ - equal( toc.length, 141, "Full Nav toc parsed" ); - start(); - }); - }); + var book = ePub("../books/moby-dick/"); + book.opened.then(function(){ + book.navigation.load().then(function(toc){ + equal( toc.length, 141, "Full Nav toc parsed" ); + start(); + }); + }); }); asyncTest("Load TOC from Nav", 1, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - var nav = book.navigation.nav.load(); - nav.then(function(toc){ - equal( toc.length, 141, "Full Nav toc parsed" ); - start(); - }); - }); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + var nav = book.navigation.nav.load(); + nav.then(function(toc){ + equal( toc.length, 141, "Full Nav toc parsed" ); + start(); + }); + }); }); asyncTest("Load TOC from NCX", 1, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.opened.then(function(){ - var ncx = book.navigation.ncx.load(); - ncx.then(function(toc){ - equal( toc.length, 14, "Full NCX toc parsed" ); - start(); - }); - }); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.opened.then(function(){ + var ncx = book.navigation.ncx.load(); + ncx.then(function(toc){ + equal( toc.length, 14, "Full NCX toc parsed" ); + start(); + }); + }); }); asyncTest("Get all TOC", 1, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.loaded.navigation.then(function(){ - equal( book.navigation.get().length, 141, "Full Nav toc parsed" ); - start(); - }); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.loaded.navigation.then(function(){ + equal( book.navigation.get().length, 141, "Full Nav toc parsed" ); + start(); + }); }); asyncTest("Get TOC item by href", 1, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.loaded.navigation.then(function(){ - var item = book.navigation.get("chapter_001.xhtml"); - equal( item.id, "toc-chapter_001", "Found TOC item" ); - start(); - }); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.loaded.navigation.then(function(){ + var item = book.navigation.get("chapter_001.xhtml"); + equal( item.id, "toc-chapter_001", "Found TOC item" ); + start(); + }); }); asyncTest("Get TOC item by ID", 1, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - book.loaded.navigation.then(function(){ - var item = book.navigation.get("#toc-chapter_001"); - equal( item.href, "chapter_001.xhtml", "Found TOC item" ); - start(); - }); + var book = ePub("../books/moby-dick/OPS/package.opf"); + book.loaded.navigation.then(function(){ + var item = book.navigation.get("#toc-chapter_001"); + equal( item.href, "chapter_001.xhtml", "Found TOC item" ); + start(); + }); }); @@ -312,15 +312,15 @@ module('Hooks'); asyncTest("Register a new hook", 1, function() { - var beforeDisplay = new EPUBJS.Hook(); - beforeDisplay.register(function(args){ - var defer = new RSVP.defer(); - console.log("ran", 1); - defer.resolve(); - return defer.promise; - }); - equal( beforeDisplay.hooks.length, 1, "Registered a hook" ); - start(); + var beforeDisplay = new EPUBJS.Hook(); + beforeDisplay.register(function(args){ + var defer = new RSVP.defer(); + console.log("ran", 1); + defer.resolve(); + return defer.promise; + }); + equal( beforeDisplay.hooks.length, 1, "Registered a hook" ); + start(); // this.beforeDisplay.trigger(args).then(function(){}); @@ -328,44 +328,44 @@ asyncTest("Register a new hook", 1, function() { asyncTest("Trigger all new hook", 4, function() { - var beforeDisplay = new EPUBJS.Hook(this); - this.testerObject = {tester: 1}; + var beforeDisplay = new EPUBJS.Hook(this); + this.testerObject = {tester: 1}; - beforeDisplay.register(function(testerObject){ - var defer = new RSVP.defer(); + beforeDisplay.register(function(testerObject){ + var defer = new RSVP.defer(); - start(); - equal( testerObject.tester, 1, "tester is 1" ); - stop(); + start(); + equal( testerObject.tester, 1, "tester is 1" ); + stop(); - testerObject.tester += 1; + testerObject.tester += 1; - defer.resolve(); - return defer.promise; - }); + defer.resolve(); + return defer.promise; + }); - beforeDisplay.register(function(testerObject){ - var defer = new RSVP.defer(); + beforeDisplay.register(function(testerObject){ + var defer = new RSVP.defer(); - start(); - equal(testerObject.tester, 2, "tester is 2" ); - stop(); + start(); + equal(testerObject.tester, 2, "tester is 2" ); + stop(); - testerObject.tester += 1; + testerObject.tester += 1; - defer.resolve(); - return defer.promise; - }); + defer.resolve(); + return defer.promise; + }); - start(); - equal( beforeDisplay.hooks.length, 2, "Added two hooks" ); - stop(); + start(); + equal( beforeDisplay.hooks.length, 2, "Added two hooks" ); + stop(); - beforeDisplay.trigger(this.testerObject).then(function(){ - - start(); - equal( this.testerObject.tester, 3, "tester is 3" ); + beforeDisplay.trigger(this.testerObject).then(function(){ - }.bind(this)); + start(); + equal( this.testerObject.tester, 3, "tester is 3" ); -}); \ No newline at end of file + }.bind(this)); + +}); diff --git a/test/tests/rendering.js b/test/tests/rendering.js index 0084afa..5cf1357 100644 --- a/test/tests/rendering.js +++ b/test/tests/rendering.js @@ -2,15 +2,15 @@ module('Rendering'); /* asyncTest("Render To", 1, function() { - var book = ePub("../books/moby-dick/OPS/package.opf"); - var rendition = book.renderTo("qunit-fixture", {width:400, height:600}); - var displayed = rendition.display(0); + var book = ePub("../books/moby-dick/OPS/package.opf"); + var rendition = book.renderTo("qunit-fixture", {width:400, height:600}); + var displayed = rendition.display(0); - displayed.then(function(){ - equal( $( "iframe", "#qunit-fixture" ).length, 1, "iframe added successfully" ); - start(); - }); + displayed.then(function(){ + equal( $( "iframe", "#qunit-fixture" ).length, 1, "iframe added successfully" ); + start(); + }); }); -*/ \ No newline at end of file +*/