Merging startup optimization into trunk from branches/opt_imgs_and_startup@538.  Had to hand-merge several things.

Patch by: jgw
          me
Review by: me


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@539 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/GWTCompiler.java b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
index 2d7c52c..fa7ab4b 100644
--- a/dev/core/src/com/google/gwt/dev/GWTCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/GWTCompiler.java
@@ -477,14 +477,11 @@
 
   private String getHtmlSuffix() {
     StringBuffer sb = new StringBuffer();
+    String moduleFunction = module.getName().replace('.', '_');
 
     // Generate the call to tell the bootstrap code that we're ready to go.
     sb.append("\n");
-    sb.append("if ($wnd.__gwt_tryGetModuleControlBlock) {\n");
-    sb.append("  var $mcb = $wnd.__gwt_tryGetModuleControlBlock(location.search);\n");
-    sb.append("  if ($mcb) $mcb.compilationLoaded(window);\n");
-    sb.append("}\n");
-
+    sb.append("parent." + moduleFunction + ".onScriptLoad(window);\n");
     sb.append("--></script></body></html>\n");
 
     String s = sb.toString();
@@ -783,8 +780,8 @@
 
   private void writeSelectionScript(TreeLogger logger,
       SelectionScriptGenerator selGen) {
-    String html = selGen.generateSelectionScript();
-    String fn = module.getName() + ".nocache.html";
+    String html = selGen.generateSelectionScript(obfuscate);
+    String fn = module.getName() + ".nocache.js";
     File selectionFile = new File(outDir, fn);
     Util.writeStringAsFile(selectionFile, html);
     String msg = "Compilation selection script written to "
diff --git a/dev/core/src/com/google/gwt/dev/cfg/DefaultPropertyProvider.java b/dev/core/src/com/google/gwt/dev/cfg/DefaultPropertyProvider.java
index d3d589e..c94eb07 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/DefaultPropertyProvider.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/DefaultPropertyProvider.java
@@ -37,10 +37,10 @@
    * were to include the selector script in the host page itself rather than in
    * an iframe.
    */
-  public DefaultPropertyProvider(Property property) {
-    super(property);
+  public DefaultPropertyProvider(ModuleDef module, Property property) {
+    super(module, property);
     String src = "function () {";
-    src += "return parent.__gwt_getMetaProperty(\"";
+    src += "return _gwt_getMetaProperty(\"";
     src += property.getName();
     src += "\"); }";
     setBody(parseFunction(src));
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
index 9187655..2ccbd63 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -224,6 +224,10 @@
     return (String[]) entryPointTypeNames.toArray(new String[n]);
   }
 
+  public synchronized String getFunctionName() {
+    return name.replace('.', '_');
+  }
+
   public synchronized String getName() {
     return name;
   }
@@ -379,7 +383,7 @@
           if (prop.getProvider() == null) {
             // Create a default provider.
             //
-            prop.setProvider(new DefaultPropertyProvider(prop));
+            prop.setProvider(new DefaultPropertyProvider(this, prop));
           }
         } else {
           prop.setActiveValue(knownValues[0]);
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
index a28b172..6a6ca54 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
@@ -49,12 +49,12 @@
 
     protected final String __define_property_2_values = null;
 
+    protected final String __entry_point_1_class = null;
+
     protected final String __extend_property_1_name = null;
 
     protected final String __extend_property_2_values = null;
 
-    protected final String __entry_point_1_class = null;
-
     protected final String __generate_with_1_class = null;
 
     protected final String __inherits_1_name = null;
@@ -145,7 +145,7 @@
     }
 
     protected Schema __property_provider_begin(Property property) {
-      property.setProvider(new PropertyProvider(property));
+      property.setProvider(new PropertyProvider(moduleDef, property));
       return fChild = new PropertyProviderBodySchema();
     }
 
@@ -211,12 +211,12 @@
     protected void __script_end(String src) throws UnableToCompleteException {
       ScriptReadyBodySchema childSchema = (ScriptReadyBodySchema) fChild;
       String js = childSchema.getScriptReadyBlock();
-      if (js == null) {
+      if (js != null) {
         // This is a problem.
         //
         logger.log(
-            TreeLogger.ERROR,
-            "Injected scripts require an associated JavaScript block that indicates when the corresponding script is fully loaded and ready for use",
+            TreeLogger.WARN,
+            "Injected scripts no longer require an associated JavaScript block.",
             null);
         throw new UnableToCompleteException();
       }
@@ -773,4 +773,4 @@
   }
 
 }
-//CHECKSTYLE_NAMING_ON
\ No newline at end of file
+// CHECKSTYLE_NAMING_ON
diff --git a/dev/core/src/com/google/gwt/dev/cfg/PropertyProvider.java b/dev/core/src/com/google/gwt/dev/cfg/PropertyProvider.java
index 3657ac2..13c44d6 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/PropertyProvider.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/PropertyProvider.java
@@ -24,9 +24,11 @@
 
   private JsBlock body;
 
+  private final ModuleDef module;
   private final Property property;
 
-  public PropertyProvider(Property property) {
+  public PropertyProvider(ModuleDef module, Property property) {
+    this.module = module;
     this.property = property;
   }
 
@@ -34,6 +36,10 @@
     return body;
   }
 
+  public ModuleDef getModule() {
+    return module;
+  }
+
   public Property getProperty() {
     return property;
   }
diff --git a/dev/core/src/com/google/gwt/dev/js/JsSymbolResolver.java b/dev/core/src/com/google/gwt/dev/js/JsSymbolResolver.java
index e5e02c6..6921de1 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsSymbolResolver.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsSymbolResolver.java
@@ -69,6 +69,10 @@
       x.resolve(name);
     }
 
+    public void endVisit(JsProgram x) {
+      popScope();
+    }
+
     public boolean visit(JsCatch x) {
       pushScope(x.getScope());
       return true;
@@ -79,6 +83,11 @@
       return true;
     }
 
+    public boolean visit(JsProgram x) {
+      pushScope(x.getScope());
+      return true;
+    }
+
     private JsScope getScope() {
       return (JsScope) scopeStack.peek();
     }
diff --git a/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java b/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java
index 1dc3f54..f73f95f 100644
--- a/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java
+++ b/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java
@@ -72,21 +72,14 @@
     }
   }
 
-  /**
-   * When the GWT bootstrap JavaScript starts in hosted mode, it appends this
-   * query param to the url for the nocache file so that this servlet can
-   * generate one on-the-fly.
-   */
-  private static final String HOSTED_MODE_QUERY_PARAM = "h";
-
   private final Map loadedModulesByName = new HashMap();
 
   private final Map loadedServletsByClassName = new HashMap();
 
-  private final Map modulesByServletPath = new HashMap();
-
   private final Map mimeTypes = new HashMap();
 
+  private final Map modulesByServletPath = new HashMap();
+
   private int nextRequestId;
 
   private File outDir;
@@ -259,6 +252,37 @@
     }
   }
 
+  /**
+   * Handle auto-generated resources.
+   * 
+   * @return <code>true</code> if a resource was generated
+   */
+  private boolean autoGenerateResources(HttpServletRequest request,
+      HttpServletResponse response, TreeLogger logger, String partialPath,
+      String moduleName) throws IOException {
+
+    // If the request is of the form ".../moduleName.nocache.js", then
+    // we generate the selection script for them.
+    if (partialPath.equals(moduleName + ".nocache.js")) {
+      // If the '?compiled' request property is specified, don't auto-generate.
+      if (request.getParameter("compiled") == null) {
+        // Generate the .js file.
+        try {
+          String js = genSelectionScript(logger, moduleName);
+          response.setStatus(HttpServletResponse.SC_OK);
+          response.setContentType("text/javascript");
+          response.getWriter().println(js);
+          return true;
+        } catch (UnableToCompleteException e) {
+          // Quietly continue, since this could actually be a request for a
+          // static file that happens to have an unfortunately confusing name.
+        }
+      }
+    }
+
+    return false;
+  }
+
   private void doGetModule(HttpServletRequest request,
       HttpServletResponse response, TreeLogger logger, RequestParts parts)
       throws IOException {
@@ -325,23 +349,10 @@
         + partialPath + "' in module '" + moduleName + "' ";
     logger = logger.branch(TreeLogger.TRACE, msg, null);
 
-    // If the request is of the form ".../moduleName.nocache.html[?...]", then
-    // we generate the selection script for them.
-    if (partialPath.equals(moduleName + ".nocache.html")) {
-      // Only generate a selection script for a hosted-mode client.
-      // Otherwise, fall through.
-      if (request.getParameterMap().containsKey(HOSTED_MODE_QUERY_PARAM)) {
-        // Generate the .nocache.html file.
-        try {
-          String html = genSelectionPage(logger, moduleName);
-          response.setContentType("text/html");
-          response.getWriter().println(html);
-          return;
-        } catch (UnableToCompleteException e) {
-          // Quietly continue, since this could actually be a request for a
-          // static file that happens to have an unfortunately confusing name.
-        }
-      }
+    // Handle auto-generation of resources.
+    if (autoGenerateResources(request, response, logger, partialPath,
+        moduleName)) {
+      return;
     }
 
     URL foundResource;
@@ -392,9 +403,13 @@
       logger.log(TreeLogger.TRACE, msg, null);
     }
 
-    // Maybe serve it up. Don't let the client cache anything because
-    // this servlet is for development (so files change a lot), and we do at
-    // least honor "If-Modified-Since".
+    // Maybe serve it up. Don't let the client cache anything other than
+    // xxx.cache.yyy files because this servlet is for development (so user
+    // files are assumed to change a lot), although we do honor
+    // "If-Modified-Since".
+
+    boolean infinitelyCacheable = isInfinitelyCacheable(path);
+
     InputStream is = null;
     try {
       // Check for up-to-datedness.
@@ -402,11 +417,14 @@
       long lastModified = conn.getLastModified();
       if (isNotModified(request, lastModified)) {
         response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+        if (infinitelyCacheable) {
+          response.setHeader(HttpHeaders.CACHE_CONTROL,
+              HttpHeaders.CACHE_CONTROL_MAXAGE_FOREVER);
+        }
         return;
       }
 
       // Set up headers to really send it.
-      //
       response.setStatus(HttpServletResponse.SC_OK);
       long now = new Date().getTime();
       response.setHeader(HttpHeaders.DATE,
@@ -414,13 +432,26 @@
       response.setContentType(mimeType);
       String lastModifiedStr = HttpHeaders.toInternetDateFormat(lastModified);
       response.setHeader(HttpHeaders.LAST_MODIFIED, lastModifiedStr);
-      final long jan2nd1980 = 315637200000L;
-      String inThePastStr = HttpHeaders.toInternetDateFormat(jan2nd1980);
-      response.setHeader(HttpHeaders.EXPIRES, inThePastStr);
 
-      // Send the bytes. To keep it simple, we don't compute the length.
-      // This prevents keep-alive.
-      //
+      // Expiration header. Either immediately stale (requiring an
+      // "If-Modified-Since") or infinitely cacheable (not requiring even a
+      // freshness check).
+      String maxAgeStr;
+      if (infinitelyCacheable) {
+        maxAgeStr = HttpHeaders.CACHE_CONTROL_MAXAGE_FOREVER;
+      } else {
+        maxAgeStr = HttpHeaders.CACHE_CONTROL_MAXAGE_EXPIRED;
+      }
+      response.setHeader(HttpHeaders.CACHE_CONTROL, maxAgeStr);
+
+      // Content length.
+      int contentLength = conn.getContentLength();
+      if (contentLength >= 0) {
+        response.setHeader(HttpHeaders.CONTENT_LENGTH,
+            Integer.toString(contentLength));
+      }
+
+      // Send the bytes.
       is = foundResource.openStream();
       streamOut(is, response.getOutputStream(), 1024 * 8);
     } finally {
@@ -436,19 +467,19 @@
   }
 
   /**
-   * Generates a nocache file on the fly. Note that the nocache file that is
+   * Generates a module.js file on the fly. Note that the nocache file that is
    * generated that can only be used for hosted mode. It cannot produce a web
    * mode version, since this servlet doesn't know strong names, since by
    * definition of "hosted mode" JavaScript hasn't been compiled at this point.
    */
-  private String genSelectionPage(TreeLogger logger, String moduleName)
+  private String genSelectionScript(TreeLogger logger, String moduleName)
       throws UnableToCompleteException {
-    String msg = "Generating a selector page for module " + moduleName;
+    String msg = "Generating a selection script for module " + moduleName;
     logger.log(TreeLogger.TRACE, msg, null);
 
     ModuleDef moduleDef = getModuleDef(logger, moduleName);
     SelectionScriptGenerator gen = new SelectionScriptGenerator(moduleDef);
-    return gen.generateSelectionScript();
+    return gen.generateSelectionScript(false);
   }
 
   private synchronized TreeLogger getLogger() {
@@ -668,6 +699,20 @@
   }
 
   /**
+   * A file is infinitely cacheable if it ends with ".cache.xxx", where "xxx"
+   * can be any extension.
+   */
+  private boolean isInfinitelyCacheable(String path) {
+    int lastDot = path.lastIndexOf('.');
+    if (lastDot >= 0) {
+      if (path.substring(0, lastDot).endsWith(".cache")) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
    * Checks to see whether or not a client's file is out of date relative to the
    * original.
    */
diff --git a/dev/core/src/com/google/gwt/dev/shell/ModuleSpacePropertyOracle.java b/dev/core/src/com/google/gwt/dev/shell/ModuleSpacePropertyOracle.java
index 702334b..fde7a85 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ModuleSpacePropertyOracle.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ModuleSpacePropertyOracle.java
@@ -20,7 +20,6 @@
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.dev.cfg.Properties;
 import com.google.gwt.dev.cfg.Property;
-import com.google.gwt.dev.util.Empty;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -31,12 +30,12 @@
  */
 public class ModuleSpacePropertyOracle implements PropertyOracle {
 
+  private final Map prevAnswers = new HashMap();
+
   private final Properties props;
 
   private final ModuleSpace space;
 
-  private final Map prevAnswers = new HashMap();
-
   public ModuleSpacePropertyOracle(Properties props, ModuleSpace space) {
     this.space = space;
     this.props = props;
@@ -100,12 +99,11 @@
     if (value == null) {
       // Invokes the script function.
       //
-      String scriptFnName = makeScriptFnName(prop);
       try {
         // Invoke the property provider function in JavaScript.
         //
-        value = space.invokeNativeString(scriptFnName, null, Empty.CLASSES,
-            Empty.OBJECTS);
+        value = space.invokeNativeString("__gwt_getProperty", null,
+            new Class[] {String.class}, new Object[] {prop.getName()});
       } catch (RuntimeException e) {
         // Treat as an unknown value.
         //
@@ -119,12 +117,4 @@
     // value may be null if the provider returned an unknown property value.
     return value;
   }
-
-  /**
-   * Coordinate this property provider function name with the one generated in
-   * {@link com.google.gwt.dev.util.SelectionScriptGenerator#genPropProviders(PrintWriter)}.
-   */
-  private String makeScriptFnName(Property prop) {
-    return "prop$" + prop.getName();
-  }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/HttpHeaders.java b/dev/core/src/com/google/gwt/dev/util/HttpHeaders.java
index 6d48d06..2d5da0a 100644
--- a/dev/core/src/com/google/gwt/dev/util/HttpHeaders.java
+++ b/dev/core/src/com/google/gwt/dev/util/HttpHeaders.java
@@ -27,40 +27,45 @@
  */
 public final class HttpHeaders {
 
-  public static final String IF_MODIFIED_SINCE = "If-Modified-Since";
-
-  public static final String CONTENT_TYPE = "Content-Type";
-  public static final String CONTENT_TYPE_APPLICATION_XJAVASCRIPT_UTF8 = "application/x-javascript; charset=utf-8";
-  public static final String CONTENT_TYPE_TEXT_HTML = "text/html";
-  public static final String CONTENT_TYPE_TEXT_HTML_UTF8 = "text/html; charset=utf-8";
-  public static final String CONTENT_TYPE_TEXT_PLAIN = "text/plain";
-  public static final String CONTENT_TYPE_TEXT_CSS = "text/css";
-
-  public static final String CONTENT_ENCODING = "Content-Encoding";
-  public static final String CONTENT_ENCODING_GZIP = "gzip";
-
   public static final long MS_SEC = 1000;
   public static final long MS_MIN = MS_SEC * 60;
   public static final long MS_HR = MS_MIN * 60;
   public static final long MS_DAY = MS_HR * 24;
 
+  public static final long SEC_MIN = 60;
+  public static final long SEC_HR = SEC_MIN * 60;
+  public static final long SEC_DAY = SEC_HR * 24;
+  public static final long SEC_YR = SEC_DAY * 365;
+
   public static final String CACHE_CONTROL = "Cache-Control";
+  public static final String CACHE_CONTROL_MAXAGE_EXPIRED = "max-age=0";
+
+  /*
+   * "Forever" = 1 year according to
+   * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21
+   */
+  public static final String CACHE_CONTROL_MAXAGE_FOREVER = "max-age=" + SEC_YR;
+  public static final String CACHE_CONTROL_MUST_REVALIDATE = "must-revalidate";
   public static final String CACHE_CONTROL_NO_CACHE = "no-cache";
   public static final String CACHE_CONTROL_PRIVATE = "private";
-  public static final String CACHE_CONTROL_MUST_REVALIDATE = "must-revalidate";
-  public static final String CACHE_FOREVER = "max-age="
-      + String.valueOf(90 * MS_DAY);
-  public static final String CACHE_MINUTE = "max-age=" + String.valueOf(MS_MIN);
+  public static final String CACHE_CONTROL_PUBLIC = "public";
 
-  public static final String LAST_MODIFIED = "Last-Modified";
-
-  public static final String ETAG = "ETag";
-
-  public static final String IF_NONE_MATCH = "If-None-Match";
+  public static final String CONTENT_ENCODING = "Content-Encoding";
+  public static final String CONTENT_ENCODING_GZIP = "gzip";
+  public static final String CONTENT_LENGTH = "Content-Length";
+  public static final String CONTENT_TYPE = "Content-Type";
+  public static final String CONTENT_TYPE_APPLICATION_XJAVASCRIPT_UTF8 = "application/x-javascript; charset=utf-8";
+  public static final String CONTENT_TYPE_TEXT_CSS = "text/css";
+  public static final String CONTENT_TYPE_TEXT_HTML = "text/html";
+  public static final String CONTENT_TYPE_TEXT_HTML_UTF8 = "text/html; charset=utf-8";
+  public static final String CONTENT_TYPE_TEXT_PLAIN = "text/plain";
 
   public static final String DATE = "Date";
-
+  public static final String ETAG = "ETag";
   public static final String EXPIRES = "Expires";
+  public static final String IF_MODIFIED_SINCE = "If-Modified-Since";
+  public static final String IF_NONE_MATCH = "If-None-Match";
+  public static final String LAST_MODIFIED = "Last-Modified";
 
   /**
    * The Internet date format for HTTP.
diff --git a/dev/core/src/com/google/gwt/dev/util/SelectionScriptGenerator.java b/dev/core/src/com/google/gwt/dev/util/SelectionScriptGenerator.java
index e293d13..aa3709a 100644
--- a/dev/core/src/com/google/gwt/dev/util/SelectionScriptGenerator.java
+++ b/dev/core/src/com/google/gwt/dev/util/SelectionScriptGenerator.java
@@ -22,8 +22,21 @@
 import com.google.gwt.dev.cfg.Script;
 import com.google.gwt.dev.cfg.Scripts;
 import com.google.gwt.dev.cfg.Styles;
+import com.google.gwt.dev.js.JsObfuscateNamer;
+import com.google.gwt.dev.js.JsParser;
+import com.google.gwt.dev.js.JsParserException;
+import com.google.gwt.dev.js.JsSourceGenerationVisitor;
+import com.google.gwt.dev.js.JsSymbolResolver;
+import com.google.gwt.dev.js.JsVerboseNamer;
+import com.google.gwt.dev.js.ast.JsName;
+import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.js.ast.JsScope;
+import com.google.gwt.util.tools.Utility;
 
+import java.io.IOException;
 import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringReader;
 import java.io.StringWriter;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -42,6 +55,33 @@
  */
 public class SelectionScriptGenerator {
 
+  private static String cssInjector(String cssUrl) {
+    return "  if (!__gwt_stylesLoaded['" + cssUrl + "']) {\n"
+        + "    __gwt_stylesLoaded['" + cssUrl + "'] = true;\n"
+        + "    document.write('<link rel=\\\"stylesheet\\\" href=\\\"" + cssUrl
+        + "\\\">');\n" + "  }\n";
+  }
+
+  private static void replaceAll(StringBuffer buf, String search, String replace) {
+    int len = search.length();
+    for (int pos = buf.indexOf(search); pos >= 0; pos = buf.indexOf(search,
+        pos + 1)) {
+      buf.replace(pos, pos + len, replace);
+    }
+  }
+
+  private static String scriptInjector(String scriptUrl) {
+    return "  if (!__gwt_scriptsLoaded['" + scriptUrl + "']) {\n"
+        + "    __gwt_scriptsLoaded['" + scriptUrl + "'] = true;\n"
+        + "    document.write('<script language=\\\"javascript\\\" src=\\\""
+        + scriptUrl + "\\\"></script>');\n" + "  }\n";
+  }
+
+  private final String moduleFunction;
+  private final String moduleName;
+  private final Properties moduleProps;
+  private final Property[] orderedProps;
+
   /**
    * Maps compilation strong name onto a <code>Set</code> of
    * <code>String[]</code>. We use a <code>TreeMap</code> to produce the
@@ -49,12 +89,6 @@
    */
   private final Map propertyValuesSetByStrongName = new TreeMap();
 
-  private final Property[] orderedProps;
-
-  private final Properties moduleProps;
-
-  private final String moduleName;
-
   private final Scripts scripts;
 
   private final Styles styles;
@@ -68,6 +102,7 @@
    */
   public SelectionScriptGenerator(ModuleDef moduleDef) {
     this.moduleName = moduleDef.getName();
+    this.moduleFunction = moduleDef.getFunctionName();
     this.scripts = moduleDef.getScripts();
     this.styles = moduleDef.getStyles();
     this.moduleProps = moduleDef.getProperties();
@@ -86,6 +121,7 @@
    */
   public SelectionScriptGenerator(ModuleDef moduleDef, Property[] props) {
     this.moduleName = moduleDef.getName();
+    this.moduleFunction = moduleName.replace('.', '_');
     this.scripts = moduleDef.getScripts();
     this.styles = moduleDef.getStyles();
     this.moduleProps = moduleDef.getProperties();
@@ -95,40 +131,52 @@
   /**
    * Generates a selection script based on the current settings.
    * 
-   * @return an html document whose contents are the definition of a
-   *         module.nocache.html file
+   * @return an JavaScript whose contents are the definition of a module.js file
    */
-  public String generateSelectionScript() {
-    StringWriter src = new StringWriter();
-    PrintWriter pw = new PrintWriter(src, true);
+  public String generateSelectionScript(boolean obfuscate) {
+    try {
+      String rawSource;
+      {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw, true);
 
-    pw.println("<html>");
+        String template = Utility.getFileFromClassPath("com/google/gwt/dev/util/SelectionScriptTemplate.js");
+        genScript(pw, template);
 
-    // Emit the head and script.
-    //
-    pw.println("<head><script>");
-    String onloadExpr = genScript(pw);
-    pw.println("</script></head>");
+        pw.close();
+        rawSource = sw.toString();
+      }
 
-    // Emit the body.
-    //
-    pw.print("<body onload='");
-    pw.print(onloadExpr);
-    pw.println("'>");
+      {
+        JsParser parser = new JsParser();
+        Reader r = new StringReader(rawSource);
+        JsProgram jsProgram = new JsProgram();
+        JsScope topScope = jsProgram.getScope();
+        JsName funcName = topScope.declareName(moduleFunction);
+        funcName.setObfuscatable(false);
 
-    // This body text won't be seen unless you open the html alone.
-    pw.print("<font face='arial' size='-1'>");
-    pw.print("This script is part of module</font> <code>");
-    pw.print(moduleName);
-    pw.println("</code>");
+        parser.parseInto(topScope, jsProgram.getGlobalBlock(), r, 1);
+        JsSymbolResolver.exec(jsProgram);
+        if (obfuscate) {
+          JsObfuscateNamer.exec(jsProgram);
+        } else {
+          JsVerboseNamer.exec(jsProgram);
+        }
 
-    pw.println("</body>");
-
-    pw.println("</html>");
-
-    pw.close();
-    String html = src.toString();
-    return html;
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw, true);
+        TextOutputOnPrintWriter out = new TextOutputOnPrintWriter(pw, obfuscate);
+        JsSourceGenerationVisitor v = new JsSourceGenerationVisitor(out);
+        jsProgram.traverse(v);
+        return sw.toString();
+      }
+    } catch (IOException e) {
+      throw new RuntimeException("Error processing selection script template.",
+          e);
+    } catch (JsParserException e) {
+      throw new RuntimeException("Error processing selection script template.",
+          e);
+    }
   }
 
   /**
@@ -149,22 +197,6 @@
     valuesSet.add(values.clone());
   }
 
-  private void genAnswerFunction(PrintWriter pw) {
-    pw.println("function O(a,v) {");
-    pw.println("  var answer = O.answers;");
-    pw.println("  var i = -1;");
-    pw.println("  var n = a.length - 1;");
-    pw.println("  while (++i < n) {");
-    pw.println("    if (!(a[i] in answer)) {");
-    pw.println("      answer[a[i]] = [];");
-    pw.println("    }");
-    pw.println("    answer = answer[a[i]];");
-    pw.println("  }");
-    pw.println("  answer[a[n]] = v;");
-    pw.println("}");
-    pw.println("O.answers = [];");
-  }
-
   private void genAnswers(PrintWriter pw) {
     for (Iterator iter = propertyValuesSetByStrongName.entrySet().iterator(); iter.hasNext();) {
       Map.Entry entry = (Entry) iter.next();
@@ -176,7 +208,7 @@
       for (Iterator iterator = propValuesSet.iterator(); iterator.hasNext();) {
         String[] propValues = (String[]) iterator.next();
 
-        pw.print("    O([");
+        pw.print("      O([");
         for (int i = 0; i < orderedProps.length; i++) {
           if (i > 0) {
             pw.print(",");
@@ -191,123 +223,22 @@
     }
   }
 
-  /**
-   * Generates a function that injects calls to a shared file-injection
-   * functions.
-   * 
-   * @param pw generate source onto this writer
-   */
-  private void genInjectExternalFiles(PrintWriter pw) {
-    pw.println();
-    pw.println("function injectExternalFiles() {");
-    pw.println("  var mcb = $wnd.__gwt_tryGetModuleControlBlock(location.search);");
-    pw.println("  if (!mcb) return;");
-    pw.println("  var base = mcb.getBaseURL();");
-
-    // Styles come first to give them a little more time to load.
-    pw.println("  mcb.addStyles([");
-    boolean needComma = false;
-    for (Iterator iter = styles.iterator(); iter.hasNext();) {
-      String src = (String) iter.next();
-      if (needComma) {
-        pw.println(",");
-      }
-      needComma = true;
-
-      pw.print("    ");
-      if (isRelativeURL(src)) {
-        pw.print("base+");
-      }
-      pw.print("'");
-      pw.print(src);
-      pw.print("'");
-    }
-    pw.println();
-    pw.println("    ]);");
-
-    // Scripts
-    pw.println("  mcb.addScripts([");
-    needComma = false;
-    for (Iterator iter = scripts.iterator(); iter.hasNext();) {
-      Script script = (Script) iter.next();
-      if (needComma) {
-        pw.println(",");
-      }
-      needComma = true;
-
-      // Emit the src followed by the module-ready function.
-      // Note that the module-ready function is a string because it gets
-      // eval'ed in the context of the host html window. This is absolutely
-      // required because otherwise in web mode (IE) you get an
-      // "cannot execute code from a freed script" error.
-      String src = script.getSrc();
-      pw.print("    ");
-      if (isRelativeURL(src)) {
-        pw.print("base+");
-      }
-      pw.print("'");
-      pw.print(src);
-      pw.print("', \"");
-      String readyFnJs = Jsni.generateEscapedJavaScript(script.getJsReadyFunction());
-      pw.print(readyFnJs);
-      pw.print("\"");
-    }
-    pw.println();
-    pw.println("    ]);");
-
-    pw.println("}");
-  }
-
-  private void genOnLoad(PrintWriter pw) {
-    // Emit the onload() function.
-    pw.println();
-    pw.println("function onLoad() {");
-
-    // Early out (or fall through below) if the page is loaded out of context.
-    pw.println("  if (!$wnd.__gwt_isHosted) return;");
-
-    // Maybe inject scripts.
-    if (hasExternalFiles()) {
-      pw.println("  injectExternalFiles();");
-    }
-
-    // If we're in web mode, run the compilation selector logic.
-    // The compilation will call mcb.compilationLoaded() itself.
-    pw.println("  if (!$wnd.__gwt_isHosted()) {");
-    pw.println("    selectScript();");
-    pw.println("  }");
-
-    // If we're in hosted mode, notify $wnd that we're ready to go.
-    // Requires that we get the module control block.
-    pw.println("  else {");
-    pw.println("    var mcb = $wnd.__gwt_tryGetModuleControlBlock(location.search);");
-    pw.println("    if (mcb) {");
-    pw.println("      $moduleName = mcb.getName();");
-    pw.println("      mcb.compilationLoaded(window);");
-    pw.println("    }");
-    pw.println("  }");
-    pw.println("}");
-  }
-
   private void genPropProviders(PrintWriter pw) {
-    pw.println();
-
     for (Iterator iter = moduleProps.iterator(); iter.hasNext();) {
       Property prop = (Property) iter.next();
       String activeValue = prop.getActiveValue();
       if (activeValue == null) {
         // Emit a provider function, defined by the user in module config.
-        pw.println();
         PropertyProvider provider = prop.getProvider();
         assert (provider != null) : "expecting a default property provider to have been set";
         String js = Jsni.generateJavaScript(provider.getBody());
-        pw.print("window[\"provider$" + prop.getName() + "\"] = function() ");
+        pw.print("providers['" + prop.getName() + "'] = function() ");
         pw.print(js);
         pw.println(";");
 
         // Emit a map of allowed property values as an object literal.
         pw.println();
-        pw.println("window[\"values$" + prop.getName() + "\"] = {");
+        pw.println("values['" + prop.getName() + "'] = {");
         String[] knownValues = prop.getKnownValues();
         for (int i = 0; i < knownValues.length; i++) {
           if (i > 0) {
@@ -326,9 +257,9 @@
         // Emit a wrapper that verifies that the value is valid.
         // It is this function that is called directly to get the propery.
         pw.println();
-        pw.println("window[\"prop$" + prop.getName() + "\"] = function() {");
-        pw.println("  var v = window[\"provider$" + prop.getName() + "\"]();");
-        pw.println("  var ok = window[\"values$" + prop.getName() + "\"];");
+        pw.println("props['" + prop.getName() + "'] = function() {");
+        pw.println("  var v = providers['" + prop.getName() + "']();");
+        pw.println("  var ok = values['" + prop.getName() + "'];");
         // Make sure this is an allowed value; if so, return.
         pw.println("  if (v in ok)");
         pw.println("    return v;");
@@ -336,20 +267,19 @@
         pw.println("  var a = new Array(" + knownValues.length + ");");
         pw.println("  for (var k in ok)");
         pw.println("    a[ok[k]] = k;");
-        pw.print("  $wnd.__gwt_onBadProperty(");
-        pw.print(literal(moduleName));
-        pw.print(", ");
+        pw.print("  " + moduleFunction + ".onBadProperty(");
         pw.print(literal(prop.getName()));
         pw.println(", a, v);");
         pw.println("  if (arguments.length > 0) throw null; else return null;");
         pw.println("};");
+        pw.println();
       }
     }
   }
 
   private void genPropValues(PrintWriter pw) {
-    pw.println("    var F;");
-    pw.print("    var I = [");
+    pw.println("      var F;");
+    pw.print("      var I = [");
     for (int i = 0; i < orderedProps.length; i++) {
       if (i > 0) {
         pw.print(", ");
@@ -365,7 +295,7 @@
         // When we call the provider, we supply a bogus argument to indicate
         // that it should throw an exception if the property is a bad value.
         // The absence of arguments (as in hosted mode) tells it to return null.
-        pw.print("(F=window[\"prop$" + prop.getName() + "\"],F(1))");
+        pw.print("(F=props['" + prop.getName() + "'],F(1))");
       } else {
         // This property was explicitly set at compile-time.
         //
@@ -380,87 +310,87 @@
    * a compilation.
    * 
    * @param pw
-   * @return an expression that should be called as the body's onload handler
    */
-  private String genScript(PrintWriter pw) {
-    // Emit $wnd and $doc for dynamic property providers.
-    pw.println("var $wnd = parent;");
-    pw.println("var $doc = $wnd.document;");
-    pw.println("var $moduleName = null;");
+  private void genScript(PrintWriter mainPw, String template) {
+    StringBuffer buf = new StringBuffer(template);
+    replaceAll(buf, "__MODULE_FUNC__", moduleFunction);
+    replaceAll(buf, "__MODULE_NAME__", moduleName);
 
-    // Emit property providers; these are used in both modes.
-    genPropProviders(pw);
-
-    // If the ordered props are specified, then we're generating for both modes.
+    // Remove hosted mode only stuff
     if (orderedProps != null) {
-      // Web mode or hosted mode.
-      if (orderedProps.length > 0) {
-        pw.println();
-        genAnswerFunction(pw);
-        pw.println();
-        genSrcSetFunction(pw, null);
-      } else {
-        // Rare case of no properties; happens if you inherit from Core alone.
-        assert (orderedProps.length == 0);
-        Set entrySet = propertyValuesSetByStrongName.entrySet();
-        assert (entrySet.size() == 1);
-        Map.Entry entry = (Entry) entrySet.iterator().next();
-        String strongName = (String) entry.getKey();
-        genSrcSetFunction(pw, strongName);
+      int startPos = buf.indexOf("// __SHELL_SERVLET_ONLY_BEGIN__");
+      int endPos = buf.indexOf("// __SHELL_SERVLET_ONLY_END__");
+      buf.delete(startPos, endPos);
+    }
+
+    // Add external dependencies
+    int startPos = buf.indexOf("// __MODULE_DEPS_END__");
+    for (Iterator iter = styles.iterator(); iter.hasNext();) {
+      String style = (String) iter.next();
+      String text = cssInjector(style);
+      buf.insert(startPos, text);
+      startPos += text.length();
+    }
+
+    for (Iterator iter = scripts.iterator(); iter.hasNext();) {
+      Script script = (Script) iter.next();
+      String text = scriptInjector(script.getSrc());
+      buf.insert(startPos, text);
+      startPos += text.length();
+    }
+
+    // Add property providers
+    {
+      StringWriter sw = new StringWriter();
+      PrintWriter pw = new PrintWriter(sw, true);
+      genPropProviders(pw);
+      pw.close();
+      String stuff = sw.toString();
+      startPos = buf.indexOf("// __PROPERTIES_END__");
+      buf.insert(startPos, stuff);
+    }
+
+    // Add permutations
+    {
+      StringWriter sw = new StringWriter();
+      PrintWriter pw = new PrintWriter(sw, true);
+
+      // If the ordered props are specified, then we're generating for both
+      // modes.
+      if (orderedProps != null) {
+        // Web mode or hosted mode.
+        if (orderedProps.length > 0) {
+          pw.println();
+          genPropValues(pw);
+          pw.println();
+          genAnswers(pw);
+          pw.println();
+          pw.print("      strongName = answers");
+          for (int i = 0; i < orderedProps.length; i++) {
+            pw.print("[I[" + i + "]]");
+          }
+        } else {
+          // Rare case of no properties; happens if you inherit from Core
+          // alone.
+          assert (orderedProps.length == 0);
+          Set entrySet = propertyValuesSetByStrongName.entrySet();
+          assert (entrySet.size() == 1);
+          Map.Entry entry = (Entry) entrySet.iterator().next();
+          String strongName = (String) entry.getKey();
+          // There is exactly one compilation, so it is unconditionally
+          // selected.
+          pw.print("    strongName = " + literal(strongName));
+        }
+        pw.println(";");
       }
-    } else {
-      // Hosted mode only, so there is no strong name selection (i.e. because
-      // there is no compiled JavaScript); do nothing
+
+      pw.close();
+      String stuff = sw.toString();
+      startPos = buf.indexOf("// __PERMUTATIONS_END__");
+      buf.insert(startPos, stuff);
     }
 
-    // Emit dynamic file injection logic; same logic is used in both modes.
-    if (hasExternalFiles()) {
-      genInjectExternalFiles(pw);
-    }
-
-    genOnLoad(pw);
-
-    return "onLoad()";
-  }
-
-  /**
-   * @param pw generate source onto this writer
-   * @param oneAndOnlyStrongName if <code>null</code>, use the normal logic;
-   *          otherwise, there are no client properties and thus there is
-   *          exactly one permutation, specified by this parameter
-   */
-  private void genSrcSetFunction(PrintWriter pw, String oneAndOnlyStrongName) {
-    pw.println();
-    pw.println("function selectScript() {");
-    if (oneAndOnlyStrongName == null) {
-      pw.println("  try {");
-      genPropValues(pw);
-      pw.println();
-      genAnswers(pw);
-      pw.println();
-      pw.print("    var strongName = O.answers");
-      for (int i = 0; i < orderedProps.length; i++) {
-        pw.print("[I[" + i + "]]");
-      }
-      pw.println(";");
-      pw.println("    var query = location.search;");
-      pw.println("    query = query.substring(0, query.indexOf('&'));");
-      pw.println("    var newUrl = strongName + '.cache.html' + query;");
-      pw.println("    location.replace(newUrl);");
-      pw.println("  } catch (e) {");
-      pw.println("    // intentionally silent on property failure");
-      pw.println("  }");
-    } else {
-      // There is exactly one compilation, so it is unconditionally selected.
-      //
-      String scriptToLoad = oneAndOnlyStrongName + ".cache.html";
-      pw.println("  location.replace('" + scriptToLoad + "');");
-    }
-    pw.println("}");
-  }
-
-  private boolean hasExternalFiles() {
-    return !scripts.isEmpty() || !styles.isEmpty();
+    mainPw.print(buf.toString());
   }
 
   /**
@@ -493,4 +423,5 @@
   private String literal(String lit) {
     return "\"" + lit + "\"";
   }
+
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate.js b/dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate.js
new file mode 100644
index 0000000..e10caba
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/SelectionScriptTemplate.js
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2006 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.
+ */
+
+function __MODULE_FUNC__() {
+  // ---------------- INTERNAL GLOBALS ----------------
+  
+  // Cache symbols locally for good obfuscation
+  var wnd = window;
+  var external = wnd.external;
+  
+  // These two variables gate calling gwtOnLoad; both must be true to start
+  var scriptsDone, loadDone;
+  
+  // A map of properties that were declared in meta tags
+  var __gwt_metaProps = {};
+  
+  // A map of module rebasings
+  var __gwt_base = {};
+  
+  // These variables contain deferred-binding properties, values, and
+  // providers.
+  //
+  var props = [];
+  var values = [];
+  var providers = [];
+  
+  // Property answers go here
+  var answers = [];
+
+  // ------------------ TRUE GLOBALS ------------------
+
+  // Maps to synchronize the loading of styles and scripts; resources are loaded
+  // only once, even when multiple modules depend on them.  This API must not
+  // change across GWT versions.
+  if (!wnd.__gwt_stylesLoaded) { wnd.__gwt_stylesLoaded = {}; }
+  if (!wnd.__gwt_scriptsLoaded) { wnd.__gwt_scriptsLoaded = {}; }
+
+  // --------------- INTERNAL FUNCTIONS ---------------
+
+  // The default module load error function; may be overwritten via meta props
+  //
+  function __gwt_onLoadError() {
+    alert('Failed to load module __MODULE_NAME__' +
+      '".\nPlease see the log in the development shell for details.');
+  }
+
+  // The default bad property error function; may be overwritten via meta props
+  //
+  function __gwt_onPropertyError(propName, allowedValues, badValue) {
+    var msg = 'While attempting to load module __MODULE_NAME__, property \"'
+      + propName;
+    if (badValue != null) {
+      msg += '\" was set to the unexpected value \"' + badValue + '\"';
+    } else {
+      msg += '\" was not specified';
+    }
+    msg += 'Allowed values: ' + allowedValues;
+    alert(msg);
+  }
+  
+
+  function isHostedMode() {
+    return (external && external.gwtOnLoad &&
+        (document.location.href.indexOf('gwt.hybrid') == -1));
+  }
+  
+
+  // Called by both onScriptLoad() and onInjectionDone(). It causes
+  // the specified module to be cranked up.
+  //
+  function maybeStartModule() {
+    if (scriptsDone && loadDone) {
+      var iframe = document.getElementById('__MODULE_NAME__');
+      var frameWnd = iframe.contentWindow;
+      // copy the init handlers function into the iframe
+      frameWnd.__gwt_initHandlers = __MODULE_FUNC__.__gwt_initHandlers;
+      // remove this whole function from the global namespace to allow GC
+      __MODULE_FUNC__ = null;
+      iframe.contentWindow.gwtOnLoad(__gwt_onLoadError, '__MODULE_NAME__');
+    }
+  }
+  
+  // Called to slurp up all <meta> tags:
+  // gwt:property, gwt:base, gwt:onPropertyErrorFn, gwt:onLoadErrorFn
+  //
+  function processMetas() {
+    var metas = document.getElementsByTagName('meta');
+  
+    for (var i = 0, n = metas.length; i < n; ++i) {
+      var meta = metas[i];
+      var name = meta.getAttribute('name');
+  
+      if (name) {
+        if (name == 'gwt:property') {
+          var content = meta.getAttribute('content');
+          if (content) {
+            var name = content, value = '';
+            var eq = content.indexOf('=');
+            if (eq != -1) {
+              name = content.substring(0, eq);
+              value = content.substring(eq+1);
+            }
+            __gwt_metaProps[name] = value;
+          }
+        } else if (name == 'gwt:onPropertyErrorFn') {
+          var content = meta.getAttribute('content');
+          if (content) {
+            try {
+              __gwt_onPropertyError = eval(content);
+            } catch (e) {
+              alert('Bad handler \"' + content +
+                '\" for \"gwt:onPropertyErrorFn\"');
+            }
+          }
+        } else if (name == 'gwt:onLoadErrorFn') {
+          var content = meta.getAttribute('content');
+          if (content) {
+            try {
+              __gwt_onLoadError = eval(content);
+            } catch (e) {
+              alert('Bad handler \"' + content + '\" for \"gwt:onLoadErrorFn\"');
+            }
+          }
+        } else if (name == 'gwt:base') {
+          var content = meta.getAttribute('content');
+          var eqPos = content.lastIndexOf('=');
+          if (eqPos == -1) {
+            continue;
+          }
+          var moduleBase = content.substring(0, eqPos);
+          var moduleName = content.substring(eqPos + 1);
+          __gwt_base[moduleName] = moduleBase;
+        }
+      }
+    }
+  }
+
+  /**
+   * Determines whether or not a particular property value is allowed. Called by
+   * property providers.
+   * 
+   * @param propName the name of the property being checked
+   * @param propValue the property value being tested
+   */
+  function __gwt_isKnownPropertyValue(propName, propValue) {
+    return propValue in values[propName];
+  }
+
+  /**
+   * Returns a meta property value, if any.  Used by DefaultPropertyProvider.
+   */
+  function __gwt_getMetaProperty(name) {
+    var value = __gwt_metaProps[name];
+    return (value == null) ? null : value;
+  }
+
+  // Deferred-binding mapper function.
+  //
+  function O(a,v) {
+    var answer = answers;
+    var i = -1;
+    var n = a.length - 1;
+    while (++i < n) {
+      if (!(a[i] in answer)) {
+        answer[a[i]] = [];
+      }
+      answer = answer[a[i]];
+    }
+    answer[a[n]] = v;
+  }
+  
+  // --------------- PROPERTY PROVIDERS ---------------
+
+// __PROPERTIES_BEGIN__
+// __PROPERTIES_END__
+
+  // --------------- EXPOSED FUNCTIONS ----------------
+
+  // Called when the script injection is complete.
+  //
+  __MODULE_FUNC__.onInjectionDone = function() {
+    // Mark this module's script injection done and (possibly) start the module.
+    scriptsDone = true;
+    maybeStartModule();
+  }
+
+  // Called when the compiled script identified by moduleName is done loading.
+  //
+  __MODULE_FUNC__.onScriptLoad = function() {
+    // Mark this module's script as done loading and (possibly) start the module.
+    loadDone = true;
+    maybeStartModule();
+  }
+  
+  // --------------- STRAIGHT-LINE CODE ---------------
+
+// __SHELL_SERVLET_ONLY_BEGIN__
+  // Force shell servlet to serve compiled output for web mode
+  if (!isHostedMode()) {
+    document.write('<script src="__MODULE_NAME__.nocache.js?compiled"></script>');
+    return;
+  }
+// __SHELL_SERVLET_ONLY_END__
+
+  processMetas();
+
+  var strongName;
+  if (isHostedMode()) {
+    // In hosted mode, inject the script frame directly.
+    var iframe = document.createElement('iframe');
+    iframe.id = '__MODULE_NAME__';
+    iframe.style.width = '0px';
+    iframe.style.height = '0px';
+    iframe.style.border = '0px';
+    document.body.appendChild(iframe);
+
+    iframe.src = 'blank.html';
+    iframe.onload = function() {
+      var frameWnd = iframe.contentWindow;
+      frameWnd.$wnd = wnd;
+      frameWnd.$doc = wnd.document;
+
+      // inject hosted mode property evaluation function
+      frameWnd.__gwt_getProperty = function(name) {
+        return providers[name]();
+      };
+
+      // inject gwtOnLoad
+      frameWnd.gwtOnLoad = function(errFn, modName) {
+        if (!external.gwtOnLoad(frameWnd, modName)) {
+          errFn(modName);
+        }
+      }
+
+      // Hook the iframe's onunload, so that the hosted browser has a chance
+      // to clean up its ModuleSpaces.
+      frameWnd.onunload = function() {
+        external.gwtOnLoad(frameWnd, null);
+      };
+
+      __MODULE_FUNC__.onScriptLoad();
+    };
+  } else {
+    try {
+// __PERMUTATIONS_BEGIN__
+      // Permutation logic
+// __PERMUTATIONS_END__
+    } catch (e) {
+      // intentionally silent on property failure
+      return;
+    }  
+
+	  // TODO: do we still need this query stuff?
+	  var query = location.search;
+	  query = query.substring(0, query.indexOf('&'));
+
+	  var base = __gwt_base['__MODULE_NAME__'];
+	  var newUrl = (base ? base + '/' : '') + strongName + '.cache.html' + query;
+	  document.write('<iframe id="__MODULE_NAME__" style="width:0;height:0;border:0" src="' + newUrl + '"></iframe>');
+  }
+
+// __MODULE_DEPS_BEGIN__
+  // Module dependencies, such as scripts and css
+// __MODULE_DEPS_END__
+  document.write('<script>__MODULE_FUNC__.onInjectionDone(\'__MODULE_NAME__\')</script>');
+}
+
+// Called from compiled code to hook the window's resize & load events (the
+// code running in the script frame is not allowed to hook these directly).
+// 
+// Notes:
+// 1) We declare it here in the global scope so that it won't closure the
+// internals of the module func.
+//
+// 2) We hang it off the module func to avoid polluting the global namespace.
+//
+// 3) This function will be copied directly into the script frame window!
+//
+__MODULE_FUNC__.__gwt_initHandlers = function(resize, beforeunload, unload) {
+  var wnd = window;
+  var oldOnResize = wnd.onresize;
+  wnd.onresize = function() {
+   resize();
+   if (oldOnResize)
+     oldOnResize();
+  };
+  
+  var oldOnBeforeUnload = wnd.onbeforeunload;
+  wnd.onbeforeunload = function() {
+   var ret = beforeunload();
+  
+   var oldRet;
+   if (oldOnBeforeUnload)
+     oldRet = oldOnBeforeUnload();
+  
+   if (ret !== null)
+     return ret;
+   return oldRet;
+  };
+  
+  var oldOnUnload = wnd.onunload;
+  wnd.onunload = function() {
+   unload();
+   if (oldOnUnload)
+     oldOnUnload();
+  };
+}
+
+__MODULE_FUNC__();
diff --git a/eclipse/settings/english.dictionary b/eclipse/settings/english.dictionary
index 61a9e4c..2ba576b 100644
--- a/eclipse/settings/english.dictionary
+++ b/eclipse/settings/english.dictionary
@@ -21230,7 +21230,6 @@
 homomorphisms

 hone

 honed

-honer

 hones

 honest

 honestly

@@ -21249,6 +21248,7 @@
 honeys

 honeysuckle

 honing

+honor

 honorary

 hood

 hood's

@@ -47224,4 +47224,9 @@
 polymorphically

 modeled

 reentrancy

-temp
+temp

+servlet

+deprecated

+recognize

+minimalist
+cacheable
diff --git a/samples/dynatable/src/com/google/gwt/sample/dynatable/public/DynaTable.html b/samples/dynatable/src/com/google/gwt/sample/dynatable/public/DynaTable.html
index 629378b..016e829 100644
--- a/samples/dynatable/src/com/google/gwt/sample/dynatable/public/DynaTable.html
+++ b/samples/dynatable/src/com/google/gwt/sample/dynatable/public/DynaTable.html
@@ -2,14 +2,12 @@
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
-    <meta name='gwt:module' content='com.google.gwt.sample.dynatable.DynaTable' />
     <link type="text/css" rel="stylesheet" href="DynaTable.css" />
     <title></title>
   </head>
   <body>
-    <iframe id='__gwt_historyFrame' style='width:0;height:0;border:0'></iframe> <script
-    type="text/javascript" language='javascript' src='gwt.js'>
-    </script>
+    <iframe id='__gwt_historyFrame' style='width:0;height:0;border:0'></iframe>
+	<script type="text/javascript" language='javascript' src='com.google.gwt.sample.dynatable.DynaTable.nocache.js'></script>
     <h1>School Schedule for Professors and Students</h1>
     <table width="100%" border="0" summary="School Schedule for Professors and Students">
       <tr valign="top">
diff --git a/samples/hello/src/com/google/gwt/sample/hello/public/Hello.html b/samples/hello/src/com/google/gwt/sample/hello/public/Hello.html
index f97006b..1dc9a6f 100644
--- a/samples/hello/src/com/google/gwt/sample/hello/public/Hello.html
+++ b/samples/hello/src/com/google/gwt/sample/hello/public/Hello.html
@@ -1,9 +1,8 @@
 <html>
 	<head>
-		<meta name='gwt:module' content='com.google.gwt.sample.hello.Hello'>
 		<title>Hello</title>
 	</head>
 	<body bgcolor="white"> 
-		<script language="javascript" src="gwt.js"></script>
+		<script language="javascript" src="com.google.gwt.sample.hello.Hello.nocache.js"></script>
 	</body>
 </html>
diff --git a/samples/i18n/src/com/google/gwt/sample/i18n/public/I18N.html b/samples/i18n/src/com/google/gwt/sample/i18n/public/I18N.html
index 77dab1d..a919760 100644
--- a/samples/i18n/src/com/google/gwt/sample/i18n/public/I18N.html
+++ b/samples/i18n/src/com/google/gwt/sample/i18n/public/I18N.html
@@ -1,6 +1,5 @@
 <html>
   <head>
-    <meta name='gwt:module' content='com.google.gwt.sample.i18n.I18N'>
     <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
     <script language=javaScript>
       // Create dictionaries using the following style:
@@ -18,7 +17,7 @@
 		<title>Internationalization sample</title>
 	</head>
 	<body bgcolor="white">
-    <script language="javascript" src="gwt.js"></script>
+    <script language="javascript" src="com.google.gwt.sample.i18n.I18N.nocache.js"></script>
 
     <h1>
       &#206;&#241;&#355;&#233;&#114;&#241;&#229;&#355;&#238;&#246;&#241;&#229;&#316;&#238;&#382;&#229;&#355;&#238;&#246;&#241;
diff --git a/samples/json/src/com/google/gwt/sample/json/public/JSON.html b/samples/json/src/com/google/gwt/sample/json/public/JSON.html
index f546797..903eeb7 100644
--- a/samples/json/src/com/google/gwt/sample/json/public/JSON.html
+++ b/samples/json/src/com/google/gwt/sample/json/public/JSON.html
@@ -1,11 +1,10 @@
 <html>
 	<head>
-		<meta name='gwt:module' content='com.google.gwt.sample.json.JSON'>
 		<link rel='stylesheet' href='JSON.css'>
 		<title>JSON Interoperability Example</title>
 	</head>
 	<body>
-		<script language='javascript' src='gwt.js'></script>
+		<script language='javascript' src='com.google.gwt.sample.json.JSON.nocache.js'></script>
 		
 		<h1>JSON Interop Using JSNI</h1>
 		
diff --git a/samples/kitchensink/src/com/google/gwt/sample/kitchensink/public/KitchenSink.html b/samples/kitchensink/src/com/google/gwt/sample/kitchensink/public/KitchenSink.html
index 5d052e1..d8f4593 100644
--- a/samples/kitchensink/src/com/google/gwt/sample/kitchensink/public/KitchenSink.html
+++ b/samples/kitchensink/src/com/google/gwt/sample/kitchensink/public/KitchenSink.html
@@ -1,12 +1,9 @@
 <html>
 	<head>
-		<meta name='gwt:module' content='com.google.gwt.sample.kitchensink.KitchenSink'>
 		<title>Kitchen Sink</title>
 	</head>
 	<body> 
-		<!-- This script is the bootstrap stuff that simply must be there; it is sent down uncompressed -->
-		<script language='javascript' src='gwt.js'></script>
-
+		<script language='javascript' src='com.google.gwt.sample.kitchensink.KitchenSink.nocache.js'></script>
 		<iframe id='__gwt_historyFrame' style='width:0;height:0;border:0'></iframe>
 	</body>
 </html>
diff --git a/samples/mail/src/com/google/gwt/sample/mail/public/Mail.html b/samples/mail/src/com/google/gwt/sample/mail/public/Mail.html
index 30d6d6f..468557b 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/public/Mail.html
+++ b/samples/mail/src/com/google/gwt/sample/mail/public/Mail.html
@@ -1,10 +1,8 @@
 <html>
 	<head>
-		<meta name='gwt:module' content='com.google.gwt.sample.mail.Mail'>
 		<title>Mail App</title>
 	</head>
 	<body style='background-color: #EEEEEE'>
-		<!-- This script is the bootstrap stuff that simply must be there; it is sent down uncompressed -->
-		<script language='javascript' src='gwt.js'></script>
+		<script language='javascript' src='com.google.gwt.sample.mail.Mail.nocache.js'></script>
 	</body>
 </html>
diff --git a/samples/simplexml/src/com/google/gwt/sample/simplexml/public/SimpleXML.html b/samples/simplexml/src/com/google/gwt/sample/simplexml/public/SimpleXML.html
index 2b32316..a2a3522 100644
--- a/samples/simplexml/src/com/google/gwt/sample/simplexml/public/SimpleXML.html
+++ b/samples/simplexml/src/com/google/gwt/sample/simplexml/public/SimpleXML.html
@@ -1,10 +1,9 @@
 <html>
 	<head>
-		<meta name='gwt:module' content='com.google.gwt.sample.simplexml.SimpleXML'>
 		<title>Simple XML Example</title>
-			<link rel="stylesheet" type="text/css" href="SimpleXML.css" />
+		<link rel="stylesheet" type="text/css" href="SimpleXML.css" />
 	</head>
 	<body bgcolor="white"> 
-		<script language="javascript" src="gwt.js"></script>
+		<script language="javascript" src="com.google.gwt.sample.simplexml.SimpleXML.nocache.js"></script>
 	</body>
 </html>
diff --git a/user/src/com/google/gwt/core/public/blank.html b/user/src/com/google/gwt/core/public/blank.html
new file mode 100644
index 0000000..8c7fe21
--- /dev/null
+++ b/user/src/com/google/gwt/core/public/blank.html
@@ -0,0 +1,2 @@
+<html>
+</html>
\ No newline at end of file
diff --git a/user/src/com/google/gwt/core/public/gwt.js b/user/src/com/google/gwt/core/public/gwt.js
index cfe9c1c..a5468a4 100644
--- a/user/src/com/google/gwt/core/public/gwt.js
+++ b/user/src/com/google/gwt/core/public/gwt.js
@@ -1,4 +1,4 @@
-// Copyright 2006 Google Inc.
+// Copyright 2007 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
@@ -15,577 +15,27 @@
 // This startup script should be included in host pages either just after
 // <body> or inside the <head> after module <meta> tags.
 //
+(function(){
+	var metas = document.getElementsByTagName("meta");
 
-//////////////////////////////////////////////////////////////////////////////
-// DynamicResources
-//
-
-function DynamicResources() {
-  this.pendingElemsBySrc_ = {};
-  this.pendingScriptElems_ = new Array();
-}
-DynamicResources.prototype = {};
-
-// The array is set up such that, pairwise, the entries are (src, readyFnStr).
-// Called once for each module that is attached to the host page.
-// It is theoretically possible that addScripts() could be called reentrantly
-// if the browser event loop is pumped during this function and an iframe loads; 
-// we may want to enhance this method in the future to support that case.
-DynamicResources.prototype.addScripts = function(scriptArray, insertBeforeElem) {
-  var wasEmpty = (this.pendingScriptElems_.length == 0);
-  var anyAdded = false;
-  for (var i = 0, n = scriptArray.length; i < n; i += 2) {
-    var src = scriptArray[i];
-    if (this.pendingElemsBySrc_[src]) {
-      // Don't load the same script twice.
-      continue;
-    }
-    // Set up the element but don't add it to the DOM until its turn.
-    anyAdded = true;
-    var e = document.createElement("script");
-    this.pendingElemsBySrc_[src] = e;
-    var readyFn;
-    eval("readyFn = " + scriptArray[i+1]);
-    e.__readyFn = readyFn;
-    e.type = "text/javascript";
-    e.src = src;
-    e.__insertBeforeElem = insertBeforeElem;
-    this.pendingScriptElems_ = this.pendingScriptElems_.concat(e);
-  }
-  
-  if (wasEmpty && anyAdded) {
-    // Kickstart.
-    this.injectScript(this.pendingScriptElems_[0]);
-  }
-}
-
-DynamicResources.prototype.injectScript = function(scriptElem) {
-  var parentElem = scriptElem.__insertBeforeElem.parentNode;
-  parentElem.insertBefore(scriptElem, scriptElem.__insertBeforeElem);
-}
-
-DynamicResources.prototype.addStyles = function(styleSrcArray, insertBeforeElem) {
-  var parent = insertBeforeElem.parentNode;
-  for (var i = 0, n = styleSrcArray.length; i < n; ++i) {
-    var src = styleSrcArray[i];
-    if (this.pendingElemsBySrc_[src]) 
-      continue;
-    var e = document.createElement("link");
-    this.pendingElemsBySrc_[src] = e;
-    e.type = "text/css";
-    e.rel = "stylesheet";
-    e.href = src;
-    parent.insertBefore(e, insertBeforeElem);
-  }
-}
-
-DynamicResources.prototype.isReady = function() {
-  var elems = this.pendingScriptElems_;
-  if (elems.length > 0) {
-    var e = elems[0];
-    if (!e.__readyFn()) {
-      // The pending script isn't ready yet.
-      return false;
-    }
-    
-    // The pending script has now finished loading. Enqueue the next, if any.
-    e.__readyFn = null;
-    elems.shift();
-    if (elems.length > 0) {
-      // There is another script.
-      this.injectScript(elems[0]);
-      return false;
-    }
-  }
-
-  // There are no more pending scripts.
-  return true;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// ModuleControlBlock
-//
-function ModuleControlBlock(metaElem, rawName) {
-  var parts = ["", rawName];
-  var i = rawName.lastIndexOf("=");
-  if (i != -1) {
-    parts[0] = rawName.substring(0, i) + '/';
-    parts[1] = rawName.substring(i+1);
-  }
-
-  this.metaElem_ = metaElem;
-  this.baseUrl_ = parts[0];
-  this.name_ = parts[1];
-  this.compilationLoaded_ = false;
-  this.frameWnd_ = null;
-}
-ModuleControlBlock.prototype = {};
-
-/**
- * Determines whether this module is fully loaded and ready to run.
- */
-ModuleControlBlock.prototype.isReady = function() {
-  return this.compilationLoaded_;
-};
-
-/**
- * Called when the compilation for this module is loaded.
- */
-ModuleControlBlock.prototype.compilationLoaded = function(frameWnd) {
-  this.frameWnd_ = frameWnd;
-  this.compilationLoaded_ = true;
-}
-
-/**
- * Gets the logical module name, not including a base url prefix if one was
- * specified.
- */
-ModuleControlBlock.prototype.getName = function() {
-  return this.name_;
-}
-
-/**
- * Gets the base URL of the module, guaranteed to end with a slash.
- */
-ModuleControlBlock.prototype.getBaseURL = function() {
-  return this.baseUrl_;
-}
-
-/**
- * Gets the window of the module's frame.
- */
-ModuleControlBlock.prototype.getModuleFrameWindow = function() {
-  return this.frameWnd_;
-}
-
-/**
- * Injects a set of dynamic scripts.
- * The array is set up such that, pairwise, the entries are (src, readyFnStr).
- */
-ModuleControlBlock.prototype.addScripts = function(scriptSrcArray) {
-  return ModuleControlBlocks.dynamicResources_.addScripts(scriptSrcArray, this.metaElem_);
-}
-
-/**
- * Injects a set of dynamic styles.
- */
-ModuleControlBlock.prototype.addStyles = function(styleSrcArray) {
-  return ModuleControlBlocks.dynamicResources_.addStyles(styleSrcArray, this.metaElem_);
-}
- 
-//////////////////////////////////////////////////////////////////////////////
-// ModuleControlBlocks
-//
-function ModuleControlBlocks() {
-  this.blocks_ = [];
-}
-ModuleControlBlocks.dynamicResources_ = new DynamicResources(); // "static"
-ModuleControlBlocks.prototype = {};
-
-/**
- * Adds a module control control block for the named module.
- * @param metaElem the meta element that caused the module to be added
- * @param name the name of the module being added, optionally preceded by
- * an alternate base url of the form "_path_=_module_".
- */
-ModuleControlBlocks.prototype.add = function(metaElem, name) {
-  var mcb = new ModuleControlBlock(metaElem, name);
-  this.blocks_ = this.blocks_.concat(mcb);
-};
-
-/**
- * Determines whether all the modules are loaded and ready to run.
- */
-ModuleControlBlocks.prototype.isReady = function() {
-  for (var i = 0, n = this.blocks_.length; i < n; ++i) {
-    var mcb = this.blocks_[i];
-    if (!mcb.isReady()) {
-      return false;
-    }
-  }
-  
-  // Are there any pending dynamic resources (e.g. styles, scripts)?
-  if (!ModuleControlBlocks.dynamicResources_.isReady()) {
-    // No, we're still waiting on one or more dynamic resources.
-    return false;
-  }
-
-  return true;
-}
-
-/**
- * Determines whether there are any module control blocks.
- */
-ModuleControlBlocks.prototype.isEmpty = function() {
-  return this.blocks_.length == 0;
-}
-
-/**
- * Gets the module control block at the specified index.
- */
-ModuleControlBlocks.prototype.get = function(index) {
-  return this.blocks_[index];
-}
-
-/**
- * Injects an iframe for each module.
- */
-ModuleControlBlocks.prototype.injectFrames = function() {
-  for (var i = 0, n = this.blocks_.length; i < n; ++i) {
-    var mcb = this.blocks_[i];
-
-    // Insert an iframe for the module
-    var iframe = document.createElement("iframe");
-    var selectorUrl = mcb.getBaseURL() + mcb.getName() + ".nocache.html";
-    selectorUrl += "?" + (__gwt_isHosted() ? "h&" : "" ) + i;
-    var unique = new Date().getTime();
-    selectorUrl += "&" + unique;
-    iframe.style.border = '0px';
-    iframe.style.width = '0px';
-    iframe.style.height = '0px';
-    
-    // Fragile browser-specific ordering issues below
-    
-/*@cc_on
-    // prevent extra clicky noises on IE
-    iframe.src = selectorUrl;
-@*/
-    
-    if (document.body.firstChild) {
-      document.body.insertBefore(iframe, document.body.firstChild);
-    } else {
-      document.body.appendChild(iframe);
-    }
-    
-/*@cc_on
-    // prevent extra clicky noises on IE
-    return;
-@*/
-
-    if (iframe.contentWindow) {
-      // Older Mozilla has a caching bug for the iframe and won't reload the nocache.
-      iframe.contentWindow.location.replace(selectorUrl);
-    } else {
-      // Older Safari doesn't have a contentWindow.
-      iframe.src = selectorUrl;
-    }
-  }
-}
-
-/**
- * Runs the entry point for each module.
- */
-ModuleControlBlocks.prototype.run = function() {
-  for (var i = 0, n = this.blocks_.length; i < n; ++i) {
-    var mcb = this.blocks_[i];
-    var name = mcb.getName();
-    var frameWnd = mcb.getModuleFrameWindow();
-    if (__gwt_isHosted()) {
-      if (!window.external.gwtOnLoad(frameWnd, name)) {
-        // Module failed to load.
-        if (__gwt_onLoadError) {
-            __gwt_onLoadError(name);
-        } else {
-            window.alert("Failed to load module '" + name + 
-            "'.\nPlease see the log in the development shell for details.");
-        }
-      }
-    } else {
-      // The compilation itself handles calling the error function.
-      frameWnd.gwtOnLoad(__gwt_onLoadError, name);
-    }
-  }
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// Globals
-//
-
-var __gwt_retryWaitMillis = 10;
-var __gwt_isHostPageLoaded = false;
-var __gwt_metaProps = {};
-var __gwt_onPropertyError = null;
-var __gwt_onLoadError = null;
-var __gwt_moduleControlBlocks = new ModuleControlBlocks();
-
-//////////////////////////////////////////////////////////////////////////////
-// Common 
-//
-
-/**
- * Determines whether or not the page is being loaded in the GWT hosted browser.
- */
-function __gwt_isHosted() {
-  if (window.external && window.external.gwtOnLoad) {
-    // gwt.hybrid makes the hosted browser pretend not to be
-    if (document.location.href.indexOf("gwt.hybrid") == -1) {
-      return true;
-    }
-  }
-  return false;
-}
-
-/**
- * Tries to get a module control block based on a query string passed in from
- * the caller. Used by iframes to get references back to their mcbs.
- * @param queryString the entire query string as returned by location.search,
- * which notably includes the leading '?' if one is specified
- * @return the relevant module control block, or <code>null</code> if it cannot 
- * be derived based on <code>queryString</code>
- */
-function __gwt_tryGetModuleControlBlock(queryString) {
-  if (queryString.length > 0) {
-    // The pattern is ?[h&]<index>[&<unique>]
-    var queryString = queryString.substring(1);
-    if (queryString.indexOf("h&") == 0) {
-      // Ignore the hosted mode flag here; only GWTShellServlet cares about it.
-      queryString = queryString.substring(2);
-    }
-    var pos = queryString.indexOf("&");
-    if (pos >= 0) {
-      queryString = queryString.substring(0, pos);
-    }
-    var mcbIndex = parseInt(queryString);
-    if (!isNaN(mcbIndex)) {
-      var mcb = __gwt_moduleControlBlocks.get(mcbIndex);
-      return mcb;
-    }
-    // Ignore the unique number that remains on the query string.
-  }
-  return null;
-}
-
-/**
- * Parses meta tags from the host html.
- * 
- * <meta name="gwt:module" content="_module-name_">
- *    causes the specified module to be loaded
- *
- * <meta name="gwt:property" content="_name_=_value_">
- *    statically defines a deferred binding client property
- *
- * <meta name="gwt:onPropertyErrorFn" content="_fnName_">
- *    specifies the name of a function to call if a client property is set to 
- *    an invalid value (meaning that no matching compilation will be found)
- * 
- * <meta name="gwt:onLoadErrorFn" content="_fnName_">
- *    specifies the name of a function to call if an exception happens during 
- *    bootstrapping or if a module throws an exception out of onModuleLoad(); 
- *    the function should take a message parameter
- */
-function __gwt_processMetas() {
-  var metas = document.getElementsByTagName("meta");
-  for (var i = 0, n = metas.length; i < n; ++i) {
-    var meta = metas[i];
-    var name = meta.getAttribute("name");
-    if (name) {
-      if (name == "gwt:module") {
-        var moduleName = meta.getAttribute("content");
-        if (moduleName) {
-          __gwt_moduleControlBlocks.add(meta, moduleName);
-        }
-      } else if (name == "gwt:property") {
-        var content = meta.getAttribute("content");
-        if (content) {
-          var name = content, value = "";
-          var eq = content.indexOf("=");
-          if (eq != -1) {
-            name = content.substring(0, eq);
-            value = content.substring(eq+1);
-          }
-          __gwt_metaProps[name] = value;
-        }
-      } else if (name == "gwt:onPropertyErrorFn") {
-        var content = meta.getAttribute("content");
-        if (content) {
-          try {
-            __gwt_onPropertyError = eval(content);
-          } catch (e) {
-            window.alert("Bad handler \"" + content + 
-              "\" for \"gwt:onPropertyErrorFn\"");
-          }
-        }
-      } else if (name == "gwt:onLoadErrorFn") {
-        var content = meta.getAttribute("content");
-        if (content) {
-          try {
-            __gwt_onLoadError = eval(content);
-          } catch (e) {
-            window.alert("Bad handler \"" + content + 
-              "\" for \"gwt:onLoadErrorFn\"");
-          }
-        }
-      }
-    }
-  }
-}
-
-/**
- * Determines the value of a deferred binding client property specified 
- * statically in host html.
- */
-function __gwt_getMetaProperty(name) {
-  var value = __gwt_metaProps[name];
-  if (value) {
-    return value;
-  } else {
-    return null;
-  }
-}
-
-/**
- * Determines whether or not a particular property value is allowed.
- * @param wnd the caller's window object (not $wnd!)
- * @param propName the name of the property being checked
- * @param propValue the property value being tested
- */
-function __gwt_isKnownPropertyValue(wnd, propName, propValue) {
-  return propValue in wnd["values$" + propName];
-}
-
-/**
- * Called by the selection script when a property has a bad value or is missing.
- * 'allowedValues' is an array of strings. Can be hooked in the host page using 
- * gwt:onPropertyErrorFn.
- */
-function __gwt_onBadProperty(moduleName, propName, allowedValues, badValue) {
-  if (__gwt_onPropertyError) {
-    __gwt_onPropertyError(moduleName, propName, allowedValues, badValue);
-    return;
-  } else {
-    var msg = "While attempting to load module \"" + moduleName + "\", ";
-    if (badValue != null) {
-       msg += "property \"" + propName + "\" was set to the unexpected value \"" 
-        + badValue + "\"";
-    } else {
-       msg += "property \"" + propName + "\" was not specified";
-    }
-    
-    msg += "\n\nAllowed values: " + allowedValues;
-   
-    window.alert(msg);
-  }
-}
-
-/**
- * Called directly from compiled code.
- */
-function __gwt_initHandlers(resize, beforeunload, unload) {
-   var oldOnResize = window.onresize;
-   window.onresize = function() {
-      resize();
-      if (oldOnResize)
-         oldOnResize();
-   };
-
-   var oldOnBeforeUnload = window.onbeforeunload;
-   window.onbeforeunload = function() {
-      var ret = beforeunload();
-
-      var oldRet;
-      if (oldOnBeforeUnload)
-        oldRet = oldOnBeforeUnload();
-
-      if (ret !== null)
-        return ret;
-      return oldRet;
-   };
-
-   var oldOnUnload = window.onunload;
-   window.onunload = function() {
-      unload();
-      if (oldOnUnload)
-         oldOnUnload();
-   };
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// Hosted Mode
-//
-function __gwt_onUnloadHostedMode() {
-    window.external.gwtOnLoad(null, null);
-    if (__gwt_onUnloadHostedMode.oldUnloadHandler) {
-        __gwt_onUnloadHostedMode.oldUnloadHandler();
-    }
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// Bootstrap
-//
-
-/**
- * Waits until all startup preconditions are satisfied, then launches the 
- * user-defined startup code for each module.
- */
-function __gwt_latchAndLaunch() {
-  var ready = true;
-  
-  // Are there any compilations still pending?
-  if (ready && !__gwt_moduleControlBlocks.isReady()) {
-    // Yes, we're still waiting on one or more compilations.
-    ready = false;
-  }
-
-  // Has the host html onload event fired?
-  if (ready && !__gwt_isHostPageLoaded) {
-    // No, the host html page hasn't fully loaded.
-    ready = false;
-  }
-  
-  // Are we ready to run user code?
-  if (ready) {
-    // Yes: run entry points.
-    __gwt_moduleControlBlocks.run();
-  } else {
-    // No: try again soon.
-    window.setTimeout(__gwt_latchAndLaunch, __gwt_retryWaitMillis);
-  }
-}
-
-/**
- * Starts the module-loading sequence after meta tags have been processed and
- * the body element exists.
- */
-function __gwt_loadModules() {
-  // Make sure the body element exists before starting.
-  if (!document.body) {
-    // Try again soon.
-    window.setTimeout(__gwt_loadModules, __gwt_retryWaitMillis);
-    return;
-  }
-
-  // Inject a frame for each module.
-  __gwt_moduleControlBlocks.injectFrames();
-
-  // Try to launch module entry points once everything is ready.
-  __gwt_latchAndLaunch();
-}
-
-/**
- * The very first thing to run, and it runs exactly once unconditionally.
- */
-function __gwt_bootstrap() {
-  // Hook onunload for hosted mode.
-  if (__gwt_isHosted()) {
-    __gwt_onUnloadHostedMode.oldUnloadHandler = window.onunload;
-    window.onunload = __gwt_onUnloadHostedMode;
-  }
-
-  // Hook the current window onload handler.
-  var oldHandler = window.onload;
-  window.onload = function() {
-    __gwt_isHostPageLoaded = true;
-    if (oldHandler) {
-      oldHandler();
-    }
-  };
-
-  // Parse meta tags from host html.
-  __gwt_processMetas();
-
-  // Load any modules.
-  __gwt_loadModules();
-}
-
-// Go.
-__gwt_bootstrap();
+	for (var i = 0, n = metas.length; i < n; ++i) {
+		var meta = metas[i];
+		var name = meta.getAttribute("name");
+		if (name) {
+			if (name == "gwt:module") {
+				var moduleName = meta.getAttribute("content");
+				if (moduleName) {
+					var eqPos = moduleName.lastIndexOf("=");
+					if (eqPos != -1) {
+						var base = moduleName.substring(0, eqPos);
+						moduleName = moduleName.substring(eqPos + 1);
+						window.__gwt_base = { };
+						window.__gwt_base[moduleName] = base;
+						moduleName = base + '/' + moduleName;
+					}
+					document.write('<script src="' + moduleName + '.nocache.js"></script>');
+				}
+			}
+		}
+	}
+})();
diff --git a/user/src/com/google/gwt/i18n/I18N.gwt.xml b/user/src/com/google/gwt/i18n/I18N.gwt.xml
index e6a9971..8d5dd0a 100644
--- a/user/src/com/google/gwt/i18n/I18N.gwt.xml
+++ b/user/src/com/google/gwt/i18n/I18N.gwt.xml
@@ -13,41 +13,42 @@
 		try {
           var locale;
           
-          //Look for the locale as a url argument
-          if(locale==null) {
-            var args = parent.location.search;
+          // Look for the locale as a url argument
+          if (locale == null) {
+            var args = location.search;
             var startLang = args.indexOf("locale");
-            if(startLang>=0){
-                var language = args.substring(startLang);
-                var begin = language.indexOf("=") + 1;
-                var end = language.indexOf("&");
-                if (end == -1) {
-                    end = language.length;
-                }
-                locale = language.substring(begin, end);
+            if (startLang >= 0) {
+              var language = args.substring(startLang);
+              var begin = language.indexOf("=") + 1;
+              var end = language.indexOf("&");
+              if (end == -1) {
+                end = language.length;
+              }
+              locale = language.substring(begin, end);
             }
           }      
-          if(locale == null){  
-           //Look for the locale on the web page
-            locale = parent.__gwt_getMetaProperty("locale")   
+          
+          if (locale == null) {  
+            // Look for the locale on the web page
+            locale = __gwt_getMetaProperty("locale")   
           }
            
-          if(locale == null){
+          if (locale == null) {
             return "default";
           }
            
-          while(!parent.__gwt_isKnownPropertyValue(window, "locale",  locale)){
+          while (!__gwt_isKnownPropertyValue("locale",  locale)) {
             var lastIndex = locale.lastIndexOf("_");
-            if(lastIndex == -1){
+            if (lastIndex == -1) {
           	  locale = "default";
               break;
-            } else{
+            } else {
               locale = locale.substring(0,lastIndex);
             }
           }
           return locale;
         } catch(e){
-          $wnd.alert("Unexpected exception in locale creator, using default: " + e);
+          alert("Unexpected exception in locale detection, using default: " + e);
           return "default";
         }
 		]]>
diff --git a/user/src/com/google/gwt/user/client/Window.java b/user/src/com/google/gwt/user/client/Window.java
index 61cf745..4805015 100644
--- a/user/src/com/google/gwt/user/client/Window.java
+++ b/user/src/com/google/gwt/user/client/Window.java
@@ -74,9 +74,9 @@
   }-*/;
 
   /**
-   * Use this method to explicitly disable the window's scrollbars.
-   * Applications that choose to resize their user-interfaces to fit within the
-   * window's client area will normally want to disable window scrolling.
+   * Use this method to explicitly disable the window's scrollbars. Applications
+   * that choose to resize their user-interfaces to fit within the window's
+   * client area will normally want to disable window scrolling.
    * 
    * @param enable <code>false</code> to disable window scrolling
    */
@@ -147,7 +147,7 @@
   }
 
   /**
-   * Sets the size of the margins used within the window's client area.  It is
+   * Sets the size of the margins used within the window's client area. It is
    * sometimes necessary to do this because some browsers, such as Internet
    * Explorer, add margins by default, which can confound attempts to resize
    * panels to fit exactly within the window.
@@ -249,7 +249,8 @@
   }
 
   private static native void init() /*-{
-    $wnd.__gwt_initHandlers(
+    // Magic function defined by the selection script
+    __gwt_initHandlers(
       function() {
         @com.google.gwt.user.client.Window::onResize()();
       },
diff --git a/user/src/com/google/gwt/user/tools/AppHtml.htmlsrc b/user/src/com/google/gwt/user/tools/AppHtml.htmlsrc
index 73c5b4e..2b09787 100644
--- a/user/src/com/google/gwt/user/tools/AppHtml.htmlsrc
+++ b/user/src/com/google/gwt/user/tools/AppHtml.htmlsrc
@@ -18,11 +18,11 @@
 		</style>
 
 		<!--                                           -->
-		<!-- The module reference below is the link    -->
-		<!-- between html and your Web Toolkit module  -->		
+		<!-- This script loads your compiled module.   -->
+		<!-- If you add any GWT meta tags, they must   -->
+		<!-- be added before this line.                -->
 		<!--                                           -->
-		<meta name='gwt:module' content='@moduleName'>
-		
+		<script language='javascript' src='@moduleName.nocache.js'></script>
 	</head>
 
 	<!--                                           -->
@@ -32,13 +32,6 @@
 	<!--                                           -->
 	<body>
 
-		<!--                                            -->
-		<!-- This script is required bootstrap stuff.   -->
-		<!-- You can put it in the HEAD, but startup    -->
-		<!-- is slightly faster if you include it here. -->
-		<!--                                            -->
-		<script language="javascript" src="gwt.js"></script>
-
 		<!-- OPTIONAL: include this if you want history support -->
 		<iframe id="__gwt_historyFrame" style="width:0;height:0;border:0"></iframe>