Improvements and refinements to web site

git-svn-id: https://zxing.googlecode.com/svn/trunk@397 59b500cc-1b3d-0410-9834-0bbf25fbcc57
diff --git a/zxingorg/build.xml b/zxingorg/build.xml
index 073485b..5d75636 100644
--- a/zxingorg/build.xml
+++ b/zxingorg/build.xml
@@ -67,14 +67,16 @@
       <classes dir="web/WEB-INF/classes"/>
       <fileset dir="web">
         <include name="*.jspx"/>
+        <include name="*.png"/>
       </fileset>
     </war>
   </target>
 
 	<target name="clean">
 		<delete dir="web/WEB-INF/classes"/>
-    <delete file="../core/core.jar"/>
-    <delete file="../javase/javase.jar"/>
+    <delete file="web/WEB-INF/lib/core.jar"/>
+    <delete file="web/WEB-INF/lib/javase.jar"/>
+    <delete file="zxingorg.war"/>
   </target>
 
 </project>
diff --git a/zxingorg/src/com/google/zxing/web/DecodeEmailTask.java b/zxingorg/src/com/google/zxing/web/DecodeEmailTask.java
index 9105177..10cbcb1 100644
--- a/zxingorg/src/com/google/zxing/web/DecodeEmailTask.java
+++ b/zxingorg/src/com/google/zxing/web/DecodeEmailTask.java
@@ -38,13 +38,18 @@
 import javax.mail.internet.MimeMultipart;
 import java.awt.image.BufferedImage;
 import java.io.UnsupportedEncodingException;
+import java.io.IOException;
 import java.util.Properties;
 import java.util.TimerTask;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * @author Sean Owen
+ * A {@link TimerTask} which repeatedly checks an e-mail account for messages with an attached
+ * image. When one is found it attempts to decode the image and replies with the decoded messages
+ * by e-mail.
+ *
+ * @author Sean Owen (srowen@google.com)
  */
 final class DecodeEmailTask extends TimerTask {
 
@@ -89,75 +94,85 @@
   @Override
   public void run() {
     log.info("Checking email...");
+    Session session = Session.getInstance(sessionProperties, emailAuthenticator);
+    Store store = null;
+    Folder inbox = null;
     try {
-      Session session = Session.getInstance(sessionProperties, emailAuthenticator);
-      Store store = null;
-      Folder inbox = null;
-      try {
-        store = session.getStore("pop3");
-        store.connect();
-        inbox = store.getFolder("INBOX");
-        inbox.open(Folder.READ_WRITE);
-        int count = inbox.getMessageCount();
-        if (count > 0) {
-          log.info("Found " + count + " messages");
-        }
-        for (int i = 1; i <= count; i++) {
-          log.info("Processing message " + i);
-          Message message = inbox.getMessage(i);
-          Object content = message.getContent();
-          if (content instanceof MimeMultipart) {
-            MimeMultipart mimeContent = (MimeMultipart) content;
-            int numParts = mimeContent.getCount();
-            for (int j = 0; j < numParts; j++) {
-              MimeBodyPart part = (MimeBodyPart) mimeContent.getBodyPart(j);
-              String contentType = part.getContentType();
-              if (!contentType.startsWith("image/")) {
-                continue;
-              }
-              BufferedImage image = ImageIO.read(part.getInputStream());
-              if (image != null) {
-                Reader reader = new MultiFormatReader();
-                Result result = null;
-                try {
-                  result = reader.decode(new BufferedImageMonochromeBitmapSource(image), DecodeServlet.HINTS);
-                } catch (ReaderException re) {
-                  log.info("Decoding FAILED");
-                }
-
-                Message reply = new MimeMessage(session);
-                Address sender = message.getFrom()[0];
-                reply.setRecipient(Message.RecipientType.TO, sender);
-                reply.setFrom(fromAddress);
-                if (result == null) {
-                  reply.setSubject("Decode failed");
-                  reply.setContent("Sorry, we could not decode that image.", "text/plain");
-                } else {
-                  String text = result.getText();
-                  reply.setSubject("Decode succeeded");
-                  reply.setContent(text, "text/plain");
-                }
-                log.info("Sending reply");
-                Transport.send(reply);
-              }
-            }
-          }
-          message.setFlag(Flags.Flag.DELETED, true);
-        }
-      } finally {
-        try {
-          if (inbox != null) {
-            inbox.close(true);
-          }
-          if (store != null) {
-            store.close();
-          }
-        } catch (MessagingException me) {
-          // continue
-        }
+      store = session.getStore("pop3");
+      store.connect();
+      inbox = store.getFolder("INBOX");
+      inbox.open(Folder.READ_WRITE);
+      int count = inbox.getMessageCount();
+      if (count > 0) {
+        log.info("Found " + count + " messages");
+      }
+      for (int i = 1; i <= count; i++) {
+        log.info("Processing message " + i);
+        Message message = inbox.getMessage(i);
+        processMessage(session, message);
       }
     } catch (Throwable t) {
       log.log(Level.WARNING, "Unexpected error", t);
+    } finally {
+      closeResources(store, inbox);
+    }
+  }
+
+  private void processMessage(Session session, Message message) throws MessagingException, IOException {
+    Object content = message.getContent();
+    if (content instanceof MimeMultipart) {
+      MimeMultipart mimeContent = (MimeMultipart) content;
+      int numParts = mimeContent.getCount();
+      for (int j = 0; j < numParts; j++) {
+        MimeBodyPart part = (MimeBodyPart) mimeContent.getBodyPart(j);
+        processMessagePart(session, message, part);
+      }
+    }
+    message.setFlag(Flags.Flag.DELETED, true);
+  }
+
+  private void processMessagePart(Session session, Message message, MimeBodyPart part)
+      throws MessagingException, IOException {
+    String contentType = part.getContentType();
+    if (contentType.startsWith("image/")) {
+      BufferedImage image = ImageIO.read(part.getInputStream());
+      if (image != null) {
+        Reader reader = new MultiFormatReader();
+        Result result = null;
+        try {
+          result = reader.decode(new BufferedImageMonochromeBitmapSource(image), DecodeServlet.HINTS);
+        } catch (ReaderException re) {
+          log.info("Decoding FAILED");
+        }
+
+        Message reply = new MimeMessage(session);
+        Address sender = message.getFrom()[0];
+        reply.setRecipient(Message.RecipientType.TO, sender);
+        reply.setFrom(fromAddress);
+        if (result == null) {
+          reply.setSubject("Decode failed");
+          reply.setContent("Sorry, we could not decode that image.", "text/plain");
+        } else {
+          String text = result.getText();
+          reply.setSubject("Decode succeeded");
+          reply.setContent(text, "text/plain");
+        }
+        log.info("Sending reply");
+        Transport.send(reply);
+      }
+    }
+  }
+
+  private void closeResources(Store store, Folder inbox) {
+    try {
+      if (inbox != null) {
+        inbox.close(true);
+      }
+      if (store != null) {
+        store.close();
+      }
+    } catch (MessagingException me) {
+      // continue
     }
   }
 
diff --git a/zxingorg/src/com/google/zxing/web/DecodeServlet.java b/zxingorg/src/com/google/zxing/web/DecodeServlet.java
index 7c69cc5..a50719a 100644
--- a/zxingorg/src/com/google/zxing/web/DecodeServlet.java
+++ b/zxingorg/src/com/google/zxing/web/DecodeServlet.java
@@ -22,6 +22,7 @@
 import com.google.zxing.ReaderException;
 import com.google.zxing.Result;
 import com.google.zxing.client.j2se.BufferedImageMonochromeBitmapSource;
+import com.google.zxing.client.result.ParsedReaderResult;
 import org.apache.commons.fileupload.FileItem;
 import org.apache.commons.fileupload.FileUploadException;
 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
@@ -63,7 +64,10 @@
 import java.util.logging.Logger;
 
 /**
- * @author Sean Owen
+ * {@link HttpServlet} which decodes images containing barcodes. Given a URL, it will
+ * retrieve the image and decode it. It can also process image files uploaded via POST.
+ * 
+ * @author Sean Owen (srowen@google.com)
  */
 public final class DecodeServlet extends HttpServlet {
 
@@ -114,7 +118,7 @@
   }
 
   @Override
-  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
     String imageURIString = request.getParameter("u");
     if (imageURIString == null || imageURIString.length() == 0) {
@@ -149,7 +153,7 @@
       log.info("Decoding " + imageURI);
       InputStream is = getResponse.getEntity().getContent();
       try {
-        processStream(is, response);
+        processStream(is, request, response);
       } finally {
         is.close();
       }
@@ -183,12 +187,12 @@
             log.info("Decoding uploaded file");
             InputStream is = item.getInputStream();
             try {
-              processStream(is, response);
+              processStream(is, request, response);
             } finally {
               is.close();
             }
           } else {
-            throw new ServletException("File is too large: " + item.getSize());
+            response.sendRedirect("badimage.jspx");
           }
           break;
         }
@@ -199,7 +203,8 @@
 
   }
 
-  private static void processStream(InputStream is, HttpServletResponse response) throws IOException {
+  private static void processStream(InputStream is, HttpServletRequest request, HttpServletResponse response)
+      throws ServletException, IOException {
     BufferedImage image = ImageIO.read(is);
     if (image == null) {
       response.sendRedirect("badimage.jspx");
@@ -216,13 +221,20 @@
       return;
     }
 
-    response.setContentType("text/plain");
-    response.setCharacterEncoding("UTF-8");
-    Writer out = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
-    try {
-      out.write(result.getText());
-    } finally {
-      out.close();
+    if (request.getParameter("full") == null) {
+      response.setContentType("text/plain");
+      response.setCharacterEncoding("UTF-8");
+      Writer out = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
+      try {
+        out.write(result.getText());
+      } finally {
+        out.close();
+      }
+    } else {
+      request.setAttribute("result", result);
+      ParsedReaderResult parsedReaderResult = ParsedReaderResult.parseReaderResult(result);
+      request.setAttribute("parsedReaderResult", parsedReaderResult);
+      request.getRequestDispatcher("decoderesult.jspx").forward(request, response);
     }
   }
 
diff --git a/zxingorg/src/com/google/zxing/web/DoSFilter.java b/zxingorg/src/com/google/zxing/web/DoSFilter.java
index bb94cea..ec287ae 100755
--- a/zxingorg/src/com/google/zxing/web/DoSFilter.java
+++ b/zxingorg/src/com/google/zxing/web/DoSFilter.java
@@ -35,7 +35,10 @@
 import java.util.TimerTask;

 

 /**

- * @author Sean Owen

+ * A {@link Filter} that rejects requests from hosts that are sending too many

+ * requests in too short a time.

+ * 

+ * @author Sean Owen (srowen@google.com)

  */

 public final class DoSFilter implements Filter {

 

diff --git a/zxingorg/src/com/google/zxing/web/EmailAuthenticator.java b/zxingorg/src/com/google/zxing/web/EmailAuthenticator.java
index 7fd79c6..b5d9b3c 100644
--- a/zxingorg/src/com/google/zxing/web/EmailAuthenticator.java
+++ b/zxingorg/src/com/google/zxing/web/EmailAuthenticator.java
@@ -19,6 +19,11 @@
 import javax.mail.Authenticator;
 import javax.mail.PasswordAuthentication;
 
+/**
+ * A simple {@link Authenticator} which replies with a fixed username and password.
+ * 
+ * @author Sean Owen (srowen@google.com)
+ */
 final class EmailAuthenticator extends Authenticator {
 
   private final String emailUsername;
diff --git a/zxingorg/src/com/google/zxing/web/IPTrie.java b/zxingorg/src/com/google/zxing/web/IPTrie.java
index e9ebc63..25a01f8 100755
--- a/zxingorg/src/com/google/zxing/web/IPTrie.java
+++ b/zxingorg/src/com/google/zxing/web/IPTrie.java
@@ -20,7 +20,9 @@
 import java.util.Arrays;

 

 /**

- * @author Sean Owen

+ * A trie data structure for storing a set of IP addresses efficiently.

+ * 

+ * @author Sean Owen (srowen@google.com)

  */

 final class IPTrie {

 

diff --git a/zxingorg/src/com/google/zxing/web/ServletContextLogHandler.java b/zxingorg/src/com/google/zxing/web/ServletContextLogHandler.java
index c76ca24..3ee60ea 100644
--- a/zxingorg/src/com/google/zxing/web/ServletContextLogHandler.java
+++ b/zxingorg/src/com/google/zxing/web/ServletContextLogHandler.java
@@ -22,7 +22,9 @@
 import java.util.logging.LogRecord;
 
 /**
- * @author Sean Owen
+ * A {@link Handler} that redirects log messages to the servlet container log.
+ * 
+ * @author Sean Owen (srowen@google.com)
  */
 final class ServletContextLogHandler extends Handler {
 
diff --git a/zxingorg/web/analytics.jspx b/zxingorg/web/analytics.jspx
new file mode 100644
index 0000000..02d0176
--- /dev/null
+++ b/zxingorg/web/analytics.jspx
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2008 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<!-- Author: Sean Owen (srowen@google.com) -->
+<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1">
+  <jsp:output omit-xml-declaration="true"/>
+  <script type="text/javascript">
+    var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+    document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+  </script>
+  <script type="text/javascript">
+    var pageTracker = _gat._getTracker("UA-788492-5");
+    pageTracker._initData();
+    pageTracker._trackPageview();
+  </script>
+</jsp:root>
diff --git a/zxingorg/web/badimage.jspx b/zxingorg/web/badimage.jspx
index 0fed7b1..f9700b1 100644
--- a/zxingorg/web/badimage.jspx
+++ b/zxingorg/web/badimage.jspx
@@ -14,6 +14,7 @@
  See the License for the specific language governing permissions and
  limitations under the License.
  -->
+<!-- Author: Sean Owen (srowen@google.com) -->
 <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1">
   <jsp:output
           omit-xml-declaration="false" doctype-root-element="html"
@@ -23,27 +24,14 @@
   <jsp:scriptlet>response.setHeader("Cache-Control", "public");</jsp:scriptlet>
   <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
     <head>
-      <title>No Barcode Found</title>
+      <title>Bad Image</title>
     </head>
     <body>
-      <p>
-        <b>Bad URL</b>
-      </p>
+      <h1><img src="zxing-icon.png" height="32" width="32" alt=""/> Bad Image</h1>
       <p>The image you uploaded could not be decoded, or was too large. Go "Back" in your browser and try another
         image.
       </p>
-      <script type="text/javascript">
-        var gaJsHost = (("https:" == document.location.protocol) ?
-        "https://ssl." : "http://www.");
-        document.write(unescape("%3Cscript src='" + gaJsHost +
-        "google-analytics.com/ga.js'
-        type='text/javascript'%3E%3C/script%3E"));
-      </script>
-      <script type="text/javascript">
-        var pageTracker = _gat._getTracker("UA-788492-5");
-        pageTracker._initData();
-        pageTracker._trackPageview();
-      </script>
+      <jsp:include page="analytics.jspx"/>
     </body>
   </html>
 </jsp:root>
diff --git a/zxingorg/web/badurl.jspx b/zxingorg/web/badurl.jspx
index 10e8b5c..30b6f5e 100644
--- a/zxingorg/web/badurl.jspx
+++ b/zxingorg/web/badurl.jspx
@@ -14,6 +14,7 @@
  See the License for the specific language governing permissions and
  limitations under the License.
  -->
+<!-- Author: Sean Owen (srowen@google.com) -->
 <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1">
   <jsp:output
           omit-xml-declaration="false" doctype-root-element="html"
@@ -23,27 +24,14 @@
   <jsp:scriptlet>response.setHeader("Cache-Control", "public");</jsp:scriptlet>
   <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
     <head>
-      <title>No Barcode Found</title>
+      <title>Bad URL</title>
     </head>
     <body>
-      <p>
-        <b>Bad URL</b>
-      </p>
+      <h1><img src="zxing-icon.png" height="32" width="32" alt=""/> Bad URL</h1>
       <p>You didn't specify a URL, or the URL was not valid, or did not return an image. Go "Back" in your browser and
         try again.
       </p>
-      <script type="text/javascript">
-        var gaJsHost = (("https:" == document.location.protocol) ?
-        "https://ssl." : "http://www.");
-        document.write(unescape("%3Cscript src='" + gaJsHost +
-        "google-analytics.com/ga.js'
-        type='text/javascript'%3E%3C/script%3E"));
-      </script>
-      <script type="text/javascript">
-        var pageTracker = _gat._getTracker("UA-788492-5");
-        pageTracker._initData();
-        pageTracker._trackPageview();
-      </script>
+      <jsp:include page="analytics.jspx"/>      
     </body>
   </html>
 </jsp:root>
diff --git a/zxingorg/web/decode.jspx b/zxingorg/web/decode.jspx
index 4a4d4df..cba8596 100644
--- a/zxingorg/web/decode.jspx
+++ b/zxingorg/web/decode.jspx
@@ -14,6 +14,7 @@
  See the License for the specific language governing permissions and
  limitations under the License.
  -->
+<!-- Author: Sean Owen (srowen@google.com) -->
 <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1">
   <jsp:output
           omit-xml-declaration="false" doctype-root-element="html"
@@ -26,47 +27,29 @@
       <title>ZXing Decoder Online</title>
     </head>
     <body>
-
-      <h1>ZXing Decoder Online</h1>
-
+      <h1><img src="zxing-icon.png" height="32" width="32" alt=""/> ZXing Decoder Online</h1>
       <p><b>Under Construction</b>: This is a simple page that will let you decode a 1D or 2D barcode found
         in an image online. Enter a URL below.
       </p>
-
       <form action="decode" method="get">
         <p>
-          <input type="text" size="50" name="u"/>
-          <input type="submit"/>
+          <input type="text" size="50" name="u"/>&amp;nbsp;<input type="submit"/>
+          <input type="hidden" name="full" value="true"/>
         </p>
       </form>
-
       <p>Or try uploading a file:</p>
-
       <form action="decode" method="post" enctype="multipart/form-data">
         <p>
-          <input type="file" size="50" name="f"/>
-          <input type="submit"/>
+          <input type="file" size="50" name="f"/>&amp;nbsp;<input type="submit"/>
+          <input type="hidden" name="full" value="true"/>
         </p>
       </form>
-
       <p>See the
         <a href="http://code.google.com/p/zxing">project page</a>
         for details.
       </p>
-
-      <script type="text/javascript">
-        var gaJsHost = (("https:" == document.location.protocol) ?
-        "https://ssl." : "http://www.");
-        document.write(unescape("%3Cscript src='" + gaJsHost +
-        "google-analytics.com/ga.js'
-        type='text/javascript'%3E%3C/script%3E"));
-      </script>
-      <script type="text/javascript">
-        var pageTracker = _gat._getTracker("UA-788492-5");
-        pageTracker._initData();
-        pageTracker._trackPageview();
-      </script>
-
+      <p>Copyright (C) 2008 Google Inc.</p>
+      <jsp:include page="analytics.jspx"/>
     </body>
   </html>
 </jsp:root>
diff --git a/zxingorg/web/decoderesult.jspx b/zxingorg/web/decoderesult.jspx
new file mode 100644
index 0000000..152d375
--- /dev/null
+++ b/zxingorg/web/decoderesult.jspx
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2008 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<!-- Author: Sean Owen (srowen@google.com) -->
+<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1">
+  <jsp:output
+          omit-xml-declaration="false" doctype-root-element="html"
+          doctype-public="-//WAPFORUM//DTD XHTML Mobile 1.1//EN"
+          doctype-system="http://www.openmobilealliance.org/tech/DTD/xhtml-mobile11.dtd"/>
+  <jsp:directive.page contentType="application/xhtml+xml" session="false"/>
+  <jsp:scriptlet>response.setHeader("Cache-Control", "no-cache");</jsp:scriptlet>
+  <jsp:useBean id="result" scope="request" type="com.google.zxing.Result"/>
+  <jsp:useBean id="parsedReaderResult" scope="request" type="com.google.zxing.client.result.ParsedReaderResult"/>
+  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+    <head>
+      <title>Decode Succeeded</title>
+      <style type="text/css">
+        td { vertical-align: top; padding: 0.1in; background-color: #EEEEEE; font-family: monospace; }
+      </style>
+    </head>
+    <body>
+      <h1><img src="zxing-icon.png" height="32" width="32" alt=""/> Decode Succeeded</h1>
+      <table>
+        <tr>
+          <td>Raw text</td>
+          <td>${result.text}</td>
+        </tr>
+        <tr>
+          <td>Barcode format</td>
+          <td>${result.barcodeFormat}</td>
+        </tr>
+        <tr>
+          <td>Parsed Result Type</td>
+          <td>${parsedReaderResult.type}</td>
+        </tr>
+        <tr>
+          <td>Parsed Result</td>
+          <td>${parsedReaderResult.displayResult}</td>
+        </tr>
+      </table>
+      <p>Copyright (C) 2008 Google Inc.</p>
+      <jsp:include page="analytics.jspx"/>      
+    </body>
+  </html>
+</jsp:root>
diff --git a/zxingorg/web/index.jspx b/zxingorg/web/index.jspx
index 9d670fd..0e8a68b 100644
--- a/zxingorg/web/index.jspx
+++ b/zxingorg/web/index.jspx
@@ -14,6 +14,7 @@
  See the License for the specific language governing permissions and
  limitations under the License.
  -->
+<!-- Author: Sean Owen (srowen@google.com) -->
 <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1">
   <jsp:output
           omit-xml-declaration="false" doctype-root-element="html"
@@ -26,9 +27,7 @@
       <title>Download ZXing Reader</title>
     </head>
     <body>
-      <p>
-        <strong>Welcome to zxing!</strong>
-      </p>
+      <h1><img src="zxing-icon.png" height="32" width="32" alt=""/> Download ZXing Reader</h1>
       <p>
         <a href="BarcodeReader.jad">Download</a>
         the ZXing Barcode Reader.
@@ -47,18 +46,8 @@
         <a href="BarcodeReader.apk">Download</a>
         the Android client.
       </p>
-      <script type="text/javascript">
-        var gaJsHost = (("https:" == document.location.protocol) ?
-        "https://ssl." : "http://www.");
-        document.write(unescape("%3Cscript src='" + gaJsHost +
-        "google-analytics.com/ga.js'
-        type='text/javascript'%3E%3C/script%3E"));
-      </script>
-      <script type="text/javascript">
-        var pageTracker = _gat._getTracker("UA-788492-5");
-        pageTracker._initData();
-        pageTracker._trackPageview();
-      </script>
+      <p>Copyright (C) 2008 Google Inc.</p>
+      <jsp:include page="analytics.jspx"/>      
     </body>
   </html>
 </jsp:root>
diff --git a/zxingorg/web/notfound.jspx b/zxingorg/web/notfound.jspx
index cdec207..54b6193 100644
--- a/zxingorg/web/notfound.jspx
+++ b/zxingorg/web/notfound.jspx
@@ -14,6 +14,7 @@
  See the License for the specific language governing permissions and
  limitations under the License.
  -->
+<!-- Author: Sean Owen (srowen@google.com) -->
 <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.1">
   <jsp:output
           omit-xml-declaration="false" doctype-root-element="html"
@@ -26,24 +27,11 @@
       <title>No Barcode Found</title>
     </head>
     <body>
-      <p>
-        <b>No Barcode Found</b>
-      </p>
+      <h1><img src="zxing-icon.png" height="32" width="32" alt=""/> No Barcode Found</h1>
       <p>No barcode was found in this image. Either it did not contain a barcode, or did not contain one in a
         supported format, or the software was simply unable to find it. Go "Back" in your browser and try another image.
       </p>
-      <script type="text/javascript">
-        var gaJsHost = (("https:" == document.location.protocol) ?
-        "https://ssl." : "http://www.");
-        document.write(unescape("%3Cscript src='" + gaJsHost +
-        "google-analytics.com/ga.js'
-        type='text/javascript'%3E%3C/script%3E"));
-      </script>
-      <script type="text/javascript">
-        var pageTracker = _gat._getTracker("UA-788492-5");
-        pageTracker._initData();
-        pageTracker._trackPageview();
-      </script>
+      <jsp:include page="analytics.jspx"/>      
     </body>
   </html>
 </jsp:root>
diff --git a/zxingorg/web/zxing-icon.png b/zxingorg/web/zxing-icon.png
new file mode 100644
index 0000000..7be1aa4
--- /dev/null
+++ b/zxingorg/web/zxing-icon.png
Binary files differ