diff --git a/images/buttons.png b/images/buttons.png
index 682212660..3357b47d6 100644
Binary files a/images/buttons.png and b/images/buttons.png differ
diff --git a/images/source/FileButton.psd.zip b/images/source/FileButton.psd.zip
new file mode 100644
index 000000000..1f2b51cee
Binary files /dev/null and b/images/source/FileButton.psd.zip differ
diff --git a/multi-page-viewer.css b/multi-page-viewer.css
index f9a7837b1..7f4701022 100644
--- a/multi-page-viewer.css
+++ b/multi-page-viewer.css
@@ -84,7 +84,7 @@ span {
     background-color: #eee;
     border-bottom: 1px solid #666;
     padding: 4px 0px 0px 8px;
-    position:fixed;
+    position: fixed;
     left: 0px;
     top: 0px;
     height: 40px;
@@ -136,10 +136,61 @@ span {
     background: url('images/buttons.png') no-repeat -28px 0px;
 }
 
+#openFileButton {
+    background: url('images/buttons.png') no-repeat -56px -23px;
+    cursor: default;
+    display: inline-block;
+    float: left;
+    margin: 0px 0px 0px 3px;
+    width: 29px;
+    height: 23px;
+}
+
+#openFileButton.down {
+    background: url('images/buttons.png') no-repeat -56px -46px;
+}
+
+#openFileButton.disabled {
+    background: url('images/buttons.png') no-repeat -56px 0px;
+}
+
+#fileInput {
+    display: none;
+}
+
 #pageNumber {
     text-align: right;
 }
 
+#sidebar {
+    background-color: rgba(0, 0, 0, 0.8);
+    position: fixed;
+    width: 150px;
+    top: 62px;
+    bottom: 18px;
+    border-top-right-radius: 8px;
+    border-bottom-right-radius: 8px;
+    -moz-border-radius-topright: 8px;
+    -moz-border-radius-bottomright: 8px;
+    -webkit-border-top-right-radius: 8px;
+    -webkit-border-bottom-right-radius: 8px;
+}
+
+#sidebarScrollView {
+    position: absolute;
+    overflow: hidden;
+    overflow-y: auto;
+    top: 40px;
+    right: 10px;
+    bottom: 10px;
+    left: 10px;
+}
+
+#sidebarContentView {
+    height: auto;
+    width: 100px;
+}
+
 #viewer {
     margin: 44px 0px 0px;
     padding: 8px 0px;
diff --git a/multi-page-viewer.html b/multi-page-viewer.html
index 4e15cf4f8..ffbdfe707 100644
--- a/multi-page-viewer.html
+++ b/multi-page-viewer.html
@@ -33,7 +33,19 @@
             </select>
             <span class="label">Zoom</span>
         </span>
+        <span class="control">
+            <span id="openFileButton"></span>
+            <input type="file" id="fileInput"/>
+            <span class="label">Open File</span>
+        </span>
     </div>
+    <!--<div id="sidebar">
+        <div id="sidebarScrollView">
+            <div id="sidebarContentView">
+                
+            </div>
+        </div>
+    </div>-->
     <div id="viewer"></div>
 </body>
 </html>
diff --git a/multi-page-viewer.js b/multi-page-viewer.js
index 9d9cec702..baad7809e 100644
--- a/multi-page-viewer.js
+++ b/multi-page-viewer.js
@@ -12,6 +12,7 @@ var PDFViewer = {
     nextPageButton: null,
     pageNumberInput: null,
     scaleSelect: null,
+    fileInput: null,
     
     willJumpToPage: false,
 
@@ -215,7 +216,7 @@ var PDFViewer = {
         }
     },
   
-    open: function(url) {
+    openURL: function(url) {
         PDFViewer.url = url;
         document.title = url;
     
@@ -231,26 +232,35 @@ var PDFViewer = {
                     req.responseArrayBuffer ||
                     req.response;
 
-                PDFViewer.pdf = new PDFDoc(new Stream(data));
-                PDFViewer.numberOfPages = PDFViewer.pdf.numPages;
-                document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString();
-          
-                for (var i = 1; i <= PDFViewer.numberOfPages; i++) {
-                    PDFViewer.createPage(i);
-                }
-
-                if (PDFViewer.numberOfPages > 0) {
-                    PDFViewer.drawPage(1);
-                }
-                
-                PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ?
-                     'disabled' : '';
-                 PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ?
-                     'disabled' : '';
+                PDFViewer.readPDF(data);
             }
         };
     
         req.send(null);
+    },
+    
+    readPDF: function(data) {
+        while (PDFViewer.element.hasChildNodes()) {
+            PDFViewer.element.removeChild(PDFViewer.element.firstChild);
+        }
+        
+        PDFViewer.pdf = new PDFDoc(new Stream(data));
+        PDFViewer.numberOfPages = PDFViewer.pdf.numPages;
+        document.getElementById('numPages').innerHTML = PDFViewer.numberOfPages.toString();
+  
+        for (var i = 1; i <= PDFViewer.numberOfPages; i++) {
+            PDFViewer.createPage(i);
+        }
+
+        if (PDFViewer.numberOfPages > 0) {
+            PDFViewer.drawPage(1);
+            document.location.hash = 1;
+        }
+        
+        PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ?
+             'disabled' : '';
+         PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ?
+             'disabled' : '';
     }
 };
 
@@ -354,11 +364,63 @@ window.onload = function() {
     PDFViewer.scaleSelect.onchange = function(evt) {
         PDFViewer.changeScale(parseInt(this.value));
     };
+    
+    if (window.File && window.FileReader && window.FileList && window.Blob) {
+        var openFileButton = document.getElementById('openFileButton');
+        openFileButton.onclick = function(evt) {
+            if (this.className.indexOf('disabled') === -1) {
+                PDFViewer.fileInput.click();
+            }
+        };
+        openFileButton.onmousedown = function(evt) {
+            if (this.className.indexOf('disabled') === -1) {
+                this.className = 'down';
+            }
+        };
+        openFileButton.onmouseup = function(evt) {
+            this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : '';
+        };
+        openFileButton.onmouseout = function(evt) {
+            this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : '';
+        };
+        
+        PDFViewer.fileInput = document.getElementById('fileInput');
+        PDFViewer.fileInput.onchange = function(evt) {
+            var files = evt.target.files;
+            
+            if (files.length > 0) {
+                var file = files[0];
+                var fileReader = new FileReader();
+                
+                document.title = file.name;
+                
+                // Read the local file into a Uint8Array.
+                fileReader.onload = function(evt) {
+                    var data = evt.target.result;
+                    var buffer = new ArrayBuffer(data.length);
+                    var uint8Array = new Uint8Array(buffer);
+                    
+                    for (var i = 0; i < data.length; i++) {
+                        uint8Array[i] = data.charCodeAt(i);
+                    }
+                    
+                    PDFViewer.readPDF(uint8Array);
+                };
+                
+                // Read as a binary string since "readAsArrayBuffer" is not yet
+                // implemented in Firefox.
+                fileReader.readAsBinaryString(file);
+            }
+        };
+        PDFViewer.fileInput.value = null;
+    } else {
+        document.getElementById('fileWrapper').style.display = 'none';
+    }
 
     PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber;
     PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0;
     
-    PDFViewer.open(PDFViewer.queryParams.file || PDFViewer.url);
+    PDFViewer.openURL(PDFViewer.queryParams.file || PDFViewer.url);
 
     window.onscroll = function(evt) {        
         var lastPagesDrawn = PDFViewer.lastPagesDrawn;