<commit_before><!DOCTYPE html>

<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title>Comic Book Reader</title>
		<style>
#topPanel {
	opacity: 0.9;
	position: absolute;
	top: 0px;
	z-index: 1000;
	border: 1px solid black;
	margin: 20px;
	margin-top: 0px;
	padding: 20px;
	padding-top: 0px;
	box-shadow: 10px 10px 5px #888888;
	background: silver;
	text-align: center;
}

#loadProgress {
	width: 100%;
	display: none;
}

#btnFullScreen {
	font: 30px/100px Helvetica, Arial, sans-serif;
}

#fileInput {
	display: none;
}

#fileLoad {
	font: 30px/100px Helvetica, Arial, sans-serif;
}

.comicImage {
	pointer-events: none;
	width: 100%;
	user-select: none;
	-moz-user-select: none;
	-webkit-user-select: none;
	-webkit-user-drag: none;
}

#comicPannel {
	position: absolute;
	z-index: 0px;
	/*border: 10px solid orange;*/
	overflow: hidden;
}

#pageContainer {
	/*border: 20px solid black;*/
	overflow: visible;
}

#pageLeft {
	position: absolute;
	z-index: 0px;
	text-align: center;
	background-color: red;
}

#pageMiddle {
	position: absolute;
	z-index: 0px;
	text-align: center;
	background-color: green;
}

#pageRight {
	position: absolute;
	z-index: 0px;
	text-align: center;
	background-color: blue;
}

#pageOverlay {
	position: absolute;
	z-index: 1px;
	pointer-events: none;
	text-align: center;
	font: 100px/300px Helvetica, Arial, sans-serif;
	text-shadow: 4px 4px 20px white;
	opacity: 0.5;
}
		</style>
		<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
		<script src="js/polyfill/polyfill.js"></script>
		<script src="js/zip.js"></script>
		<script src="js/screenfull.js/screenfull.js"></script>
	</head>
	<body style="margin: 0; padding: 0;">
		<div id="topPanel">
			<input id="fileInput" type="file" required="required" />
			<button id="fileLoad">Load comic from your computer</button>

			<button id="btnFullScreen">Full Screen</button>

			<progress id="loadProgress" max="1" value="0"></progress>
			<p><span id="loadError"></span></p>
			<div id="comicData">
				<b>Name:</b> <span id="nameValue"></span><br>
				<b>Size:</b> <span id="sizeValue"></span><br>
				<b>Type:</b> <span id="typeValue"></span><br>
			</div>
		</div>

		<div id="comicPannel" touchable>
			<div id="pageContainer" touchable>
				<div id="pageLeft" touchable>
					Left Page
				</div>
				<div id="pageMiddle" touchable>
					Middle Page
				</div>
				<div id="pageRight" touchable>
					Right Page
				</div>
				<div id="pageOverlay" touchable>
				</div>
			</div>
		</div>

		<script>

var g_entries = [];
var g_images = [];
var g_image_index = 0;
var g_moving_pannel = null;
var g_is_mouse_down = false;
var g_mouse_start_x = 0;
var g_mouse_start_y = 0;
var g_is_vertical = false;
var g_screen_width = 0;
var g_is_swiping_right = false;
var g_is_swiping_left = false;
var g_top_visible = 1.0;
var g_left = null;
var g_middle = null;
var g_right = null;
var g_scroll_y_temp = 0;
var g_scroll_y_start = 0;
var g_needs_resize = false;

function toFrieldlySize(size) {
	if (size >= 1024000000) {
		return (size / 1024000000).toFixed(2) + ' GB';
	} else if (size >= 1024000) {
		return (size / 1024000).toFixed(2) + ' MB';
	} else if (size >= 1024) {
		return (size / 1024).toFixed(2) + ' KB';
	} else if (size >= 1) {
		return (size / 1).toFixed(2) + ' B';
	}

	return '?';
}

function blobToDataURI(blob, cb) {
	var reader = new FileReader();
	reader.onload = function(e) {
		cb(e.target.result);
	};
	reader.readAsDataURL(blob);
}

function isValidImageType(file_name) {
	file_name = file_name.toLowerCase();
	return file_name.endsWith('.jpeg') ||
			file_name.endsWith('.jpg') ||
			file_name.endsWith('.png') ||
			file_name.endsWith('.bmp');
}

function hideTopPanel(is_instant) {
	var speed = is_instant ? '0.0s' : '0.3s';
	var height = $('#topPanel').outerHeight() + 10;
	var style = $('#topPanel')[0].style;
	style.transitionDuration = speed;
	style.transform = 'translate3d(0px, -' + height + 'px, 0px)';
	g_top_visible = 0.0;
}

function showTopPanel(y_offset, is_instant) {
	var speed = is_instant ? '0.0s' : '0.2s';
	var height = $('#topPanel').outerHeight();
	var offset = -height + (height * y_offset);
	var style = $('#topPanel')[0].style;
	style.transitionDuration = speed;
	style.transform = 'translate3d(0px, ' + offset + 'px, 0px)';
	style.width = (g_screen_width - 80) + 'px';
	g_top_visible = y_offset;
}

function loadComic() {
	var file_input = $('#fileInput');

	// Just return if there is no file selected
	if (file_input[0].files.length === 0) {
		return;
	}

	// Load the file's info
	clearComicData();
	var file = file_input[0].files[0];
	setComicData(file.name, file.size, file.type);

	// Read the file
	onProgress(1, 1);
	$('#loadProgress').hide();
	$('#comicPannel').show();

	hideTopPanel(false);

	var blob = file.slice();
	onLoaded(blob);
}

function friendlyPageNumber() {
	return 'Page ' + (g_image_index + 1) + ' of ' + g_images.length;
}

function replaceIfDifferentImage(parent, image) {
	var children = parent.children();
	if (children.length === 0) {
		parent.append(image);
	} else if (children.length && children[0].id !== image.id) {
		parent.empty();
		parent.append(image);
	}
}

function loadCurrentPage() {
	// Load the middle page
	updatePageCache(g_image_index);
	replaceIfDifferentImage(g_middle, g_images[g_image_index]);
	$('#pageOverlay')[0].innerHTML = friendlyPageNumber();

	// Load right page
	if (g_image_index === g_images.length -1) {
		g_right.empty();
	} else if (g_image_index < g_images.length -1) {
		updatePageCache(g_image_index + 1);
		replaceIfDifferentImage(g_right, g_images[g_image_index + 1]);
	}

	// Load left page
	if (g_image_index === 0) {
		g_left.empty();
	} else if (g_image_index > 0) {
		updatePageCache(g_image_index - 1);
		replaceIfDifferentImage(g_left, g_images[g_image_index - 1]);
	}
}

function updatePageCache(index) {
	var img = g_images[index];
	if (img.is_loaded) {
		console.info('!!! Cached page: ' + index + ', ' + img.title);
	} else {
		var entry = g_entries[index];
		entry.getData(new zip.BlobWriter(), function(blob) {
	//		console.info(entry.filename);
	//		console.info(blob);
			blobToDataURI(blob, function(data_uri) {
				// Load the blob into an image
				var img = g_images[entry.index];
				img.src = data_uri;
				img.is_loaded = true;
				console.info('Loaded page: ' + index + ', ' + img.title);
			});
		});
	}
}

function setComicData(name, size, type) {
	$('#comicData').show();
	$('#nameValue').text(name);
	$('#sizeValue').text(toFrieldlySize(size));
	$('#typeValue').text(type);
}

function clearComicData() {
	// Reset the UI
	$('#loadError').hide();
	$('#comicData').hide();
	$('#loadProgress').val(0);
	setComicData('?', '?', '?');

	// Remove all the old images and compressed file entries
	g_middle.empty();
	g_left.empty();
	g_right.empty();
	g_image_index = 0;
	g_images = [];
	g_entries = [];
}

function onLoaded(blob) {
	var reader = new zip.BlobReader(blob);
	zip.createReader(reader, function(reader) {
		reader.getEntries(function(entries) {
			// Get only the entries that are valid images
			g_entries = [];
			entries.forEach(function(entry) {
				if (! entry.directory && isValidImageType(entry.filename)) {
					g_entries.push(entry);
				}
			});

			// Sort the entries by their file names
			g_entries.sort(function(a, b){
				if(a.filename < b.filename) return -1;
				if(a.filename > b.filename) return 1;
				return 0;
			});

			// Create empty images for each page
			var i = 0;
			g_entries.forEach(function(entry) {
				var img = document.createElement('img');
				img.id = 'page_' + i;
				img.title = entry.filename;
				img.className = 'comicImage';
				img.ondragstart = function() { return false; }
				img.onload = function() {
					if (g_needs_resize) {
						onResize(g_screen_width);
					}
				};
				img.draggable = 'false';
				g_images.push(img);
				entry.index = i;
				i++;
			});

			g_image_index = 0;
			loadCurrentPage();
			var width = $(window).width();
			onResize(width);
		});
	}, function(e) {
		onError('Failed to read file!');
	});
}

function onError(msg) {
	$('#comicPannel').hide();
	$('#comicData').hide();
	$('#loadError').text('Error: ' + msg);
	$('#loadError').show();
	showTopPanel(1.0, true);
}

function onProgress(loaded, total) {
	$('#loadProgress').show();
	$('#loadProgress').val(loaded / total);
}

function largestNumber(a, b, c) {
	var larger = a > b ? a : b;
	larger = larger > c ? larger : c;
	return larger;
}

function largestPageNaturalHeight() {
	var left_children = g_left.children();
	var middle_children = g_middle.children();
	var right_children = g_right.children();

	var left_width = left_children.length > 0 ? left_children[0].naturalWidth : 0;
	var middle_width = middle_children.length > 0 ? middle_children[0].naturalWidth : 0;
	var right_width = right_children.length > 0 ? right_children[0].naturalWidth : 0;

	var left_ratio = left_width !== 0 ? g_screen_width / left_width : 0;
	var middle_ratio = middle_width !== 0 ? g_screen_width / middle_width : 0;
	var right_ratio = right_width !== 0 ? g_screen_width / right_width : 0;

	var left_height = left_children.length > 0 ? left_ratio * left_children[0].naturalHeight : 0;
	var middle_height = middle_children.length > 0 ? middle_ratio * middle_children[0].naturalHeight : 0;
	var right_height =  right_children.length > 0 ?  right_ratio *  right_children[0].naturalHeight : 0;

	return largestNumber(left_height, middle_height, right_height);
}

function onResize(screen_width) {
//	console.info('Resize called ...');
	g_screen_width = screen_width;

	// Move the top panel to the new top
	if (g_top_visible < 1.0) {
		hideTopPanel(true);
	} else {
		showTopPanel(g_top_visible, true);
	}

	// Figure out if the images are loaded yet.
	// If not, we will manually fire the resize event when they do
	var children = g_middle.children();
	if (children.length === 0) {
		g_needs_resize = true;
//		console.info('Needs resize ...');
		return;
	} else if (children[0].naturalWidth === 0) {
		g_needs_resize = true;
//		console.info('Needs resize ...');
		return;
	}

	// Find the largest natural height from the images
	var height = largestPageNaturalHeight();

	// Make the panel as wide as the screen
	g_needs_resize = false;
	$('#comicPannel')[0].style.width = (g_screen_width * 1) + 'px';

	// Make it as wide as the screen and as tall as the tallest image
	var style = $('#pageContainer')[0].style;
	style.width = (g_screen_width * 3) + 'px';
	style.height = height + 'px';
	style.transitionDuration = '0.0s';
	style.transform = 'translate3d(-' + g_screen_width + 'px, 0px, 0px)';

	// Make it as wide as the screen and as tall as the tallest image
	style = $('#pageOverlay')[0].style;
	style.width = g_screen_width + 'px';
	style.height = height + 'px';
	style.transitionDuration = '0.0s';
	style.transform = 'translate3d(' + (1 * g_screen_width) + 'px, 0px, 0px)';

	// Make it as wide as the screen and as tall as the tallest image
	style = g_left[0].style;
	style.width = g_screen_width + 'px';
	style.height = height + 'px';
	style.transitionDuration = '0.0s';
	g_left[0].panel_index = 0;
	style.transform = 'translate3d(' + (g_left[0].panel_index * g_screen_width) + 'px, 0px, 0px)';

	// Make it as wide as the screen and as tall as the tallest image
	style = g_middle[0].style;
	style.width = g_screen_width + 'px';
	style.height = height + 'px';
	style.transitionDuration = '0.0s';
	g_middle[0].panel_index = 1;
	style.transform = 'translate3d(' + (g_middle[0].panel_index * g_screen_width) + 'px, 0px, 0px)';

	// Make it as wide as the screen and as tall as the tallest image
	style = g_right[0].style;
	style.width = g_screen_width + 'px';
	style.height = height + 'px';
	style.transitionDuration = '0.0s';
	g_right[0].panel_index = 2;
	style.transform = 'translate3d(' + (g_right[0].panel_index * g_screen_width) + 'px, 0px, 0px)';
}

$(document).ready(function() {
	// Tell zip.js where it can find the worker js file
	zip.workerScriptsPath = 'js/';

	g_left = $('#pageLeft');
	g_middle = $('#pageMiddle');
	g_right = $('#pageRight');

	// Resize everything when the browser resizes
	$(window).resize(function(e) {
		var width = $(window).width();
		onResize(width);
	});
	$(window).trigger('resize');

	// Stop the right click menu from popping up
	$(document).on('contextmenu', function(e) {
		e.preventDefault();
	});

	// Toggle full screen
	$('#btnFullScreen').click(function () {
		if (screenfull.enabled) {
			screenfull.toggle();
		}
	});

	g_left.mousedown(function(e) {
		if (this.panel_index === 1) {
			g_moving_pannel = this;
		} else {
			g_moving_pannel = null;
		}
	});

	g_middle.mousedown(function(e) {
		if (this.panel_index === 1) {
			g_moving_pannel = this;
		} else {
			g_moving_pannel = null;
		}
	});

	g_right.mousedown(function(e) {
		if (this.panel_index === 1) {
			g_moving_pannel = this;
		} else {
			g_moving_pannel = null;
		}
	});

	$('body').mousedown(function(e) {
		// Skip if clicking on something that is no touchable
		if (! e.target.hasAttribute('touchable')) {
			return;
		}

		// If the top menu is showing, hide it
		if (e.target.hasAttribute('touchable') && g_top_visible > 0.0) {
			hideTopPanel(false);
			return;
		}

		g_is_mouse_down = true;
		g_mouse_start_x = e.clientX;
		g_mouse_start_y = e.clientY;
	});

	$('body').on('mouseup mouseleave', function(e) {
		if (g_top_visible > 0.0 && g_top_visible < 1.0) {
			hideTopPanel(false);
		}

		if (! g_is_mouse_down) {
			return;
		}
		g_is_mouse_down = false;
		g_moving_pannel = null;
		g_scroll_y_start += g_scroll_y_temp;
		g_scroll_y_temp = 0;


		if (g_is_swiping_right) {
			g_is_swiping_right = false;

			var style = g_middle[0].style;
			style.transitionDuration = '0.3s';
			style.transform = 'translate3d(' + (g_screen_width * 2) + 'px, 0px, 0px)';

			style = g_left[0].style;
			style.transitionDuration = '0.3s';
			style.transform = 'translate3d(' + (g_screen_width) + 'px, 0px, 0px)';

			// Update the page orderings, after the pages move into position
			setTimeout(function() {
				var old_left = g_left;
				var old_middle = g_middle;
				var old_right = g_right;
				g_right = old_middle;
				g_middle = old_left;
				g_left = old_right;

				g_left[0].panel_index = 0;
				g_middle[0].panel_index = 1;
				g_right[0].panel_index = 2;

				style = g_left[0].style;
				style.transitionDuration = '0.0s';
				style.transform = 'translate3d(' + (g_left[0].panel_index * g_screen_width) + 'px, 0px, 0px)';
				g_scroll_y_start = 0;
				window.scrollTo(0, 0);

				if (g_image_index > 0) {
					g_image_index--;
					loadCurrentPage();
				}
			}, 300);
		} else if (g_is_swiping_left) {
			g_is_swiping_left = false;

			var style = g_middle[0].style;
			style.transitionDuration = '0.3s';
			style.transform = 'translate3d(0px, 0px, 0px)';

			style = g_right[0].style;
			style.transitionDuration = '0.3s';
			style.transform = 'translate3d(' + (g_screen_width) + 'px, 0px, 0px)';

			// Update the page orderings, after the pages move into position
			setTimeout(function() {
				var old_left = g_left;
				var old_middle = g_middle;
				var old_right = g_right;
				g_left = old_middle;
				g_middle = old_right;
				g_right = old_left;

				g_left[0].panel_index = 0;
				g_middle[0].panel_index = 1;
				g_right[0].panel_index = 2;

				style = g_right[0].style;
				style.transitionDuration = '0.0s';
				style.transform = 'translate3d(' + (g_right[0].panel_index * g_screen_width) + 'px, 0px, 0px)';
				g_scroll_y_start = 0;
				window.scrollTo(0, 0);

				if (g_image_index < g_images.length -1) {
					g_image_index++;
					loadCurrentPage();
				}
			}, 300);
		} else {
			var style = g_left[0].style;
			style.transitionDuration = '0.3s';
			style.transform = 'translate3d(0px, 0px, 0px)';

			style = g_middle[0].style;
			style.transitionDuration = '0.3s';
			style.transform = 'translate3d(' + (g_screen_width * 1) + 'px, 0px, 0px)';

			style = g_right[0].style;
			style.transitionDuration = '0.3s';
			style.transform = 'translate3d(' + (g_screen_width * 2) + 'px, 0px, 0px)';
		}
	});

	$('body').mousemove(function(e) {
		if (! g_is_mouse_down) {
			return;
		}

		// Figure out if we are moving vertically or horizontally
//		console.info(e.clientX + ', ' + g_mouse_start_x + ', ' + g_moving_pannel.panel_index + ', ' + g_moving_pannel.id);
		if (Math.abs(e.clientY - g_mouse_start_y) > Math.abs(e.clientX - g_mouse_start_x)) {
			g_is_vertical = true;
		} else {
			g_is_vertical = false;
		}

		// Get how far we have moved since pressing down
//		console.info(g_is_vertical);
//		console.info(e.clientX + ', ' + e.clientY + ', ' + g_is_vertical);
		var x_offset = e.clientX - g_mouse_start_x;
		var y_offset = e.clientY - g_mouse_start_y;
//		console.info(y_offset);

		//console.info(g_mouse_start_y);
//		console.info(g_is_vertical + ', ' + x_offset + ', ' + y_offset);
		if (g_is_vertical && g_moving_pannel) {
//			console.info('vertical ...');
			// Show the top panel if we are swiping down from the top
			if (g_mouse_start_y < 200 && y_offset > 0) {
				var y = y_offset > 200.0 ? 200.0 : y_offset;
	//			console.info(y / 200.0);
				showTopPanel(y / 200.0, false);
			// Scroll the page up and down
			} else {
				var window_height = $(window).height();
				var image_height = $('#' + g_middle.children()[0].id).height();

				// Only scroll down if the top of the image is above the screen top
				var new_offset = y_offset + g_scroll_y_start;
				if (new_offset >= 0 && image_height - new_offset > window_height) {
					g_scroll_y_temp = y_offset;
					window.scrollTo(0, new_offset);
//					console.info(image_height + ' + ' + new_offset + '(' + (image_height - new_offset)  + ') > ' + window_height);
				}
			}
		}

		// Scroll the comic panels if we are swiping right or left
		if (! g_is_vertical && g_moving_pannel) {
			var x = (g_moving_pannel.panel_index * g_screen_width) + x_offset;
			var style = g_moving_pannel.style;
			style.transitionDuration = '0.0s';
			style.transform = 'translate3d(' + x + 'px, 0px, 0px)';

			if (x_offset > 0) {
				var x = (g_left[0].panel_index * g_screen_width) + x_offset;
				var style = g_left[0].style;
				style.transitionDuration = '0.0s';
				style.transform = 'translate3d(' + x + 'px, 0px, 0px)';

				if (Math.abs(x_offset) > g_screen_width / 2 && g_image_index > 0) {
	//				console.info(Math.abs(x_offset) + ' > ' + (g_screen_width / 2));
					g_is_swiping_right = true;
				} else {
					g_is_swiping_right = false;
					g_is_swiping_left = false;
				}
			} else {
				var x = (g_right[0].panel_index * g_screen_width) + x_offset;
				var style = g_right[0].style;
				style.transitionDuration = '0.0s';
				style.transform = 'translate3d(' + x + 'px, 0px, 0px)';

				if (Math.abs(x_offset) > g_screen_width / 2 && g_image_index < g_images.length -1) {
	//				console.info(Math.abs(x_offset) + ' > ' + (g_screen_width / 2));
					g_is_swiping_left = true;
				} else {
					g_is_swiping_right = false;
					g_is_swiping_left = false;
				}
			}
		}
	});

	$('#comicPannel').hide();

	// When a file is selected, load it
	$('#fileInput').change(function(e) {
		loadComic();
	});

	// When the button is clicked, click the hidden file load button
	$('#fileLoad').click(function(e) {
		$('#fileInput').click();
	});
	clearComicData();
});
		</script>
	</body>

</html>
<commit_msg>Spelling,<commit_after><!DOCTYPE html>

<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title>Comic Book Reader</title>
		<style>
#topPanel {
	opacity: 0.9;
	position: absolute;
	top: 0px;
	z-index: 1000;
	border: 1px solid black;
	margin: 20px;
	margin-top: 0px;
	padding: 20px;
	padding-top: 0px;
	box-shadow: 10px 10px 5px #888888;
	background: silver;
	text-align: center;
}

#loadProgress {
	width: 100%;
	display: none;
}

#btnFullScreen {
	font: 30px/100px Helvetica, Arial, sans-serif;
}

#fileInput {
	display: none;
}

#fileLoad {
	font: 30px/100px Helvetica, Arial, sans-serif;
}

.comicImage {
	pointer-events: none;
	width: 100%;
	user-select: none;
	-moz-user-select: none;
	-webkit-user-select: none;
	-webkit-user-drag: none;
}

#comicPanel {
	position: absolute;
	z-index: 0px;
	/*border: 10px solid orange;*/
	overflow: hidden;
}

#pageContainer {
	/*border: 20px solid black;*/
	overflow: visible;
}

#pageLeft {
	position: absolute;
	z-index: 0px;
	text-align: center;
	background-color: red;
}

#pageMiddle {
	position: absolute;
	z-index: 0px;
	text-align: center;
	background-color: green;
}

#pageRight {
	position: absolute;
	z-index: 0px;
	text-align: center;
	background-color: blue;
}

#pageOverlay {
	position: absolute;
	z-index: 1px;
	pointer-events: none;
	text-align: center;
	font: 100px/300px Helvetica, Arial, sans-serif;
	text-shadow: 4px 4px 20px white;
	opacity: 0.5;
}
		</style>
		<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
		<script src="js/polyfill/polyfill.js"></script>
		<script src="js/zip.js"></script>
		<script src="js/screenfull.js/screenfull.js"></script>
	</head>
	<body style="margin: 0; padding: 0;">
		<div id="topPanel">
			<input id="fileInput" type="file" required="required" />
			<button id="fileLoad">Load comic from your computer</button>

			<button id="btnFullScreen">Full Screen</button>

			<progress id="loadProgress" max="1" value="0"></progress>
			<p><span id="loadError"></span></p>
			<div id="comicData">
				<b>Name:</b> <span id="nameValue"></span><br>
				<b>Size:</b> <span id="sizeValue"></span><br>
				<b>Type:</b> <span id="typeValue"></span><br>
			</div>
		</div>

		<div id="comicPanel" touchable>
			<div id="pageContainer" touchable>
				<div id="pageLeft" touchable>
					Left Page
				</div>
				<div id="pageMiddle" touchable>
					Middle Page
				</div>
				<div id="pageRight" touchable>
					Right Page
				</div>
				<div id="pageOverlay" touchable>
				</div>
			</div>
		</div>

		<script>

var g_entries = [];
var g_images = [];
var g_image_index = 0;
var g_moving_panel = null;
var g_is_mouse_down = false;
var g_mouse_start_x = 0;
var g_mouse_start_y = 0;
var g_is_vertical = false;
var g_screen_width = 0;
var g_is_swiping_right = false;
var g_is_swiping_left = false;
var g_top_visible = 1.0;
var g_left = null;
var g_middle = null;
var g_right = null;
var g_scroll_y_temp = 0;
var g_scroll_y_start = 0;
var g_needs_resize = false;

function toFrieldlySize(size) {
	if (size >= 1024000000) {
		return (size / 1024000000).toFixed(2) + ' GB';
	} else if (size >= 1024000) {
		return (size / 1024000).toFixed(2) + ' MB';
	} else if (size >= 1024) {
		return (size / 1024).toFixed(2) + ' KB';
	} else if (size >= 1) {
		return (size / 1).toFixed(2) + ' B';
	}

	return '?';
}

function blobToDataURI(blob, cb) {
	var reader = new FileReader();
	reader.onload = function(e) {
		cb(e.target.result);
	};
	reader.readAsDataURL(blob);
}

function isValidImageType(file_name) {
	file_name = file_name.toLowerCase();
	return file_name.endsWith('.jpeg') ||
			file_name.endsWith('.jpg') ||
			file_name.endsWith('.png') ||
			file_name.endsWith('.bmp');
}

function hideTopPanel(is_instant) {
	var speed = is_instant ? '0.0s' : '0.3s';
	var height = $('#topPanel').outerHeight() + 10;
	var style = $('#topPanel')[0].style;
	style.transitionDuration = speed;
	style.transform = 'translate3d(0px, -' + height + 'px, 0px)';
	g_top_visible = 0.0;
}

function showTopPanel(y_offset, is_instant) {
	var speed = is_instant ? '0.0s' : '0.2s';
	var height = $('#topPanel').outerHeight();
	var offset = -height + (height * y_offset);
	var style = $('#topPanel')[0].style;
	style.transitionDuration = speed;
	style.transform = 'translate3d(0px, ' + offset + 'px, 0px)';
	style.width = (g_screen_width - 80) + 'px';
	g_top_visible = y_offset;
}

function loadComic() {
	var file_input = $('#fileInput');

	// Just return if there is no file selected
	if (file_input[0].files.length === 0) {
		return;
	}

	// Load the file's info
	clearComicData();
	var file = file_input[0].files[0];
	setComicData(file.name, file.size, file.type);

	// Read the file
	onProgress(1, 1);
	$('#loadProgress').hide();
	$('#comicPanel').show();

	hideTopPanel(false);

	var blob = file.slice();
	onLoaded(blob);
}

function friendlyPageNumber() {
	return 'Page ' + (g_image_index + 1) + ' of ' + g_images.length;
}

function replaceIfDifferentImage(parent, image) {
	var children = parent.children();
	if (children.length === 0) {
		parent.append(image);
	} else if (children.length && children[0].id !== image.id) {
		parent.empty();
		parent.append(image);
	}
}

function loadCurrentPage() {
	// Load the middle page
	updatePageCache(g_image_index);
	replaceIfDifferentImage(g_middle, g_images[g_image_index]);
	$('#pageOverlay')[0].innerHTML = friendlyPageNumber();

	// Load right page
	if (g_image_index === g_images.length -1) {
		g_right.empty();
	} else if (g_image_index < g_images.length -1) {
		updatePageCache(g_image_index + 1);
		replaceIfDifferentImage(g_right, g_images[g_image_index + 1]);
	}

	// Load left page
	if (g_image_index === 0) {
		g_left.empty();
	} else if (g_image_index > 0) {
		updatePageCache(g_image_index - 1);
		replaceIfDifferentImage(g_left, g_images[g_image_index - 1]);
	}
}

function updatePageCache(index) {
	var img = g_images[index];
	if (img.is_loaded) {
		console.info('!!! Cached page: ' + index + ', ' + img.title);
	} else {
		var entry = g_entries[index];
		entry.getData(new zip.BlobWriter(), function(blob) {
	//		console.info(entry.filename);
	//		console.info(blob);
			blobToDataURI(blob, function(data_uri) {
				// Load the blob into an image
				var img = g_images[entry.index];
				img.src = data_uri;
				img.is_loaded = true;
				console.info('Loaded page: ' + index + ', ' + img.title);
			});
		});
	}
}

function setComicData(name, size, type) {
	$('#comicData').show();
	$('#nameValue').text(name);
	$('#sizeValue').text(toFrieldlySize(size));
	$('#typeValue').text(type);
}

function clearComicData() {
	// Reset the UI
	$('#loadError').hide();
	$('#comicData').hide();
	$('#loadProgress').val(0);
	setComicData('?', '?', '?');

	// Remove all the old images and compressed file entries
	g_middle.empty();
	g_left.empty();
	g_right.empty();
	g_image_index = 0;
	g_images = [];
	g_entries = [];
}

function onLoaded(blob) {
	var reader = new zip.BlobReader(blob);
	zip.createReader(reader, function(reader) {
		reader.getEntries(function(entries) {
			// Get only the entries that are valid images
			g_entries = [];
			entries.forEach(function(entry) {
				if (! entry.directory && isValidImageType(entry.filename)) {
					g_entries.push(entry);
				}
			});

			// Sort the entries by their file names
			g_entries.sort(function(a, b){
				if(a.filename < b.filename) return -1;
				if(a.filename > b.filename) return 1;
				return 0;
			});

			// Create empty images for each page
			var i = 0;
			g_entries.forEach(function(entry) {
				var img = document.createElement('img');
				img.id = 'page_' + i;
				img.title = entry.filename;
				img.className = 'comicImage';
				img.ondragstart = function() { return false; }
				img.onload = function() {
					if (g_needs_resize) {
						onResize(g_screen_width);
					}
				};
				img.draggable = 'false';
				g_images.push(img);
				entry.index = i;
				i++;
			});

			g_image_index = 0;
			loadCurrentPage();
			var width = $(window).width();
			onResize(width);
		});
	}, function(e) {
		onError('Failed to read file!');
	});
}

function onError(msg) {
	$('#comicPanel').hide();
	$('#comicData').hide();
	$('#loadError').text('Error: ' + msg);
	$('#loadError').show();
	showTopPanel(1.0, true);
}

function onProgress(loaded, total) {
	$('#loadProgress').show();
	$('#loadProgress').val(loaded / total);
}

function largestNumber(a, b, c) {
	var larger = a > b ? a : b;
	larger = larger > c ? larger : c;
	return larger;
}

function largestPageNaturalHeight() {
	var left_children = g_left.children();
	var middle_children = g_middle.children();
	var right_children = g_right.children();

	var left_width = left_children.length > 0 ? left_children[0].naturalWidth : 0;
	var middle_width = middle_children.length > 0 ? middle_children[0].naturalWidth : 0;
	var right_width = right_children.length > 0 ? right_children[0].naturalWidth : 0;

	var left_ratio = left_width !== 0 ? g_screen_width / left_width : 0;
	var middle_ratio = middle_width !== 0 ? g_screen_width / middle_width : 0;
	var right_ratio = right_width !== 0 ? g_screen_width / right_width : 0;

	var left_height = left_children.length > 0 ? left_ratio * left_children[0].naturalHeight : 0;
	var middle_height = middle_children.length > 0 ? middle_ratio * middle_children[0].naturalHeight : 0;
	var right_height =  right_children.length > 0 ?  right_ratio *  right_children[0].naturalHeight : 0;

	return largestNumber(left_height, middle_height, right_height);
}

function onResize(screen_width) {
//	console.info('Resize called ...');
	g_screen_width = screen_width;

	// Move the top panel to the new top
	if (g_top_visible < 1.0) {
		hideTopPanel(true);
	} else {
		showTopPanel(g_top_visible, true);
	}

	// Figure out if the images are loaded yet.
	// If not, we will manually fire the resize event when they do
	var children = g_middle.children();
	if (children.length === 0) {
		g_needs_resize = true;
//		console.info('Needs resize ...');
		return;
	} else if (children[0].naturalWidth === 0) {
		g_needs_resize = true;
//		console.info('Needs resize ...');
		return;
	}

	// Find the largest natural height from the images
	var height = largestPageNaturalHeight();

	// Make the panel as wide as the screen
	g_needs_resize = false;
	$('#comicPanel')[0].style.width = (g_screen_width * 1) + 'px';

	// Make it as wide as the screen and as tall as the tallest image
	var style = $('#pageContainer')[0].style;
	style.width = (g_screen_width * 3) + 'px';
	style.height = height + 'px';
	style.transitionDuration = '0.0s';
	style.transform = 'translate3d(-' + g_screen_width + 'px, 0px, 0px)';

	// Make it as wide as the screen and as tall as the tallest image
	style = $('#pageOverlay')[0].style;
	style.width = g_screen_width + 'px';
	style.height = height + 'px';
	style.transitionDuration = '0.0s';
	style.transform = 'translate3d(' + (1 * g_screen_width) + 'px, 0px, 0px)';

	// Make it as wide as the screen and as tall as the tallest image
	style = g_left[0].style;
	style.width = g_screen_width + 'px';
	style.height = height + 'px';
	style.transitionDuration = '0.0s';
	g_left[0].panel_index = 0;
	style.transform = 'translate3d(' + (g_left[0].panel_index * g_screen_width) + 'px, 0px, 0px)';

	// Make it as wide as the screen and as tall as the tallest image
	style = g_middle[0].style;
	style.width = g_screen_width + 'px';
	style.height = height + 'px';
	style.transitionDuration = '0.0s';
	g_middle[0].panel_index = 1;
	style.transform = 'translate3d(' + (g_middle[0].panel_index * g_screen_width) + 'px, 0px, 0px)';

	// Make it as wide as the screen and as tall as the tallest image
	style = g_right[0].style;
	style.width = g_screen_width + 'px';
	style.height = height + 'px';
	style.transitionDuration = '0.0s';
	g_right[0].panel_index = 2;
	style.transform = 'translate3d(' + (g_right[0].panel_index * g_screen_width) + 'px, 0px, 0px)';
}

$(document).ready(function() {
	// Tell zip.js where it can find the worker js file
	zip.workerScriptsPath = 'js/';

	g_left = $('#pageLeft');
	g_middle = $('#pageMiddle');
	g_right = $('#pageRight');

	// Resize everything when the browser resizes
	$(window).resize(function(e) {
		var width = $(window).width();
		onResize(width);
	});
	$(window).trigger('resize');

	// Stop the right click menu from popping up
	$(document).on('contextmenu', function(e) {
		e.preventDefault();
	});

	// Toggle full screen
	$('#btnFullScreen').click(function () {
		if (screenfull.enabled) {
			screenfull.toggle();
		}
	});

	g_left.mousedown(function(e) {
		if (this.panel_index === 1) {
			g_moving_panel = this;
		} else {
			g_moving_panel = null;
		}
	});

	g_middle.mousedown(function(e) {
		if (this.panel_index === 1) {
			g_moving_panel = this;
		} else {
			g_moving_panel = null;
		}
	});

	g_right.mousedown(function(e) {
		if (this.panel_index === 1) {
			g_moving_panel = this;
		} else {
			g_moving_panel = null;
		}
	});

	$('body').mousedown(function(e) {
		// Skip if clicking on something that is no touchable
		if (! e.target.hasAttribute('touchable')) {
			return;
		}

		// If the top menu is showing, hide it
		if (e.target.hasAttribute('touchable') && g_top_visible > 0.0) {
			hideTopPanel(false);
			return;
		}

		g_is_mouse_down = true;
		g_mouse_start_x = e.clientX;
		g_mouse_start_y = e.clientY;
	});

	$('body').on('mouseup mouseleave', function(e) {
		if (g_top_visible > 0.0 && g_top_visible < 1.0) {
			hideTopPanel(false);
		}

		if (! g_is_mouse_down) {
			return;
		}
		g_is_mouse_down = false;
		g_moving_panel = null;
		g_scroll_y_start += g_scroll_y_temp;
		g_scroll_y_temp = 0;


		if (g_is_swiping_right) {
			g_is_swiping_right = false;

			var style = g_middle[0].style;
			style.transitionDuration = '0.3s';
			style.transform = 'translate3d(' + (g_screen_width * 2) + 'px, 0px, 0px)';

			style = g_left[0].style;
			style.transitionDuration = '0.3s';
			style.transform = 'translate3d(' + (g_screen_width) + 'px, 0px, 0px)';

			// Update the page orderings, after the pages move into position
			setTimeout(function() {
				var old_left = g_left;
				var old_middle = g_middle;
				var old_right = g_right;
				g_right = old_middle;
				g_middle = old_left;
				g_left = old_right;

				g_left[0].panel_index = 0;
				g_middle[0].panel_index = 1;
				g_right[0].panel_index = 2;

				style = g_left[0].style;
				style.transitionDuration = '0.0s';
				style.transform = 'translate3d(' + (g_left[0].panel_index * g_screen_width) + 'px, 0px, 0px)';
				g_scroll_y_start = 0;
				window.scrollTo(0, 0);

				if (g_image_index > 0) {
					g_image_index--;
					loadCurrentPage();
				}
			}, 300);
		} else if (g_is_swiping_left) {
			g_is_swiping_left = false;

			var style = g_middle[0].style;
			style.transitionDuration = '0.3s';
			style.transform = 'translate3d(0px, 0px, 0px)';

			style = g_right[0].style;
			style.transitionDuration = '0.3s';
			style.transform = 'translate3d(' + (g_screen_width) + 'px, 0px, 0px)';

			// Update the page orderings, after the pages move into position
			setTimeout(function() {
				var old_left = g_left;
				var old_middle = g_middle;
				var old_right = g_right;
				g_left = old_middle;
				g_middle = old_right;
				g_right = old_left;

				g_left[0].panel_index = 0;
				g_middle[0].panel_index = 1;
				g_right[0].panel_index = 2;

				style = g_right[0].style;
				style.transitionDuration = '0.0s';
				style.transform = 'translate3d(' + (g_right[0].panel_index * g_screen_width) + 'px, 0px, 0px)';
				g_scroll_y_start = 0;
				window.scrollTo(0, 0);

				if (g_image_index < g_images.length -1) {
					g_image_index++;
					loadCurrentPage();
				}
			}, 300);
		} else {
			var style = g_left[0].style;
			style.transitionDuration = '0.3s';
			style.transform = 'translate3d(0px, 0px, 0px)';

			style = g_middle[0].style;
			style.transitionDuration = '0.3s';
			style.transform = 'translate3d(' + (g_screen_width * 1) + 'px, 0px, 0px)';

			style = g_right[0].style;
			style.transitionDuration = '0.3s';
			style.transform = 'translate3d(' + (g_screen_width * 2) + 'px, 0px, 0px)';
		}
	});

	$('body').mousemove(function(e) {
		if (! g_is_mouse_down) {
			return;
		}

		// Figure out if we are moving vertically or horizontally
//		console.info(e.clientX + ', ' + g_mouse_start_x + ', ' + g_moving_panel.panel_index + ', ' + g_moving_panel.id);
		if (Math.abs(e.clientY - g_mouse_start_y) > Math.abs(e.clientX - g_mouse_start_x)) {
			g_is_vertical = true;
		} else {
			g_is_vertical = false;
		}

		// Get how far we have moved since pressing down
//		console.info(g_is_vertical);
//		console.info(e.clientX + ', ' + e.clientY + ', ' + g_is_vertical);
		var x_offset = e.clientX - g_mouse_start_x;
		var y_offset = e.clientY - g_mouse_start_y;
//		console.info(y_offset);

		//console.info(g_mouse_start_y);
//		console.info(g_is_vertical + ', ' + x_offset + ', ' + y_offset);
		if (g_is_vertical && g_moving_panel) {
//			console.info('vertical ...');
			// Show the top panel if we are swiping down from the top
			if (g_mouse_start_y < 200 && y_offset > 0) {
				var y = y_offset > 200.0 ? 200.0 : y_offset;
	//			console.info(y / 200.0);
				showTopPanel(y / 200.0, false);
			// Scroll the page up and down
			} else {
				var window_height = $(window).height();
				var image_height = $('#' + g_middle.children()[0].id).height();

				// Only scroll down if the top of the image is above the screen top
				var new_offset = y_offset + g_scroll_y_start;
				if (new_offset >= 0 && image_height - new_offset > window_height) {
					g_scroll_y_temp = y_offset;
					window.scrollTo(0, new_offset);
//					console.info(image_height + ' + ' + new_offset + '(' + (image_height - new_offset)  + ') > ' + window_height);
				}
			}
		}

		// Scroll the comic panels if we are swiping right or left
		if (! g_is_vertical && g_moving_panel) {
			var x = (g_moving_panel.panel_index * g_screen_width) + x_offset;
			var style = g_moving_panel.style;
			style.transitionDuration = '0.0s';
			style.transform = 'translate3d(' + x + 'px, 0px, 0px)';

			if (x_offset > 0) {
				var x = (g_left[0].panel_index * g_screen_width) + x_offset;
				var style = g_left[0].style;
				style.transitionDuration = '0.0s';
				style.transform = 'translate3d(' + x + 'px, 0px, 0px)';

				if (Math.abs(x_offset) > g_screen_width / 2 && g_image_index > 0) {
	//				console.info(Math.abs(x_offset) + ' > ' + (g_screen_width / 2));
					g_is_swiping_right = true;
				} else {
					g_is_swiping_right = false;
					g_is_swiping_left = false;
				}
			} else {
				var x = (g_right[0].panel_index * g_screen_width) + x_offset;
				var style = g_right[0].style;
				style.transitionDuration = '0.0s';
				style.transform = 'translate3d(' + x + 'px, 0px, 0px)';

				if (Math.abs(x_offset) > g_screen_width / 2 && g_image_index < g_images.length -1) {
	//				console.info(Math.abs(x_offset) + ' > ' + (g_screen_width / 2));
					g_is_swiping_left = true;
				} else {
					g_is_swiping_right = false;
					g_is_swiping_left = false;
				}
			}
		}
	});

	$('#comicPanel').hide();

	// When a file is selected, load it
	$('#fileInput').change(function(e) {
		loadComic();
	});

	// When the button is clicked, click the hidden file load button
	$('#fileLoad').click(function(e) {
		$('#fileInput').click();
	});
	clearComicData();
});
		</script>
	</body>

</html>

{'fraction_non_alphanumeric': 0.16096563858414406, 'fraction_numerical': 0.020389153384392466, 'mean_word_length': 3.661560728500784, 'pattern_counts': {'":': 0, '<': 145, '<?xml version=': 0, '>': 189, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '700356', 'n_tokens_mistral': 16299, 'n_tokens_neox': 14416, 'n_words': 3168}