Load global scripts when first method in the class is called
diff --git a/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java b/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java
new file mode 100644
index 0000000..cb0dfd5
--- /dev/null
+++ b/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java
@@ -0,0 +1,180 @@
+/**
+ * HTML via Java(tm) Language Bindings
+ * Copyright (C) 2013 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details. apidesign.org
+ * designates this particular file as subject to the
+ * "Classpath" exception as provided by apidesign.org
+ * in the License file that accompanied this code.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. Look for COPYING file in the top folder.
+ * If not, see http://wiki.apidesign.org/wiki/GPLwithClassPathException
+ */
+package net.java.html.boot.fx;
+
+import java.net.URL;
+import java.util.concurrent.CountDownLatch;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.scene.Scene;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.web.WebView;
+import javafx.stage.Stage;
+import net.java.html.js.JavaScriptBody;
+import net.java.html.js.JavaScriptResource;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNotSame;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
+ */
+public class FXBrowsersOnResourceTest {
+    
+    public FXBrowsersOnResourceTest() {
+    }
+    
+    @BeforeClass public void initFX() throws Throwable {
+        new Thread("initFX") {
+            @Override
+            public void run() {
+                App.launch(App.class);
+            }
+        }.start();
+        App.CDL.await();
+    }
+
+    @Test
+    public void behaviorOfTwoWebViewsAtOnce() throws Throwable {
+        class R implements Runnable {
+            CountDownLatch DONE = new CountDownLatch(1);
+            Throwable t;
+
+            @Override
+            public void run() {
+                try {
+                    doTest();
+                } catch (Throwable ex) {
+                    t = ex;
+                } finally {
+                    DONE.countDown();
+                }
+            }
+            
+            private void doTest() throws Throwable {
+                URL u = FXBrowsersOnResourceTest.class.getResource("/org/apidesign/html/boot/fx/empty.html");
+                assertNotNull(u, "URL found");
+                FXBrowsers.load(App.getV1(), u, OnPages.class, "first");
+                
+            }
+        }
+        R run = new R();
+        Platform.runLater(run);
+        run.DONE.await();
+        for (int i = 0; i < 100; i++) {
+            if (run.t != null) {
+                throw run.t;
+            }
+            if (System.getProperty("finalSecond") == null) {
+                Thread.sleep(100);
+            }
+        }
+        
+        
+        
+        assertEquals(Integer.getInteger("finalFirst"), Integer.valueOf(3), "Three times in view one");
+        assertEquals(Integer.getInteger("finalSecond"), Integer.valueOf(2), "Two times in view one");
+    }
+
+    @JavaScriptResource("wnd.js")
+    public static class OnPages {
+        static Class<?> first;
+        static Object firstWindow;
+        
+        public static void first() {
+            first = OnPages.class;
+            firstWindow = window();
+            assertNotNull(firstWindow, "First window found");
+            
+            assertEquals(increment(), 1, "Now it is one");
+            
+            URL u = FXBrowsersOnResourceTest.class.getResource("/org/apidesign/html/boot/fx/empty.html");
+            assertNotNull(u, "URL found");
+            FXBrowsers.load(App.getV2(), u, OnPages.class, "second", "Hello");
+            
+            assertEquals(increment(), 2, "Now it is two and not influenced by second view");
+            System.setProperty("finalFirst", "" + increment());
+        }
+        
+        public static void second(String... args) {
+            assertEquals(args.length, 1, "One string argument");
+            assertEquals(args[0], "Hello", "It is hello");
+            assertEquals(first, OnPages.class, "Both views share the same classloader");
+            
+            Object window = window();
+            assertNotNull(window, "Some window found");
+            assertNotNull(firstWindow, "First window is known");
+            assertNotSame(firstWindow, window, "The window objects should be different");
+            
+            assertEquals(increment(), 1, "Counting starts from zero");
+            System.setProperty("finalSecond", "" + increment());
+        }
+        
+        @JavaScriptBody(args = {}, body = "return wnd;")
+        private static native Object window();
+        
+        @JavaScriptBody(args = {}, body = ""
+            + "if (wnd.cnt) return ++wnd.cnt;"
+            + "return wnd.cnt = 1;"
+        )
+        private static native int increment();
+    }
+    
+    public static class App extends Application {
+        static final CountDownLatch CDL = new CountDownLatch(1);
+        private static BorderPane pane;
+
+        /**
+         * @return the v1
+         */
+        static WebView getV1() {
+            return (WebView)System.getProperties().get("v1");
+        }
+
+        /**
+         * @return the v2
+         */
+        static WebView getV2() {
+            return (WebView)System.getProperties().get("v2");
+        }
+
+        @Override
+        public void start(Stage stage) throws Exception {
+            pane= new BorderPane();
+            Scene scene = new Scene(pane, 800, 600);
+            stage.setScene(scene);
+            
+            System.getProperties().put("v1", new WebView());
+            System.getProperties().put("v2", new WebView());
+
+            pane.setCenter(getV1());
+            pane.setBottom(getV2());
+
+            stage.show();
+            CDL.countDown();
+        }
+        
+        
+    }
+}
diff --git a/boot-fx/src/test/resources/net/java/html/boot/fx/wnd.js b/boot-fx/src/test/resources/net/java/html/boot/fx/wnd.js
new file mode 100644
index 0000000..fabd851
--- /dev/null
+++ b/boot-fx/src/test/resources/net/java/html/boot/fx/wnd.js
@@ -0,0 +1,27 @@
+/*
+ * HTML via Java(tm) Language Bindings
+ * Copyright (C) 2013 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details. apidesign.org
+ * designates this particular file as subject to the
+ * "Classpath" exception as provided by apidesign.org
+ * in the License file that accompanied this code.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. Look for COPYING file in the top folder.
+ * If not, see http://wiki.apidesign.org/wiki/GPLwithClassPathException
+ */
+if (typeof wnd !== 'undefined') {
+    throw 'Window should not be defined yet: ' + wnd;
+}
+
+wnd = {
+};
+
diff --git a/boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java b/boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java
index 0f5da49..367a641 100644
--- a/boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java
+++ b/boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java
@@ -156,6 +156,7 @@
         private String name;
         private int found;
         private ClassLoader loader;
+        private String resource;
 
         public FindInClass(ClassLoader l, ClassVisitor cv) {
             super(Opcodes.ASM4, cv);
@@ -263,6 +264,14 @@
                         "org/apidesign/html/boot/spi/Fn", "define",
                         "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/String;)Lorg/apidesign/html/boot/spi/Fn;"
                 );
+                if (resource != null) {
+                    super.visitLdcInsn(Type.getObjectType(FindInClass.this.name));
+                    super.visitLdcInsn(resource);
+                    super.visitMethodInsn(Opcodes.INVOKESTATIC,
+                            "org/apidesign/html/boot/spi/Fn", "preload",
+                            "(Lorg/apidesign/html/boot/spi/Fn;Ljava/lang/Class;Ljava/lang/String;)Lorg/apidesign/html/boot/spi/Fn;"
+                    );
+                }
                 super.visitInsn(Opcodes.DUP);
                 super.visitFieldInsn(
                         Opcodes.PUTSTATIC, FindInClass.this.name,
@@ -487,11 +496,11 @@
             public void visit(String attrName, Object value) {
                 String relPath = (String) value;
                 if (relPath.startsWith("/")) {
-                    loadScript(loader, relPath);
+                    resource = relPath;
                 } else {
                     int last = name.lastIndexOf('/');
                     String fullPath = name.substring(0, last + 1) + relPath;
-                    loadScript(loader, fullPath);
+                    resource = fullPath;
                 }
             }
         }
diff --git a/boot/src/main/java/org/apidesign/html/boot/spi/Fn.java b/boot/src/main/java/org/apidesign/html/boot/spi/Fn.java
index 4de2960..a0cea41 100644
--- a/boot/src/main/java/org/apidesign/html/boot/spi/Fn.java
+++ b/boot/src/main/java/org/apidesign/html/boot/spi/Fn.java
@@ -21,8 +21,15 @@
 package org.apidesign.html.boot.spi;
 
 import java.io.Closeable;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.Reader;
 import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
 import net.java.html.js.JavaScriptBody;
 import org.apidesign.html.boot.impl.FnContext;
 
@@ -87,6 +94,31 @@
         return FnContext.currentPresenter().defineFn(code, names);
     }
     
+    private static final Map<String,Set<Presenter>> LOADED = new HashMap<String, Set<Presenter>>();
+    public static Fn preload(final Fn fn, final Class<?> caller, final String resource) {
+        return new Fn() {
+            @Override
+            public Object invoke(Object thiz, Object... args) throws Exception {
+                final Presenter p = FnContext.currentPresenter();
+                Set<Presenter> there = LOADED.get(resource);
+                if (there == null) {
+                    there = new HashSet<Presenter>();
+                    LOADED.put(resource, there);
+                }
+                if (there.add(p)) {
+                    InputStream is = caller.getClassLoader().getResourceAsStream(resource);
+                    try {
+                        InputStreamReader r = new InputStreamReader(is, "UTF-8");
+                        p.loadScript(r);
+                    } finally {
+                        is.close();
+                    }
+                }
+                return fn.invoke(thiz, args);
+            }
+        };
+    }
+    
     /** The currently active presenter.
      * 
      * @return the currently active presenter or <code>null</code>