/*= BN.js */
if (typeof BN === 'undefined') { 
	window.BN = {};
}

(function () {
	var _global = {
		namespace: {
			create: function (ns) {			
				if (typeof ns !== 'string' || ns.length === 0) {
					throw new Error('Invalid or empty namespace');
				}
				var root = BN;
				ns = ns.split('.');
				for (var i = (ns[0] === 'BN' ? 1 : 0); i < ns.length; i++) {
					if (typeof root[ns[i]] === 'undefined') {
						root[ns[i]] = {};
					}
					root = root[ns[i]];
				}
				return root;
			},
			has: function (ns) {
				var contains = true;			
				if (typeof ns !== 'string' || ns.length === 0) {
					contains = false;
				} else {
					var root = BN;
					ns = ns.split('.');
					for (var i = (ns[0] === 'BN' ? 1 : 0); i < ns.length; i++) {
						if (typeof root[ns[i]] === 'undefined') {
							contains = false;
							break;
						}
						root = root[ns[i]];
					}
				}
				return contains;
			}
		}
	};
	
	for (var key in _global) {
		if (typeof BN[key] === 'undefined') {
			BN[key] = _global[key]; 
		}
	}	
})();
/*=bn_overlay.js */
(function (_scope) {
	var getDim = function (elem) {
		// get computed dimension
		var $elem = $(elem);
		return {
			width: $elem.width(),
			height: $elem.height()
		}	
	
	};
	var getPosition = function (elem) {
		var offset = $(elem).offset();
		return {
			left: parseInt(elem.style.left, 10) || offset.left,
			top: parseInt(elem.style.top, 10) || offset.top
		}
	};
	var getDimAndPosition = function (elem) {
		var offset = elem === window ? {left: 0, top: 0} : getPosition(elem);
		var dim = getDim(elem);
		return {
			left: offset.left,
			top: offset.top,
			width: dim.width,
			height: dim.height
		};
	};
	var createOverlayTemplate = function () {
		var elem = document.createElement('div');
		elem.innerHTML = '<div class="inner"><div class="header"></div><div class="body"></div><div class="footer"></div></div>';
		return document.body.appendChild(elem);
	};
	var getPageDim = function () {
		return {
			height: $(document).height(),
			width: document.body.clientWidth
		}
	};
	var Overlay = function (params) {
		var _settings = $.extend({
			offset: {x: 0, y: 0},
			modal: false
		}, params);
		this.get = function (name) {
			return _settings[name];
		};
		this.set = function (key, val) {
			if (/triggers|offset|align|width/.test(key)) {
				_settings[key] = val;
			}
		}
		this.initialize();
	};
	Overlay.prototype = {
		initialize: function () {
			/* setup the overlay element */
			var overlayParam = this.get('overlay');
			if (typeof overlayParam === 'string') {
				this.overlay = $(overlayParam)[0];
			} else {
				if (overlayParam.selector) {
					this.overlay = $(overlayParam.selector)[0];
				} else {
					this.overlay = createOverlayTemplate();
					if (overlayParam.id) {
						this.overlay.id = overlayParam.id;
					}
					if (overlayParam.className) {
						this.overlay.className = overlayParam.className;
					}
				}				
			}
			$(this.overlay).addClass('bn-overlay');
			var width = this.get('width');
			if (width) {
				this.overlay.style.width = parseInt(width, 10) + 'px';
			}
			
			/* check if user specify content to be inserted into overlay */
			var txt = this.get('content');
			if (txt) {
				this.append(txt);
			}
			/* if user defined triggers... */
			var triggers = this.get('trigger');
			if (triggers) {
				this.setTriggers(triggers, this.get('triggerOn'));
			}
			
			if (this.get('modal')) {
				this.setModal();
			}
			
			if (typeof window.innerHeight === 'undefined' && window.XMLHttpRequest == null) {
				var shim = this.overlay.shim = document.createElement('iframe');
				shim.src='javascript:false;';
				shim.className = 'shim';
				shim.setAttribute('frameBorder', 0);
				this.overlay.insertBefore(shim, this.overlay.firstChild);
			}
		},
		setModal: function () {
			var pageDim = getPageDim();
			this.blocker = document.createElement('div');
			this.blocker.className = 'bn-blocker hide';			
			this.blocker.style.width = pageDim.width + 'px';
			this.blocker.style.height = pageDim.height + 'px';
			this.overlay.parentNode.insertBefore(this.blocker, this.overlay);
		},
		setTriggers: function (triggers, triggerOn) {
			(function (_that) {
				$triggers = $(triggers);
				if (triggerOn === 'click') {
					$triggers.click(function (e) {
						try {
							_that.respond(this);
						} catch (e) {
						} finally {
							return false;
						}
					});
				} else if (triggerOn === 'mouseover') {
					var delay = _that.get('delay');
					if (typeof delay === 'number') {
						delay = [delay, delay]
					}
					var _openDelay, _closeDelay;
					var $_thatOverlay = $(_that.overlay);
					$triggers.mouseover(function (e) {
						_that.position(this);
						_that.checkBoundary(this);
						window.clearTimeout(_closeDelay);
						_openDelay = window.setTimeout(function () {
							_that.show();							
						}, delay[0]);
					});
					$triggers.mouseout(function (e) {
						window.clearTimeout(_openDelay);
						_closeDelay = window.setTimeout(function () {
							_that.hide();							
						}, delay[1]);
					});
					$_thatOverlay.mouseover(function (e) {
						window.clearTimeout(_closeDelay);
					});
					$_thatOverlay.mouseout(function (e) {
						window.clearTimeout(_openDelay);
						_closeDelay = window.setTimeout(function () {
							_that.hide();							
						}, delay[1]);
					});
				}
			})(this);
		},
		respond: function (trigger) {
			var cb = this.get('callback');
			if (this.isVisible()) {
				this.hide();
				if (this._previousTrigger !== trigger) {
					this.position(trigger);
					this.checkBoundary(trigger);
					this.show()
					if (cb) {
						cb.call(this, trigger);
					}
				}
			} else {
				$(this.overlay).addClass('bn-overlay');
				this.position(trigger);
				this.checkBoundary(trigger);
				this.show();
				if (cb) {
					cb.call(this, trigger);
				}
			}
			this._previousTrigger = trigger;
		},
		show: function () {
			var shim;
			if (this.get('modal')) {
				$(this.blocker).removeClass('hide');
			}
			if (shim = this.overlay.shim) {
				var overlayDim = getDim(this.overlay);
				shim.style.width = overlayDim.width + 'px';
				shim.style.height = overlayDim.height + 'px'; 
			}
			this.overlay.style.position = 'absolute';
			this.overlay.style.display = 'block';
		},
		hide: function () {
			if (this.get('modal')) {
				$(this.blocker).addClass('hide');
			}
			this.overlay.style.display = 'none';
			this.overlay.style.position = '';
			this.overlay.style.top = this.overlay.style.left = null;
		},
		isVisible: function () {
			return $(this.overlay).css('display') === 'none' ? false : true;
		},
		checkBoundary: function (trigger) {
			var overlayDim = getDimAndPosition(this.overlay);
			var alignment = this.get('align');
			var containerDim = getDim(window);
			var offsetFromTrigger = this.get('offset');			
			var triggerDim = getDimAndPosition(trigger);
			if (containerDim.width > overlayDim.width) {
				var overlayLeft = overlayDim.left;
				var overlayRight = overlayDim.left + overlayDim.width;
				var boundaryLeft = 0;
				var boundaryRight = containerDim.width;
				if (overlayRight > boundaryRight) {
					if (alignment === 'right') {
						this.overlay.style.left = triggerDim.left - overlayDim.width - offsetFromTrigger.x + 'px';
					} else {
						this.overlay.style.left = triggerDim.left - overlayDim.width + 'px';
					}				
				} else if (overlayLeft < boundaryLeft) {
					if (alignment === 'left') {
						this.overlay.style.left = triggerDim.left + triggerDim.width - offsetFromTrigger.x + 'px';
					} else {
						this.overlay.style.left = triggerDim.left + triggerDim.width + 'px';
					}
				}
			}
			if (containerDim.height > overlayDim.height) {
				var overlayTop = overlayDim.top;
				var overlayBottom = overlayDim.top + overlayDim.height;				
				var boundaryTop = $(window).scrollTop();
				var boundaryBottom = containerDim.height + boundaryTop;
				if (overlayBottom > boundaryBottom) {
					if (alignment === 'bottom') {
						this.overlay.style.top = triggerDim.top - overlayDim.height - offsetFromTrigger.y + 'px';
					} else {
						this.overlay.style.top = triggerDim.top - overlayDim.height + 'px';
					}
				} else if (overlayTop < boundaryTop) {
					if (alignment === 'top') {
						this.overlay.style.top = triggerDim.top + triggerDim.height - offsetFromTrigger.y + 'px';
					} else {
						this.overlay.style.top = triggerDim.top + triggerDim.height + 'px';
					}
				}
			}
		},
		position: function (ref) {
			var refDim = getDimAndPosition(ref || window);
			var overlayDim = getDimAndPosition(this.overlay);
			var defaultOffset = this.get('offset');
			var alignment = this.get('align');
			if (alignment === 'left') {
				this.overlay.style.left = (refDim.left - overlayDim.width + defaultOffset.x) + 'px';
				this.overlay.style.top = (refDim.top + defaultOffset.y) + 'px';
			} else if (alignment === 'right') {
				this.overlay.style.left = (refDim.left + refDim.width + defaultOffset.x) + 'px';
				this.overlay.style.top = (refDim.top + defaultOffset.y) + 'px';
			} else if (alignment === 'bottom') {
				this.overlay.style.left = (refDim.left + defaultOffset.x) + 'px';
				this.overlay.style.top = (refDim.top + refDim.height + defaultOffset.y) + 'px';
			} else if (alignment === 'top') {
				this.overlay.style.left = (refDim.left + defaultOffset.x) + 'px';
				this.overlay.style.top = (refDim.top - overlayDim.height + defaultOffset.y) + 'px';
			} else {
				this.overlay.style.left = Math.floor(refDim.width/2 - overlayDim.width/2) + 'px';
				this.overlay.style.top = $(window).scrollTop() + Math.floor(refDim.height/2 - overlayDim.height/2) + 'px';
			}
		},
		insertClose: function (selector) {
			var close = document.createElement('div');
			close.className = 'close';
			close.innerHTML = '<span></span>close';
			this.setClose(close);
			if (selector) {
				var elem = $(this.overlay).find(selector)[0];
				if (elem) {
					elem.appendChild(close);
				}
			} else {
				this.overlay.appendChild(close);
			}
		},
		setClose: function (elem) {
			var overlay = this;
			var hideOnClick = function () {
				overlay.hide();
				return false;
			};
			if (elem) {
				if (typeof elem === 'string') {
					elem = $(this.overlay).find(elem)[0];
					if (elem) {
						elem.onclick = hideOnClick;
					}
				} else {
					elem.onclick = hideOnClick;
				}
			} else {
				$(this.overlay).find('.close').each(function () {
					this.onclick = hideOnClick;
				});
			}
		},
		update: function (content) {
			if (typeof content === 'string') {
				$(this.overlay).find('.body')[0].innerHTML = content;
			} else {
				var $thisOverlay = $(this.overlay);
				if (content.header) {
					$thisOverlay.find('.header')[0].innerHTML = content.header;
				}
				if (content.body) {
					$thisOverlay.find('.body')[0].innerHTML = content.body;
				}
				if (content.footer) {
					$thisOverlay.find('.footer')[0].innerHTML = content.footer;
				}
			}
		},
		append: function (content) {
			if (typeof content === 'string') {
				$(this.overlay).find('.body')[0].innerHTML += content;
			} else {
				var $thisOverlay = $(this.overlay);
				if (content.header) {
					$thisOverlay.find('.header')[0].innerHTML += content.header;
				}
				if (content.body) {
					$thisOverlay.find('.body')[0].innerHTML += content.body;
				}
				if (content.footer) {
					$thisOverlay.find('.footer')[0].innerHTML += content.footer;
				}
			}
		}
	};	
	_scope.Overlay = function () {
		var _overlays = [];
		return {
			create: function (params) {
				return _overlays[_overlays.length] = new Overlay(params);
			}
		};
	}();
})(BN.namespace.create('widget'));
/*= locker.js */
BN.namespace.create('EBook');
BN.EBook.locker = function (_scope) {
	var uri = function () {
		var EBOOK_IMAGE_URL = 'http://images.barnesandnoble.com/presources/ebooks/images';
		var IMAGE_URL = 'http://images.barnesandnoble.com/presources/ebooks/images';
		var ACCOUNT_URL = 'https://cart2.barnesandnoble.com/account/op.asp?stage=mainStage';
		return {
			archiveButton: EBOOK_IMAGE_URL + '/btn_archive.gif',
			accountUrl: ACCOUNT_URL,
			accountButton: EBOOK_IMAGE_URL + '/btn_account_white.gif',
			cancelButton: EBOOK_IMAGE_URL + '/btn_cancel_white.gif',
			closeWindowButton: EBOOK_IMAGE_URL + '/btn_close_white.gif',
			deleteButton: EBOOK_IMAGE_URL + '/btn_delete_white.gif',
			goToAccountButton: EBOOK_IMAGE_URL + '/btn_gotoaccount_teal.gif',
			permanentlyDeleteButton: EBOOK_IMAGE_URL + '/btn_permanentlydelete.gif',
			signInButton: EBOOK_IMAGE_URL + '/btn_signin_teal.gif'
		};
	}();
	
	var addRequest = function (params, callback) {
		var method = params.type || 'GET';
		if (params.type) {
			delete params.type;
		}
		var req = {
			baseURL: $.hosts.commServices,
			type: method,
			parameters: _scope.locker.helpers.toQueryString(params)
		};
		if (callback) {
			req.handleResponse = callback;
		}
		ui.request(req);
	};
	
	var successfulRequest = function (resp) {
		if (typeof resp.status !== 'undefined') {
			return /true/i.test(resp.status);
		} else if (typeof resp.errorCode !== 'undefined') {
			return false;
		} else {
			return false;
		}
	};
	
	var setupCommunity = function (locker) {
		/* 
		 * If user rates for first time, remove reader rating 
		 * content after user votes successfully
		 */
		$.global.RatingWidgets.ratingCallback = function (resp) {
			var widget = $.global.RatingWidgets.element.parentNode;
			if (successfulRequest(resp)) {				
				if (widget) {
					var prevSib = $(widget).prev()[0];
					var totalVotes = $(widget).next('.total-votes')[0];
					if (prevSib.innerHTML && /reader/i.test(prevSib.innerHTML)) {
						prevSib.innerHTML = 'My Rating';
					}
					if (totalVotes) {
						totalVotes.parentNode.removeChild(totalVotes);
					}
				}
			}
		};
		
		/* Setup add/remove to my bn library */
		$('#product-catalog ul.community li.add-to-library input').click(function () {
			var checkbox = this;
			checkbox.disabled = true;
			var pair = this.id.split('_'); 
			var requestedAction = checkbox.checked? 'Add' : 'Remove';
			var params = {
				page: 'Library',
				uiAction: requestedAction === 'Add'? 'AddLibraryItem' : 'RemoveLibraryItemByEan',
				bnOutput: 1,
				ean: pair[1],
				pt: pair[2]
			};
			addRequest(params, function (resp) {
				checkbox.disabled = false;
			});
		});
	};
	
	var setupMyUpdates = function () {
		$('#message-center .remove-promo-message').each(function () {
			var _that = this;
			this.onclick = function () {
				var params = {
					page: 'UserProfile',
					uiAction: 'MarkAnnouncementAsViewed',
					announcementID: this.id.substring(this.id.indexOf('-') + 1),
					type: 'POST'
				};
				addRequest(params, function (resp) {
					if (successfulRequest(resp)) {
						var li = $(_that).parents('li')[0];
						var parent = li.parentNode;
						parent.removeChild(li);
						if (parent.getElementsByTagName('li').length === 0) {
							document.getElementById('message-center').className += ' hide';
						}
					}
				});
			}		
		});
	};
	
	var setupDownload = function () {
		document.domain = 'barnesandnoble.com';
		var iframePrefix = 'download-response-';
		var depot = document.createElement('div');
		depot.id = 'download-container';
		depot.className = 'hide';
		document.getElementById('locker').appendChild(depot);
		$('#product-catalog ul.actions li.download>a').click(function () {
			// if there's a download error popup from previous request, close it
			$(this).parent('li.download').find('div.download-error').css('display', 'none');
			var ean = _scope.locker.helpers.toQueryParams(this.href).ean;
			if (typeof ean === 'string') {
				if (!this.id) {
					this.id = 'download-' + ean;
				}					
				var iframe = document.getElementById(iframePrefix + ean);
				if (!iframe) {
					iframe = document.createElement('iframe');
					iframe.id = iframePrefix + ean;
					depot.appendChild(iframe);
				}
				iframe.src = this.href + "&callback=parent.BN.EBook.locker.handleDownloadError";
			}
			return false;
		});
	};
	
	var setupBuyNow = function () {
		BN.EBook.Util.setBuyNow('.actions .buy-now a');
	};
	
	var setupSortBy = function (numberOfItems) {
		if (numberOfItems > 1) {
			var url = document.location.href.split('?')[0];
			$('#sort-locker-items>select')[0].onchange = function () {
				if (this.value) {
					var queryParams = _scope.locker.helpers.toQueryParams(document.location.search);
					queryParams.sort_by = this.value;								
					document.location.href = url + _scope.locker.helpers.toQueryString(queryParams);
				}
			};
		}
	};
	
	var createOverlay = function (params) {
		return BN.widget.Overlay.create(params);
	};
	
	var setupHelpMessages = function () {
		var deletePopup = createOverlay({
			trigger: '#product-catalog li.delete img.help',
			triggerOn: 'mouseover',
			delay: 300,
			overlay: '#delete-ebook-help',
			offset: {x: -255, y: 9},
			align: 'top'
		});
		var myLibPopup = createOverlay({
			trigger: '#product-catalog li.add-to-library img.help',
			triggerOn: 'mouseover',
			delay: 300,
			overlay: '#mybn-library-help',
			offset: {x: -255, y: 9},
			align: 'top'
		}) ;
		var unlockCodePopup = createOverlay({
			trigger: '#unlock-code img.help',
			triggerOn: 'mouseover',
			delay: 300,
			overlay: '#unlock-code-help',
			offset: {x: 9, y: 6},
			align: 'right'
		});
	};
	
	var setupConfirmDeleteMessage = function (product, category) {
		if (/archive/i.test(category) || /sample/i.test(product)) {
			var delMsg = '<p>Deleting this item will permanently remove it from your collection.</p><div class="actions"><img class="delete" src="' + uri.deleteButton + '" alt="Delete Permanently"/><img class="close" src="' + uri.cancelButton + '" alt="Cancel" /></a>';
		} else {
			var delMsg = '<p>Deleting this item will permanently remove it from your collection. We recommend you archive this title instead in case you want to download it again.</p><div class="actions"><img class="archive" src="' + uri.archiveButton + '" alt="Yes, Archive"/><img class="delete" src="' + uri.permanentlyDeleteButton + '" alt="Delete"/></a></div>';
		}
		var confirmDeletePopup = createOverlay({
			trigger: '#product-catalog ul.actions li.delete input.submit',
			triggerOn: 'click',
			overlay: {id: 'confirm-delete', className: 'bn-overlay-dialog'},
			content: { header: 'Delete', body: delMsg },
			align: 'left',
			offset: { x: 0, y: 6 },
			callback: function (target) {
				var archiveButton = $(this.overlay).find('.actions .archive')[0];
				var deleteButton = $(this.overlay).find('.actions .delete')[0];
				var id = target.id.split('-')[1];
				if (!document.forms['archive-'+id]) {
					$(archiveButton).css('display', 'none');
				} else {
					archiveButton.onclick = function () {
						document.forms['archive-'+id].submit();
						return false;
					};
				}
				deleteButton.onclick = function () {
					document.forms['delete-'+id].submit();
					return false;
				};
				$(this.overlay).find('.actions').css('display', 'block');
			}
		});
		confirmDeletePopup.setClose();
		confirmDeletePopup.insertClose('.header');
	};
	
	var _locker = {
		initialize: function (params) {
			this.get = function (name) {
				return params[name];
			};
			var signedIn = params.signedIn;
			if (signedIn == 'false') {
				$(document.body).addClass('not-signed-in');
				new $.SignInWidget();
				$('#signInOverlay').find('a.overlayClose').click(function(){
					document.location = 'http://www.barnesandnoble.com';
				});
			} else {
				this.popup = createOverlay({
					overlay: { id: 'locker-popup', className: 'bn-overlay-dialog' },
					width: 338
				});
				this.checkFlashMessage();
				setupSortBy(this.get('numberOfItems'));
				setupMyUpdates();
				setupCommunity();
				setupHelpMessages();
				setupConfirmDeleteMessage(this.get('product'), this.get('category'));
				setupDownload();
				if (/sample/i.test(params.product)) {
					setupBuyNow();
				}
			}
		},
		checkFlashMessage: function () {
			var $action = $('#flash-message>p>span.action');
			if ($action.length) {
				var txt = $action.text();
				this.popup.update({
					header: txt.substring(0,1).toUpperCase() + txt.substring(1), 
					body: '<p>' + $action.next().text() + '</p>',
					footer: '<img class="close" alt="" src="'+ uri.closeWindowButton +'" />'
				});
				this.popup.setClose();
				this.popup.insertClose('.header');
				this.popup.position();
				this.popup.show();
			};
		},
		handleDownloadError: (function () {
			var ErrorPopup = (function () {
				var isIe6 = typeof window.innerHeight === 'undefined' && !window.XMLHttpRequest;
				var getCodeData = function (code) {
					var titles = ['Technical Difficulty', 'Unlock this eBook', 'Update Your Default Credit Card'];
					var buttons = {
						account: '<a href="' + uri.accountUrl + '"><img alt="Go to Account Page" src="' + uri.goToAccountButton + '" /></a>',
						signIn: '<a class="close" onclick="new $.SignInWidget();" href="' + uri.accountUrl + '"><img alt="Sign In" src="' + uri.signInButton + '" /></a>',
						cancel: '<img class="close" src="' + uri.cancelButton + '" />'
					};
					var footers = [buttons.account + buttons.cancel, buttons.signIn + buttons.cancel];
					var KEYS = {
						// format: [0] is title, [1] is footer, [2] is error type used in classname
						SIGNIN: [titles[0], footers[1], 'signin'],
						TECHNICAL: [titles[0], '', 'technical'],
						UNLOCK: [titles[1], footers[0], 'unlock'],					
						UPDATE: [titles[2], footers[0], 'update']					
					};
					var codeMap = {
						'-1127': KEYS.UPDATE,
						'-1131': KEYS.UNLOCK,
						'-1141': KEYS.UPDATE,
						'-1177': KEYS.UNLOCK,
						'1107': KEYS.UPDATE,
						'1604': KEYS.TECHNICAL,
						'1605': KEYS.TECHNICAL,
						'1606': KEYS.TECHNICAL,
						'1607': KEYS.TECHNICAL,
						'1608': KEYS.TECHNICAL,
						'1609': KEYS.SIGNIN
					};
					return codeMap[code] || ['', '', 'unknown'];
				};
				var createPopupHtml = function () {
					var shell = document.createElement('div');
					shell.innerHTML = '<div class="inner"><div></div><div></div><div></div></div>';
					$shell = $(shell);
					$shell.find('div.inner > div:first-child')
						  .addClass('header')
						  .html('<span class="title"></span><div class="close"><span></span>close</div>');
					$shell.find('div.inner > div:nth-child(2)').addClass('body');
					$shell.find('div.inner > div:last-child').addClass('footer');
					return shell;
				};
				var _ErrorPopup = function (resp) {
					this.error = resp;
					this.classname = this.title = this.body = this.footer = null;					
					this.setClassNames();
					this.update();
				};
				_ErrorPopup.prototype = {
					setClassNames: function () {
						this.classname = 'download-error bn-overlay-dialog bn-overlay';
					},
					update: function () {
						var data = getCodeData(this.error.errorCode);
						this.title = data[0];
						this.body = this.error.errorMessage;
						this.footer = data[1];
						this.classname += ' ' + data[2] + '-error';
					},
					isIn: function (container) {
						return $(container).find('div.download-error')[0] || false;
					},
					insertIn: function (container) {
						return container.appendChild(createPopupHtml());
					},
					render: function (shell) {
						shell.className = this.classname;
						$shell = $(shell);
						$shell.find('div.header .title').html(this.title);
						$shell.find('div.body').html(this.body);
						if (this.footer !== '' && this.footer !== null) {
							$shell.find('.footer').removeClass('hide').html(this.footer);
						} else {
							$shell.find('.footer').addClass('hide');
						}
						$shell.find('.close').click(function () {
							shell.style.display = 'none';
							return false;
						});
						if (isIe6) {
							var shim = $shell.find('iframe.shim')[0];
							if (!shim) {
								shim = document.createElement('iframe');
								shim.src = 'javascript:false;';
								shim.className = 'shim';
								shim.setAttribute('frameborder', 0);
								shim.setAttribute('scrolling', 'no');
								shell.insertBefore(shim, shell.firstChild);
							}
							shim.style.width = $shell.width() + 'px';
							shim.style.height = $shell.height() + 'px';
						}
						shell.style.display = 'block';					
					}
				};
				return _ErrorPopup;
			})();
			return function (resp) {
				if (!successfulRequest(resp)) {
					var container = $('#download-' + resp.ean).parents('li.download')[0];
					if (container) {
						var popup = new ErrorPopup(resp);
						var html = popup.isIn(container);
						if (html === false) {
							html = popup.insertIn(container);
						}
						popup.render(html);
						popup = null;
					}
				}
			};
		})()
	};
	_locker.helpers = {
		toQueryParams: function (str, separator) {
			/* Using regex logic from the Prototype library: http://prototypejs.org */
			var match = str.replace(/^\s+/, '').replace(/\s+$/, '').match(/([^?#]*)(#.*)?$/);
			var hash = {};
			if (match) {
				var arr = match[1].split(separator || '&');	
				for (var i = 0; i < arr.length; ++i) {
					var pair = arr[i].split('=');
					if (pair[0]) {
						var key = decodeURIComponent(pair.shift());
						var value = pair.length > 1 ? pair.join('=') : pair[0];
						if (value !== undefined) {
							value = decodeURIComponent(value);
						}
						if (key in hash) {
							if (hash[key].constructor !== Array) {
								hash[key] = [hash[key]];
							}
							hash[key].push(value);
						} else { 
							hash[key] = value;
						}
					}
				}
			}
			return hash;
		}, 
		toQueryString: function (params) {
			var arr = [];
			for (var keys in params) {
				arr.push(keys + '=' + encodeURIComponent(params[keys]));
			}
			return '?' + arr.join('&');
		}
	};
	return _locker;
}(BN.EBook);