Moving implementation classes into org.netbeans.html namespace netbeans
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 16 Dec 2013 16:59:43 +0100
branchnetbeans
changeset 36292fb71afdc0e
parent 361 700087d2a5d3
child 364 2739565c7a45
Moving implementation classes into org.netbeans.html namespace
boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java
boot-fx/src/main/java/org/apidesign/html/boot/fx/AbstractFXPresenter.java
boot-fx/src/main/java/org/apidesign/html/boot/fx/Dbgr.java
boot-fx/src/main/java/org/apidesign/html/boot/fx/FXBrwsr.java
boot-fx/src/main/java/org/apidesign/html/boot/fx/FXInspect.java
boot-fx/src/main/java/org/apidesign/html/boot/fx/FXPresenter.java
boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java
boot-fx/src/main/java/org/netbeans/html/boot/fx/Dbgr.java
boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java
boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java
boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java
boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java
boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersTest.java
boot-fx/src/test/java/org/apidesign/html/boot/fx/BootstrapTest.java
boot-fx/src/test/java/org/apidesign/html/boot/fx/FXPresenterTst.java
boot-fx/src/test/java/org/apidesign/html/boot/fx/KOFx.java
boot-fx/src/test/java/org/netbeans/html/boot/fx/BootstrapTest.java
boot-fx/src/test/java/org/netbeans/html/boot/fx/FXPresenterTst.java
boot-fx/src/test/java/org/netbeans/html/boot/fx/KOFx.java
boot-fx/src/test/resources/org/apidesign/html/boot/fx/empty.html
boot-fx/src/test/resources/org/netbeans/html/boot/fx/empty.html
boot/src/main/java/net/java/html/boot/BrowserBuilder.java
boot/src/main/java/org/apidesign/html/boot/impl/FindResources.java
boot/src/main/java/org/apidesign/html/boot/impl/FnContext.java
boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java
boot/src/main/java/org/apidesign/html/boot/impl/JavaScriptProcesor.java
boot/src/main/java/org/apidesign/html/boot/impl/JsAgent.java
boot/src/main/java/org/apidesign/html/boot/impl/JsCallback.java
boot/src/main/java/org/apidesign/html/boot/impl/JsClassLoader.java
boot/src/main/java/org/apidesign/html/boot/impl/Test.java
boot/src/main/java/org/apidesign/html/boot/spi/Fn.java
boot/src/main/java/org/netbeans/html/boot/impl/FindResources.java
boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java
boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java
boot/src/main/java/org/netbeans/html/boot/impl/JavaScriptProcesor.java
boot/src/main/java/org/netbeans/html/boot/impl/JsAgent.java
boot/src/main/java/org/netbeans/html/boot/impl/JsCallback.java
boot/src/main/java/org/netbeans/html/boot/impl/JsClassLoader.java
boot/src/main/java/org/netbeans/html/boot/impl/Test.java
boot/src/test/java/org/apidesign/html/boot/impl/Arithm.java
boot/src/test/java/org/apidesign/html/boot/impl/Compile.java
boot/src/test/java/org/apidesign/html/boot/impl/FnTest.java
boot/src/test/java/org/apidesign/html/boot/impl/JavaScriptProcesorTest.java
boot/src/test/java/org/apidesign/html/boot/impl/JsClassLoaderBase.java
boot/src/test/java/org/apidesign/html/boot/impl/JsClassLoaderTest.java
boot/src/test/java/org/apidesign/html/boot/impl/JsMethods.java
boot/src/test/java/org/netbeans/html/boot/impl/Arithm.java
boot/src/test/java/org/netbeans/html/boot/impl/Compile.java
boot/src/test/java/org/netbeans/html/boot/impl/FnTest.java
boot/src/test/java/org/netbeans/html/boot/impl/JavaScriptProcesorTest.java
boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderBase.java
boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderTest.java
boot/src/test/java/org/netbeans/html/boot/impl/JsMethods.java
boot/src/test/resources/org/apidesign/html/boot/impl/jsmethods.js
boot/src/test/resources/org/netbeans/html/boot/impl/jsmethods.js
context/src/main/java/net/java/html/BrwsrCtx.java
context/src/main/java/org/apidesign/html/context/impl/CtxAccssr.java
context/src/main/java/org/apidesign/html/context/impl/CtxImpl.java
context/src/main/java/org/apidesign/html/context/spi/Contexts.java
context/src/main/java/org/netbeans/html/context/impl/CtxAccssr.java
context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java
geo/src/main/java/net/java/html/geo/Position.java
geo/src/main/java/org/apidesign/html/geo/impl/GeoProcessor.java
geo/src/main/java/org/apidesign/html/geo/impl/JsG.java
geo/src/main/java/org/netbeans/html/geo/impl/GeoProcessor.java
geo/src/main/java/org/netbeans/html/geo/impl/JsG.java
geo/src/test/java/org/apidesign/html/geo/impl/Compile.java
geo/src/test/java/org/apidesign/html/geo/impl/GeoProcessorTest.java
geo/src/test/java/org/netbeans/html/geo/impl/Compile.java
geo/src/test/java/org/netbeans/html/geo/impl/GeoProcessorTest.java
json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java
json-tck/src/main/java/net/java/html/json/tests/JSONTest.java
json/src/main/java/net/java/html/json/Models.java
json/src/main/java/org/apidesign/html/json/impl/Bindings.java
json/src/main/java/org/apidesign/html/json/impl/Callback.java
json/src/main/java/org/apidesign/html/json/impl/FromJSON.java
json/src/main/java/org/apidesign/html/json/impl/JSON.java
json/src/main/java/org/apidesign/html/json/impl/JSONList.java
json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java
json/src/main/java/org/apidesign/html/json/impl/PropertyBindingAccessor.java
json/src/main/java/org/apidesign/html/json/impl/RcvrJSON.java
json/src/main/java/org/apidesign/html/json/impl/SetAndGet.java
json/src/main/java/org/apidesign/html/json/impl/WrapperObject.java
json/src/main/java/org/apidesign/html/json/spi/FunctionBinding.java
json/src/main/java/org/apidesign/html/json/spi/JSONCall.java
json/src/main/java/org/apidesign/html/json/spi/PropertyBinding.java
json/src/main/java/org/netbeans/html/json/impl/Bindings.java
json/src/main/java/org/netbeans/html/json/impl/Callback.java
json/src/main/java/org/netbeans/html/json/impl/FromJSON.java
json/src/main/java/org/netbeans/html/json/impl/JSON.java
json/src/main/java/org/netbeans/html/json/impl/JSONList.java
json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java
json/src/main/java/org/netbeans/html/json/impl/PropertyBindingAccessor.java
json/src/main/java/org/netbeans/html/json/impl/RcvrJSON.java
json/src/main/java/org/netbeans/html/json/impl/SetAndGet.java
json/src/main/java/org/netbeans/html/json/impl/WrapperObject.java
json/src/main/resources/org/apidesign/html/json/impl/Bundle.properties
json/src/main/resources/org/apidesign/html/json/spi/package.html
json/src/main/resources/org/netbeans/html/json/impl/Bundle.properties
json/src/main/resources/org/netbeans/html/json/spi/package.html
json/src/test/java/net/java/html/json/MapModelTest.java
json/src/test/java/net/java/html/json/TypesTest.java
json/src/test/java/org/apidesign/html/json/impl/ConstructorTest.java
json/src/test/java/org/apidesign/html/json/impl/EmployeeImpl.java
json/src/test/java/org/apidesign/html/json/impl/EmployerTest.java
json/src/test/java/org/apidesign/html/json/impl/JSONListTest.java
json/src/test/java/org/apidesign/html/json/impl/JSONTest.java
json/src/test/java/org/apidesign/html/json/impl/NoPropertiesTest.java
json/src/test/java/org/netbeans/html/json/impl/ConstructorTest.java
json/src/test/java/org/netbeans/html/json/impl/EmployeeImpl.java
json/src/test/java/org/netbeans/html/json/impl/EmployerTest.java
json/src/test/java/org/netbeans/html/json/impl/JSONListTest.java
json/src/test/java/org/netbeans/html/json/impl/JSONTest.java
json/src/test/java/org/netbeans/html/json/impl/NoPropertiesTest.java
ko-archetype-test/src/test/java/org/apidesign/html/archetype/test/ArchetypeVersionTest.java
ko-archetype-test/src/test/java/org/apidesign/html/archetype/test/VerifyArchetypeTest.java
ko-archetype-test/src/test/java/org/netbeans/html/archetype/test/ArchetypeVersionTest.java
ko-archetype-test/src/test/java/org/netbeans/html/archetype/test/VerifyArchetypeTest.java
ko-archetype/src/main/java/org/apidesign/html/archetype/package-info.java
ko-archetype/src/main/java/org/netbeans/html/archetype/package-info.java
ko-fx/src/main/java/org/apidesign/html/kofx/Console.java
ko-fx/src/main/java/org/apidesign/html/kofx/FXContext.java
ko-fx/src/main/java/org/apidesign/html/kofx/Knockout.java
ko-fx/src/main/java/org/apidesign/html/kofx/LoadJSON.java
ko-fx/src/main/java/org/apidesign/html/kofx/LoadWS.java
ko-fx/src/main/java/org/netbeans/html/kofx/Console.java
ko-fx/src/main/java/org/netbeans/html/kofx/FXContext.java
ko-fx/src/main/java/org/netbeans/html/kofx/Knockout.java
ko-fx/src/main/java/org/netbeans/html/kofx/LoadJSON.java
ko-fx/src/main/java/org/netbeans/html/kofx/LoadWS.java
ko-fx/src/main/resources/org/apidesign/html/kofx/knockout-2.2.1.js
ko-fx/src/main/resources/org/netbeans/html/kofx/knockout-2.2.1.js
ko-fx/src/test/java/org/apidesign/html/kofx/DynamicHTTP.java
ko-fx/src/test/java/org/apidesign/html/kofx/KOFx.java
ko-fx/src/test/java/org/apidesign/html/kofx/KnockoutFXTest.java
ko-fx/src/test/java/org/apidesign/html/kofx/LessCallbacksCheck.java
ko-fx/src/test/java/org/netbeans/html/kofx/DynamicHTTP.java
ko-fx/src/test/java/org/netbeans/html/kofx/KOFx.java
ko-fx/src/test/java/org/netbeans/html/kofx/KnockoutFXTest.java
ko-fx/src/test/java/org/netbeans/html/kofx/LessCallbacksCheck.java
ko-fx/src/test/resources/org/apidesign/html/kofx/test.html
ko-fx/src/test/resources/org/netbeans/html/kofx/test.html
ko-ws-tyrus/src/main/java/org/apidesign/html/wstyrus/TyrusContext.java
ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/TyrusContext.java
ko-ws-tyrus/src/test/java/org/apidesign/html/wstyrus/TyrusDynamicHTTP.java
ko-ws-tyrus/src/test/java/org/apidesign/html/wstyrus/TyrusFX.java
ko-ws-tyrus/src/test/java/org/apidesign/html/wstyrus/TyrusKnockoutTest.java
ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusDynamicHTTP.java
ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusFX.java
ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusKnockoutTest.java
ko-ws-tyrus/src/test/resources/org/apidesign/html/wstyrus/test.html
ko-ws-tyrus/src/test/resources/org/netbeans/html/wstyrus/test.html
pom.xml
sound/src/main/java/org/apidesign/html/sound/impl/BrowserAudioEnv.java
sound/src/main/java/org/netbeans/html/sound/impl/BrowserAudioEnv.java
     1.1 --- a/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java	Mon Dec 16 15:48:09 2013 +0100
     1.2 +++ b/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java	Mon Dec 16 16:59:43 2013 +0100
     1.3 @@ -49,7 +49,7 @@
     1.4  import javafx.scene.web.WebView;
     1.5  import net.java.html.boot.BrowserBuilder;
     1.6  import net.java.html.js.JavaScriptBody;
     1.7 -import org.apidesign.html.boot.fx.AbstractFXPresenter;
     1.8 +import org.netbeans.html.boot.fx.AbstractFXPresenter;
     1.9  
    1.10  /** Utility methods for working with <em>JavaFX</em> <code>WebView</code>s.
    1.11   *
     2.1 --- a/boot-fx/src/main/java/org/apidesign/html/boot/fx/AbstractFXPresenter.java	Mon Dec 16 15:48:09 2013 +0100
     2.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 @@ -1,190 +0,0 @@
     2.4 -/**
     2.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     2.6 - *
     2.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
     2.8 - *
     2.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    2.10 - * Other names may be trademarks of their respective owners.
    2.11 - *
    2.12 - * The contents of this file are subject to the terms of either the GNU
    2.13 - * General Public License Version 2 only ("GPL") or the Common
    2.14 - * Development and Distribution License("CDDL") (collectively, the
    2.15 - * "License"). You may not use this file except in compliance with the
    2.16 - * License. You can obtain a copy of the License at
    2.17 - * http://www.netbeans.org/cddl-gplv2.html
    2.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    2.19 - * specific language governing permissions and limitations under the
    2.20 - * License.  When distributing the software, include this License Header
    2.21 - * Notice in each file and include the License file at
    2.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    2.23 - * particular file as subject to the "Classpath" exception as provided
    2.24 - * by Oracle in the GPL Version 2 section of the License file that
    2.25 - * accompanied this code. If applicable, add the following below the
    2.26 - * License Header, with the fields enclosed by brackets [] replaced by
    2.27 - * your own identifying information:
    2.28 - * "Portions Copyrighted [year] [name of copyright owner]"
    2.29 - *
    2.30 - * Contributor(s):
    2.31 - *
    2.32 - * The Original Software is NetBeans. The Initial Developer of the Original
    2.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
    2.34 - *
    2.35 - * If you wish your version of this file to be governed by only the CDDL
    2.36 - * or only the GPL Version 2, indicate your decision by adding
    2.37 - * "[Contributor] elects to include this software in this distribution
    2.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
    2.39 - * single choice of license, a recipient has the option to distribute
    2.40 - * your version of this file under either the CDDL, the GPL Version 2 or
    2.41 - * to extend the choice of license to its licensees as provided above.
    2.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
    2.43 - * Version 2 license, then the option applies only if the new code is
    2.44 - * made subject to such option by the copyright holder.
    2.45 - */
    2.46 -package org.apidesign.html.boot.fx;
    2.47 -
    2.48 -import java.io.BufferedReader;
    2.49 -import java.io.Reader;
    2.50 -import java.net.URL;
    2.51 -import java.util.ArrayList;
    2.52 -import java.util.Arrays;
    2.53 -import java.util.List;
    2.54 -import java.util.logging.Level;
    2.55 -import java.util.logging.Logger;
    2.56 -import javafx.application.Platform;
    2.57 -import javafx.scene.web.WebEngine;
    2.58 -import javafx.scene.web.WebView;
    2.59 -import netscape.javascript.JSObject;
    2.60 -import org.apidesign.html.boot.spi.Fn;
    2.61 -
    2.62 -/**
    2.63 - *
    2.64 - * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    2.65 - */
    2.66 -public abstract class AbstractFXPresenter implements Fn.Presenter {
    2.67 -    static final Logger LOG = Logger.getLogger(FXPresenter.class.getName());
    2.68 -    protected static int cnt;
    2.69 -    protected List<String> scripts;
    2.70 -    protected Runnable onLoad;
    2.71 -    protected WebEngine engine;
    2.72 -
    2.73 -    @Override
    2.74 -    public Fn defineFn(String code, String... names) {
    2.75 -        StringBuilder sb = new StringBuilder();
    2.76 -        sb.append("(function() {");
    2.77 -        sb.append("  return function(");
    2.78 -        String sep = "";
    2.79 -        for (String n : names) {
    2.80 -            sb.append(sep).append(n);
    2.81 -            sep = ",";
    2.82 -        }
    2.83 -        sb.append(") {\n");
    2.84 -        sb.append(code);
    2.85 -        sb.append("};");
    2.86 -        sb.append("})()");
    2.87 -        if (LOG.isLoggable(Level.FINE)) {
    2.88 -            LOG.log(Level.FINE, 
    2.89 -                "defining function #{0}:\n{1}\n", 
    2.90 -                new Object[] { ++cnt, code }
    2.91 -            );
    2.92 -        }
    2.93 -        JSObject x = (JSObject) engine.executeScript(sb.toString());
    2.94 -        return new JSFn(this, x, cnt);
    2.95 -    }
    2.96 -
    2.97 -    @Override
    2.98 -    public void loadScript(Reader code) throws Exception {
    2.99 -        BufferedReader r = new BufferedReader(code);
   2.100 -        StringBuilder sb = new StringBuilder();
   2.101 -        for (;;) {
   2.102 -            String l = r.readLine();
   2.103 -            if (l == null) {
   2.104 -                break;
   2.105 -            }
   2.106 -            sb.append(l).append('\n');
   2.107 -        }
   2.108 -        final String script = sb.toString();
   2.109 -        if (scripts != null) {
   2.110 -            scripts.add(script);
   2.111 -        }
   2.112 -        engine.executeScript(script);
   2.113 -    }
   2.114 -
   2.115 -    protected final void onPageLoad() {
   2.116 -        if (scripts != null) {
   2.117 -            for (String s : scripts) {
   2.118 -                engine.executeScript(s);
   2.119 -            }
   2.120 -        }
   2.121 -        onLoad.run();
   2.122 -    }
   2.123 -
   2.124 -    @Override
   2.125 -    public void displayPage(final URL resource, final Runnable onLoad) {
   2.126 -        this.onLoad = onLoad;
   2.127 -        final WebView view = findView(resource);
   2.128 -        this.engine = view.getEngine();
   2.129 -        try {
   2.130 -            if (FXInspect.initialize(engine)) {
   2.131 -                scripts = new ArrayList<String>();
   2.132 -            }
   2.133 -        } catch (Throwable ex) {
   2.134 -            ex.printStackTrace();
   2.135 -        }
   2.136 -
   2.137 -        class Run implements Runnable {
   2.138 -
   2.139 -            @Override
   2.140 -            public void run() {
   2.141 -                if (scripts != null) {
   2.142 -                    view.setContextMenuEnabled(true);
   2.143 -                }
   2.144 -                engine.load(resource.toExternalForm());
   2.145 -            }
   2.146 -        }
   2.147 -        Run run = new Run();
   2.148 -        if (Platform.isFxApplicationThread()) {
   2.149 -            run.run();
   2.150 -        } else {
   2.151 -            Platform.runLater(run);
   2.152 -        }
   2.153 -        waitFinished();
   2.154 -    }
   2.155 -
   2.156 -    protected abstract void waitFinished();
   2.157 -
   2.158 -    protected abstract WebView findView(final URL resource);
   2.159 -
   2.160 -    private static final class JSFn extends Fn {
   2.161 -
   2.162 -        private final JSObject fn;
   2.163 -        private static int call;
   2.164 -        private final int id;
   2.165 -
   2.166 -        public JSFn(AbstractFXPresenter p, JSObject fn, int id) {
   2.167 -            super(p);
   2.168 -            this.fn = fn;
   2.169 -            this.id = id;
   2.170 -        }
   2.171 -
   2.172 -        @Override
   2.173 -        public Object invoke(Object thiz, Object... args) throws Exception {
   2.174 -            try {
   2.175 -                if (LOG.isLoggable(Level.FINE)) {
   2.176 -                    LOG.log(Level.FINE, "calling {0} function #{1}", new Object[]{++call, id});
   2.177 -                }
   2.178 -                List<Object> all = new ArrayList<Object>(args.length + 1);
   2.179 -                all.add(thiz == null ? fn : thiz);
   2.180 -                all.addAll(Arrays.asList(args));
   2.181 -                Object ret = fn.call("call", all.toArray()); // NOI18N
   2.182 -                return ret == fn ? null : ret;
   2.183 -            } catch (Error t) {
   2.184 -                t.printStackTrace();
   2.185 -                throw t;
   2.186 -            } catch (Exception t) {
   2.187 -                t.printStackTrace();
   2.188 -                throw t;
   2.189 -            }
   2.190 -        }
   2.191 -    }
   2.192 -    
   2.193 -}
     3.1 --- a/boot-fx/src/main/java/org/apidesign/html/boot/fx/Dbgr.java	Mon Dec 16 15:48:09 2013 +0100
     3.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.3 @@ -1,87 +0,0 @@
     3.4 -/**
     3.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3.6 - *
     3.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
     3.8 - *
     3.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    3.10 - * Other names may be trademarks of their respective owners.
    3.11 - *
    3.12 - * The contents of this file are subject to the terms of either the GNU
    3.13 - * General Public License Version 2 only ("GPL") or the Common
    3.14 - * Development and Distribution License("CDDL") (collectively, the
    3.15 - * "License"). You may not use this file except in compliance with the
    3.16 - * License. You can obtain a copy of the License at
    3.17 - * http://www.netbeans.org/cddl-gplv2.html
    3.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    3.19 - * specific language governing permissions and limitations under the
    3.20 - * License.  When distributing the software, include this License Header
    3.21 - * Notice in each file and include the License file at
    3.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    3.23 - * particular file as subject to the "Classpath" exception as provided
    3.24 - * by Oracle in the GPL Version 2 section of the License file that
    3.25 - * accompanied this code. If applicable, add the following below the
    3.26 - * License Header, with the fields enclosed by brackets [] replaced by
    3.27 - * your own identifying information:
    3.28 - * "Portions Copyrighted [year] [name of copyright owner]"
    3.29 - *
    3.30 - * Contributor(s):
    3.31 - *
    3.32 - * The Original Software is NetBeans. The Initial Developer of the Original
    3.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
    3.34 - *
    3.35 - * If you wish your version of this file to be governed by only the CDDL
    3.36 - * or only the GPL Version 2, indicate your decision by adding
    3.37 - * "[Contributor] elects to include this software in this distribution
    3.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
    3.39 - * single choice of license, a recipient has the option to distribute
    3.40 - * your version of this file under either the CDDL, the GPL Version 2 or
    3.41 - * to extend the choice of license to its licensees as provided above.
    3.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
    3.43 - * Version 2 license, then the option applies only if the new code is
    3.44 - * made subject to such option by the copyright holder.
    3.45 - */
    3.46 -package org.apidesign.html.boot.fx;
    3.47 -
    3.48 -import java.lang.reflect.Method;
    3.49 -import java.util.logging.Level;
    3.50 -import javafx.scene.web.WebEngine;
    3.51 -import javafx.util.Callback;
    3.52 -import static org.apidesign.html.boot.fx.AbstractFXPresenter.LOG;
    3.53 -
    3.54 -/** Debugger bridge to shield us from propriatory impl APIs.
    3.55 - *
    3.56 - * @author Jaroslav Tulach <jtulach@netbeans.org>
    3.57 - */
    3.58 -final class Dbgr {
    3.59 -    final Object dbg;
    3.60 -    final Method sendMsg;
    3.61 -    
    3.62 -    Dbgr(WebEngine eng, Callback<String,Void> callback) {
    3.63 -        Object d;
    3.64 -        Method m;
    3.65 -        try {
    3.66 -            d = eng.getClass().getMethod("impl_getDebugger").invoke(eng); // NOI18N
    3.67 -            Class<?> debugger = eng.getClass().getClassLoader().loadClass("com.sun.javafx.scene.web.Debugger"); // NOI18N
    3.68 -            debugger.getMethod("setEnabled", boolean.class).invoke(d, true); // NOI18N
    3.69 -            debugger.getMethod("setMessageCallback", Callback.class).invoke(d, callback); // NOI18N
    3.70 -            m = debugger.getMethod("sendMessage", String.class); // NOI18N
    3.71 -        } catch (Exception ex) {
    3.72 -            LOG.log(Level.INFO, null, ex);
    3.73 -            d = null;
    3.74 -            m = null;
    3.75 -        }
    3.76 -        dbg = d;
    3.77 -        sendMsg = m;
    3.78 -    }
    3.79 -
    3.80 -    void sendMessage(String msg) {
    3.81 -        try {
    3.82 -            if (dbg != null) {
    3.83 -                sendMsg.invoke(dbg, msg);
    3.84 -            }
    3.85 -        } catch (Exception ex) {
    3.86 -            LOG.log(Level.INFO, null, ex);
    3.87 -        }
    3.88 -    }
    3.89 -    
    3.90 -}
     4.1 --- a/boot-fx/src/main/java/org/apidesign/html/boot/fx/FXBrwsr.java	Mon Dec 16 15:48:09 2013 +0100
     4.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.3 @@ -1,193 +0,0 @@
     4.4 -/**
     4.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     4.6 - *
     4.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
     4.8 - *
     4.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    4.10 - * Other names may be trademarks of their respective owners.
    4.11 - *
    4.12 - * The contents of this file are subject to the terms of either the GNU
    4.13 - * General Public License Version 2 only ("GPL") or the Common
    4.14 - * Development and Distribution License("CDDL") (collectively, the
    4.15 - * "License"). You may not use this file except in compliance with the
    4.16 - * License. You can obtain a copy of the License at
    4.17 - * http://www.netbeans.org/cddl-gplv2.html
    4.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    4.19 - * specific language governing permissions and limitations under the
    4.20 - * License.  When distributing the software, include this License Header
    4.21 - * Notice in each file and include the License file at
    4.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    4.23 - * particular file as subject to the "Classpath" exception as provided
    4.24 - * by Oracle in the GPL Version 2 section of the License file that
    4.25 - * accompanied this code. If applicable, add the following below the
    4.26 - * License Header, with the fields enclosed by brackets [] replaced by
    4.27 - * your own identifying information:
    4.28 - * "Portions Copyrighted [year] [name of copyright owner]"
    4.29 - *
    4.30 - * Contributor(s):
    4.31 - *
    4.32 - * The Original Software is NetBeans. The Initial Developer of the Original
    4.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
    4.34 - *
    4.35 - * If you wish your version of this file to be governed by only the CDDL
    4.36 - * or only the GPL Version 2, indicate your decision by adding
    4.37 - * "[Contributor] elects to include this software in this distribution
    4.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
    4.39 - * single choice of license, a recipient has the option to distribute
    4.40 - * your version of this file under either the CDDL, the GPL Version 2 or
    4.41 - * to extend the choice of license to its licensees as provided above.
    4.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
    4.43 - * Version 2 license, then the option applies only if the new code is
    4.44 - * made subject to such option by the copyright holder.
    4.45 - */
    4.46 -package org.apidesign.html.boot.fx;
    4.47 -
    4.48 -import java.net.URL;
    4.49 -import java.util.concurrent.CountDownLatch;
    4.50 -import java.util.concurrent.Executors;
    4.51 -import java.util.logging.Level;
    4.52 -import java.util.logging.Logger;
    4.53 -import javafx.application.Application;
    4.54 -import javafx.application.Platform;
    4.55 -import javafx.beans.value.ChangeListener;
    4.56 -import javafx.beans.value.ObservableValue;
    4.57 -import javafx.concurrent.Worker;
    4.58 -import javafx.event.ActionEvent;
    4.59 -import javafx.event.EventHandler;
    4.60 -import javafx.geometry.Insets;
    4.61 -import javafx.geometry.Pos;
    4.62 -import javafx.scene.Scene;
    4.63 -import javafx.scene.control.Button;
    4.64 -import javafx.scene.layout.BorderPane;
    4.65 -import javafx.scene.layout.VBox;
    4.66 -import javafx.scene.text.Text;
    4.67 -import javafx.scene.web.WebEvent;
    4.68 -import javafx.scene.web.WebView;
    4.69 -import javafx.stage.Modality;
    4.70 -import javafx.stage.Stage;
    4.71 -
    4.72 -/** This is an implementation class, use {@link BrowserBuilder} API. Just
    4.73 - * include this JAR on classpath and the {@link BrowserBuilder} API will find
    4.74 - * this implementation automatically.
    4.75 - */
    4.76 -public class FXBrwsr extends Application {
    4.77 -    private static final Logger LOG = Logger.getLogger(FXBrwsr.class.getName());
    4.78 -    private static FXBrwsr INSTANCE;
    4.79 -    private static final CountDownLatch FINISHED = new CountDownLatch(1);
    4.80 -    private BorderPane root;
    4.81 -
    4.82 -    public static synchronized WebView findWebView(final URL url, final FXPresenter onLoad) {
    4.83 -        if (INSTANCE == null) {
    4.84 -            Executors.newFixedThreadPool(1).submit(new Runnable() {
    4.85 -                @Override
    4.86 -                public void run() {
    4.87 -                    try {
    4.88 -                        FXBrwsr.launch(FXBrwsr.class);
    4.89 -                    } catch (Throwable ex) {
    4.90 -                        ex.printStackTrace();
    4.91 -                    } finally {
    4.92 -                        FINISHED.countDown();
    4.93 -                    }
    4.94 -                }
    4.95 -            });
    4.96 -        }
    4.97 -        while (INSTANCE == null) {
    4.98 -            try {
    4.99 -                FXBrwsr.class.wait();
   4.100 -            } catch (InterruptedException ex) {
   4.101 -                // wait more
   4.102 -            }
   4.103 -        }
   4.104 -        if (!Platform.isFxApplicationThread()) {
   4.105 -            final WebView[] arr = {null};
   4.106 -            final CountDownLatch waitForResult = new CountDownLatch(1);
   4.107 -            Platform.runLater(new Runnable() {
   4.108 -                @Override
   4.109 -                public void run() {
   4.110 -                    arr[0] = INSTANCE.newView(url, onLoad);
   4.111 -                    waitForResult.countDown();
   4.112 -                }
   4.113 -            });
   4.114 -            for (;;) {
   4.115 -                try {
   4.116 -                    waitForResult.await();
   4.117 -                    break;
   4.118 -                } catch (InterruptedException ex) {
   4.119 -                    LOG.log(Level.INFO, null, ex);
   4.120 -                }
   4.121 -            }
   4.122 -            return arr[0];
   4.123 -        } else {
   4.124 -            return INSTANCE.newView(url, onLoad);
   4.125 -        }
   4.126 -    }
   4.127 -
   4.128 -    @Override
   4.129 -    public void start(Stage primaryStage) throws Exception {
   4.130 -        synchronized (FXBrwsr.class) {
   4.131 -            INSTANCE = this;
   4.132 -            FXBrwsr.class.notifyAll();
   4.133 -        }
   4.134 -        BorderPane r = new BorderPane();
   4.135 -        Scene scene = new Scene(r, 800, 600);
   4.136 -        primaryStage.setScene(scene);
   4.137 -        primaryStage.show();
   4.138 -        this.root = r;
   4.139 -    }
   4.140 -
   4.141 -    private WebView newView(final URL url, final FXPresenter onLoad) {
   4.142 -        final WebView view = new WebView();
   4.143 -        view.setContextMenuEnabled(false);
   4.144 -        view.getEngine().setOnAlert(new EventHandler<WebEvent<String>>() {
   4.145 -            @Override
   4.146 -            public void handle(WebEvent<String> t) {
   4.147 -                final Stage dialogStage = new Stage();
   4.148 -                dialogStage.initModality(Modality.WINDOW_MODAL);
   4.149 -                dialogStage.setTitle("Warning");
   4.150 -                final Button button = new Button("Close");
   4.151 -                final Text text = new Text(t.getData());
   4.152 -                VBox box = new VBox();
   4.153 -                box.setAlignment(Pos.CENTER);
   4.154 -                box.setSpacing(10);
   4.155 -                box.setPadding(new Insets(10));
   4.156 -                box.getChildren().addAll(text, button);
   4.157 -                dialogStage.setScene(new Scene(box));
   4.158 -                button.setCancelButton(true);
   4.159 -                button.setOnAction(new EventHandler<ActionEvent>() {
   4.160 -                    @Override
   4.161 -                    public void handle(ActionEvent t) {
   4.162 -                        dialogStage.close();
   4.163 -                    }
   4.164 -                });
   4.165 -                dialogStage.centerOnScreen();
   4.166 -                dialogStage.showAndWait();
   4.167 -            }
   4.168 -        });
   4.169 -        root.setCenter(view);
   4.170 -        final Worker<Void> w = view.getEngine().getLoadWorker();
   4.171 -        w.stateProperty().addListener(new ChangeListener<Worker.State>() {
   4.172 -            @Override
   4.173 -            public void changed(ObservableValue<? extends Worker.State> ov, Worker.State t, Worker.State newState) {
   4.174 -                if (newState.equals(Worker.State.SUCCEEDED)) {
   4.175 -                    onLoad.onPageLoad();
   4.176 -                }
   4.177 -                if (newState.equals(Worker.State.FAILED)) {
   4.178 -                    throw new IllegalStateException("Failed to load " + url);
   4.179 -                }
   4.180 -            }
   4.181 -        });
   4.182 -        return view;
   4.183 -    }
   4.184 -
   4.185 -    static void waitFinished() {
   4.186 -        for (;;) {
   4.187 -            try {
   4.188 -                FINISHED.await();
   4.189 -                break;
   4.190 -            } catch (InterruptedException ex) {
   4.191 -                LOG.log(Level.INFO, null, ex);
   4.192 -            }
   4.193 -        }
   4.194 -    }
   4.195 -    
   4.196 -}
     5.1 --- a/boot-fx/src/main/java/org/apidesign/html/boot/fx/FXInspect.java	Mon Dec 16 15:48:09 2013 +0100
     5.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.3 @@ -1,134 +0,0 @@
     5.4 -/**
     5.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     5.6 - *
     5.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
     5.8 - *
     5.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    5.10 - * Other names may be trademarks of their respective owners.
    5.11 - *
    5.12 - * The contents of this file are subject to the terms of either the GNU
    5.13 - * General Public License Version 2 only ("GPL") or the Common
    5.14 - * Development and Distribution License("CDDL") (collectively, the
    5.15 - * "License"). You may not use this file except in compliance with the
    5.16 - * License. You can obtain a copy of the License at
    5.17 - * http://www.netbeans.org/cddl-gplv2.html
    5.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    5.19 - * specific language governing permissions and limitations under the
    5.20 - * License.  When distributing the software, include this License Header
    5.21 - * Notice in each file and include the License file at
    5.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    5.23 - * particular file as subject to the "Classpath" exception as provided
    5.24 - * by Oracle in the GPL Version 2 section of the License file that
    5.25 - * accompanied this code. If applicable, add the following below the
    5.26 - * License Header, with the fields enclosed by brackets [] replaced by
    5.27 - * your own identifying information:
    5.28 - * "Portions Copyrighted [year] [name of copyright owner]"
    5.29 - *
    5.30 - * Contributor(s):
    5.31 - *
    5.32 - * The Original Software is NetBeans. The Initial Developer of the Original
    5.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
    5.34 - *
    5.35 - * If you wish your version of this file to be governed by only the CDDL
    5.36 - * or only the GPL Version 2, indicate your decision by adding
    5.37 - * "[Contributor] elects to include this software in this distribution
    5.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
    5.39 - * single choice of license, a recipient has the option to distribute
    5.40 - * your version of this file under either the CDDL, the GPL Version 2 or
    5.41 - * to extend the choice of license to its licensees as provided above.
    5.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
    5.43 - * Version 2 license, then the option applies only if the new code is
    5.44 - * made subject to such option by the copyright holder.
    5.45 - */
    5.46 -package org.apidesign.html.boot.fx;
    5.47 -
    5.48 -import java.io.IOException;
    5.49 -import java.io.ObjectInputStream;
    5.50 -import java.io.ObjectOutputStream;
    5.51 -import java.net.InetAddress;
    5.52 -import java.net.Socket;
    5.53 -import java.nio.charset.StandardCharsets;
    5.54 -import java.util.logging.Level;
    5.55 -import java.util.logging.Logger;
    5.56 -import javafx.application.Platform;
    5.57 -import javafx.scene.web.WebEngine;
    5.58 -import javafx.util.Callback;
    5.59 -
    5.60 -/**
    5.61 - *
    5.62 - * @author Jaroslav Tulach <jtulach@netbeans.org>
    5.63 - */
    5.64 -final class FXInspect implements Runnable {
    5.65 -    private static final Logger LOG = Logger.getLogger(FXInspect.class.getName());
    5.66 -    
    5.67 -    
    5.68 -    private final WebEngine engine;
    5.69 -    private final ObjectInputStream input;
    5.70 -    private Dbgr dbg;
    5.71 -    
    5.72 -    private FXInspect(WebEngine engine, int port) throws IOException {
    5.73 -        this.engine = engine;
    5.74 -        
    5.75 -        Socket socket = new Socket(InetAddress.getByName(null), port);
    5.76 -        ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
    5.77 -        this.input = new ObjectInputStream(socket.getInputStream());
    5.78 -        initializeDebugger(output);
    5.79 -    }
    5.80 -    
    5.81 -    static boolean initialize(WebEngine engine) {
    5.82 -        final int inspectPort = Integer.getInteger("netbeans.inspect.port", -1); // NOI18N
    5.83 -        if (inspectPort != -1) {
    5.84 -            try {
    5.85 -                FXInspect inspector = new FXInspect(engine, inspectPort);
    5.86 -                Thread t = new Thread(inspector, "FX<->NetBeans Inspector");
    5.87 -                t.start();
    5.88 -                return true;
    5.89 -            } catch (IOException ex) {
    5.90 -                LOG.log(Level.INFO, "Cannot connect to NetBeans IDE to port " + inspectPort, ex); // NOI18N
    5.91 -            }
    5.92 -        }
    5.93 -        return false;
    5.94 -    }
    5.95 -    
    5.96 -    private void initializeDebugger(final ObjectOutputStream output) {
    5.97 -        Platform.runLater(new Runnable() {
    5.98 -            @Override
    5.99 -            public void run() {
   5.100 -                dbg = new Dbgr(engine, new Callback<String,Void>() {
   5.101 -                    @Override
   5.102 -                    public Void call(String message) {
   5.103 -                        try {
   5.104 -                            byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
   5.105 -                            output.writeInt(bytes.length);
   5.106 -                            output.write(bytes);
   5.107 -                            output.flush();
   5.108 -                        } catch (IOException ioex) {
   5.109 -                            ioex.printStackTrace();
   5.110 -                        }
   5.111 -                        return null;
   5.112 -                    }
   5.113 -                });
   5.114 -            }
   5.115 -        });
   5.116 -    }
   5.117 -
   5.118 -    @Override
   5.119 -    public void run() {
   5.120 -        try {
   5.121 -            while (true) {
   5.122 -                int length = input.readInt();
   5.123 -                byte[] bytes = new byte[length];
   5.124 -                input.readFully(bytes);
   5.125 -                final String message = new String(bytes, StandardCharsets.UTF_8);
   5.126 -                Platform.runLater(new Runnable() {
   5.127 -                    @Override
   5.128 -                    public void run() {
   5.129 -                        dbg.sendMessage(message);
   5.130 -                    }
   5.131 -                });
   5.132 -            }
   5.133 -        } catch (IOException ex) {
   5.134 -            LOG.log(Level.WARNING, null, ex);
   5.135 -        }
   5.136 -    }
   5.137 -}
     6.1 --- a/boot-fx/src/main/java/org/apidesign/html/boot/fx/FXPresenter.java	Mon Dec 16 15:48:09 2013 +0100
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,98 +0,0 @@
     6.4 -/**
     6.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     6.6 - *
     6.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
     6.8 - *
     6.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    6.10 - * Other names may be trademarks of their respective owners.
    6.11 - *
    6.12 - * The contents of this file are subject to the terms of either the GNU
    6.13 - * General Public License Version 2 only ("GPL") or the Common
    6.14 - * Development and Distribution License("CDDL") (collectively, the
    6.15 - * "License"). You may not use this file except in compliance with the
    6.16 - * License. You can obtain a copy of the License at
    6.17 - * http://www.netbeans.org/cddl-gplv2.html
    6.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    6.19 - * specific language governing permissions and limitations under the
    6.20 - * License.  When distributing the software, include this License Header
    6.21 - * Notice in each file and include the License file at
    6.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    6.23 - * particular file as subject to the "Classpath" exception as provided
    6.24 - * by Oracle in the GPL Version 2 section of the License file that
    6.25 - * accompanied this code. If applicable, add the following below the
    6.26 - * License Header, with the fields enclosed by brackets [] replaced by
    6.27 - * your own identifying information:
    6.28 - * "Portions Copyrighted [year] [name of copyright owner]"
    6.29 - *
    6.30 - * Contributor(s):
    6.31 - *
    6.32 - * The Original Software is NetBeans. The Initial Developer of the Original
    6.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
    6.34 - *
    6.35 - * If you wish your version of this file to be governed by only the CDDL
    6.36 - * or only the GPL Version 2, indicate your decision by adding
    6.37 - * "[Contributor] elects to include this software in this distribution
    6.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
    6.39 - * single choice of license, a recipient has the option to distribute
    6.40 - * your version of this file under either the CDDL, the GPL Version 2 or
    6.41 - * to extend the choice of license to its licensees as provided above.
    6.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
    6.43 - * Version 2 license, then the option applies only if the new code is
    6.44 - * made subject to such option by the copyright holder.
    6.45 - */
    6.46 -package org.apidesign.html.boot.fx;
    6.47 -
    6.48 -import java.io.BufferedReader;
    6.49 -import java.io.File;
    6.50 -import java.io.Reader;
    6.51 -import java.lang.reflect.Method;
    6.52 -import java.net.URL;
    6.53 -import java.net.URLClassLoader;
    6.54 -import java.util.ArrayList;
    6.55 -import java.util.Arrays;
    6.56 -import java.util.List;
    6.57 -import java.util.logging.Level;
    6.58 -import java.util.logging.Logger;
    6.59 -import javafx.application.Platform;
    6.60 -import javafx.scene.web.WebEngine;
    6.61 -import javafx.scene.web.WebView;
    6.62 -import net.java.html.boot.BrowserBuilder;
    6.63 -import netscape.javascript.JSObject;
    6.64 -import org.apidesign.html.boot.spi.Fn;
    6.65 -import org.openide.util.lookup.ServiceProvider;
    6.66 -
    6.67 -/** This is an implementation class, use {@link BrowserBuilder} API. Just
    6.68 - * include this JAR on classpath and the {@link BrowserBuilder} API will find
    6.69 - * this implementation automatically.
    6.70 - *
    6.71 - * @author Jaroslav Tulach <jtulach@netbeans.org>
    6.72 - */
    6.73 -@ServiceProvider(service = Fn.Presenter.class)
    6.74 -public final class FXPresenter extends AbstractFXPresenter {
    6.75 -    static {
    6.76 -        try {
    6.77 -            try {
    6.78 -                Class<?> c = Class.forName("javafx.application.Platform");
    6.79 -                // OK, on classpath
    6.80 -            } catch (ClassNotFoundException classNotFoundException) {
    6.81 -                Method m = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
    6.82 -                m.setAccessible(true);
    6.83 -                File f = new File(System.getProperty("java.home"), "lib/jfxrt.jar");
    6.84 -                if (f.exists()) {
    6.85 -                    URL l = f.toURI().toURL();
    6.86 -                    m.invoke(ClassLoader.getSystemClassLoader(), l);
    6.87 -                }
    6.88 -            }
    6.89 -        } catch (Exception ex) {
    6.90 -            throw new LinkageError("Can't add jfxrt.jar on the classpath", ex);
    6.91 -        }
    6.92 -    }
    6.93 -
    6.94 -    protected void waitFinished() {
    6.95 -        FXBrwsr.waitFinished();
    6.96 -    }
    6.97 -
    6.98 -    protected WebView findView(final URL resource) {
    6.99 -        return FXBrwsr.findWebView(resource, this);
   6.100 -    }
   6.101 -}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java	Mon Dec 16 16:59:43 2013 +0100
     7.3 @@ -0,0 +1,190 @@
     7.4 +/**
     7.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     7.6 + *
     7.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
     7.8 + *
     7.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    7.10 + * Other names may be trademarks of their respective owners.
    7.11 + *
    7.12 + * The contents of this file are subject to the terms of either the GNU
    7.13 + * General Public License Version 2 only ("GPL") or the Common
    7.14 + * Development and Distribution License("CDDL") (collectively, the
    7.15 + * "License"). You may not use this file except in compliance with the
    7.16 + * License. You can obtain a copy of the License at
    7.17 + * http://www.netbeans.org/cddl-gplv2.html
    7.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    7.19 + * specific language governing permissions and limitations under the
    7.20 + * License.  When distributing the software, include this License Header
    7.21 + * Notice in each file and include the License file at
    7.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    7.23 + * particular file as subject to the "Classpath" exception as provided
    7.24 + * by Oracle in the GPL Version 2 section of the License file that
    7.25 + * accompanied this code. If applicable, add the following below the
    7.26 + * License Header, with the fields enclosed by brackets [] replaced by
    7.27 + * your own identifying information:
    7.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    7.29 + *
    7.30 + * Contributor(s):
    7.31 + *
    7.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    7.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
    7.34 + *
    7.35 + * If you wish your version of this file to be governed by only the CDDL
    7.36 + * or only the GPL Version 2, indicate your decision by adding
    7.37 + * "[Contributor] elects to include this software in this distribution
    7.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    7.39 + * single choice of license, a recipient has the option to distribute
    7.40 + * your version of this file under either the CDDL, the GPL Version 2 or
    7.41 + * to extend the choice of license to its licensees as provided above.
    7.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    7.43 + * Version 2 license, then the option applies only if the new code is
    7.44 + * made subject to such option by the copyright holder.
    7.45 + */
    7.46 +package org.netbeans.html.boot.fx;
    7.47 +
    7.48 +import java.io.BufferedReader;
    7.49 +import java.io.Reader;
    7.50 +import java.net.URL;
    7.51 +import java.util.ArrayList;
    7.52 +import java.util.Arrays;
    7.53 +import java.util.List;
    7.54 +import java.util.logging.Level;
    7.55 +import java.util.logging.Logger;
    7.56 +import javafx.application.Platform;
    7.57 +import javafx.scene.web.WebEngine;
    7.58 +import javafx.scene.web.WebView;
    7.59 +import netscape.javascript.JSObject;
    7.60 +import org.apidesign.html.boot.spi.Fn;
    7.61 +
    7.62 +/**
    7.63 + *
    7.64 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    7.65 + */
    7.66 +public abstract class AbstractFXPresenter implements Fn.Presenter {
    7.67 +    static final Logger LOG = Logger.getLogger(FXPresenter.class.getName());
    7.68 +    protected static int cnt;
    7.69 +    protected List<String> scripts;
    7.70 +    protected Runnable onLoad;
    7.71 +    protected WebEngine engine;
    7.72 +
    7.73 +    @Override
    7.74 +    public Fn defineFn(String code, String... names) {
    7.75 +        StringBuilder sb = new StringBuilder();
    7.76 +        sb.append("(function() {");
    7.77 +        sb.append("  return function(");
    7.78 +        String sep = "";
    7.79 +        for (String n : names) {
    7.80 +            sb.append(sep).append(n);
    7.81 +            sep = ",";
    7.82 +        }
    7.83 +        sb.append(") {\n");
    7.84 +        sb.append(code);
    7.85 +        sb.append("};");
    7.86 +        sb.append("})()");
    7.87 +        if (LOG.isLoggable(Level.FINE)) {
    7.88 +            LOG.log(Level.FINE, 
    7.89 +                "defining function #{0}:\n{1}\n", 
    7.90 +                new Object[] { ++cnt, code }
    7.91 +            );
    7.92 +        }
    7.93 +        JSObject x = (JSObject) engine.executeScript(sb.toString());
    7.94 +        return new JSFn(this, x, cnt);
    7.95 +    }
    7.96 +
    7.97 +    @Override
    7.98 +    public void loadScript(Reader code) throws Exception {
    7.99 +        BufferedReader r = new BufferedReader(code);
   7.100 +        StringBuilder sb = new StringBuilder();
   7.101 +        for (;;) {
   7.102 +            String l = r.readLine();
   7.103 +            if (l == null) {
   7.104 +                break;
   7.105 +            }
   7.106 +            sb.append(l).append('\n');
   7.107 +        }
   7.108 +        final String script = sb.toString();
   7.109 +        if (scripts != null) {
   7.110 +            scripts.add(script);
   7.111 +        }
   7.112 +        engine.executeScript(script);
   7.113 +    }
   7.114 +
   7.115 +    protected final void onPageLoad() {
   7.116 +        if (scripts != null) {
   7.117 +            for (String s : scripts) {
   7.118 +                engine.executeScript(s);
   7.119 +            }
   7.120 +        }
   7.121 +        onLoad.run();
   7.122 +    }
   7.123 +
   7.124 +    @Override
   7.125 +    public void displayPage(final URL resource, final Runnable onLoad) {
   7.126 +        this.onLoad = onLoad;
   7.127 +        final WebView view = findView(resource);
   7.128 +        this.engine = view.getEngine();
   7.129 +        try {
   7.130 +            if (FXInspect.initialize(engine)) {
   7.131 +                scripts = new ArrayList<String>();
   7.132 +            }
   7.133 +        } catch (Throwable ex) {
   7.134 +            ex.printStackTrace();
   7.135 +        }
   7.136 +
   7.137 +        class Run implements Runnable {
   7.138 +
   7.139 +            @Override
   7.140 +            public void run() {
   7.141 +                if (scripts != null) {
   7.142 +                    view.setContextMenuEnabled(true);
   7.143 +                }
   7.144 +                engine.load(resource.toExternalForm());
   7.145 +            }
   7.146 +        }
   7.147 +        Run run = new Run();
   7.148 +        if (Platform.isFxApplicationThread()) {
   7.149 +            run.run();
   7.150 +        } else {
   7.151 +            Platform.runLater(run);
   7.152 +        }
   7.153 +        waitFinished();
   7.154 +    }
   7.155 +
   7.156 +    protected abstract void waitFinished();
   7.157 +
   7.158 +    protected abstract WebView findView(final URL resource);
   7.159 +
   7.160 +    private static final class JSFn extends Fn {
   7.161 +
   7.162 +        private final JSObject fn;
   7.163 +        private static int call;
   7.164 +        private final int id;
   7.165 +
   7.166 +        public JSFn(AbstractFXPresenter p, JSObject fn, int id) {
   7.167 +            super(p);
   7.168 +            this.fn = fn;
   7.169 +            this.id = id;
   7.170 +        }
   7.171 +
   7.172 +        @Override
   7.173 +        public Object invoke(Object thiz, Object... args) throws Exception {
   7.174 +            try {
   7.175 +                if (LOG.isLoggable(Level.FINE)) {
   7.176 +                    LOG.log(Level.FINE, "calling {0} function #{1}", new Object[]{++call, id});
   7.177 +                }
   7.178 +                List<Object> all = new ArrayList<Object>(args.length + 1);
   7.179 +                all.add(thiz == null ? fn : thiz);
   7.180 +                all.addAll(Arrays.asList(args));
   7.181 +                Object ret = fn.call("call", all.toArray()); // NOI18N
   7.182 +                return ret == fn ? null : ret;
   7.183 +            } catch (Error t) {
   7.184 +                t.printStackTrace();
   7.185 +                throw t;
   7.186 +            } catch (Exception t) {
   7.187 +                t.printStackTrace();
   7.188 +                throw t;
   7.189 +            }
   7.190 +        }
   7.191 +    }
   7.192 +    
   7.193 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/Dbgr.java	Mon Dec 16 16:59:43 2013 +0100
     8.3 @@ -0,0 +1,87 @@
     8.4 +/**
     8.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     8.6 + *
     8.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
     8.8 + *
     8.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    8.10 + * Other names may be trademarks of their respective owners.
    8.11 + *
    8.12 + * The contents of this file are subject to the terms of either the GNU
    8.13 + * General Public License Version 2 only ("GPL") or the Common
    8.14 + * Development and Distribution License("CDDL") (collectively, the
    8.15 + * "License"). You may not use this file except in compliance with the
    8.16 + * License. You can obtain a copy of the License at
    8.17 + * http://www.netbeans.org/cddl-gplv2.html
    8.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    8.19 + * specific language governing permissions and limitations under the
    8.20 + * License.  When distributing the software, include this License Header
    8.21 + * Notice in each file and include the License file at
    8.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    8.23 + * particular file as subject to the "Classpath" exception as provided
    8.24 + * by Oracle in the GPL Version 2 section of the License file that
    8.25 + * accompanied this code. If applicable, add the following below the
    8.26 + * License Header, with the fields enclosed by brackets [] replaced by
    8.27 + * your own identifying information:
    8.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    8.29 + *
    8.30 + * Contributor(s):
    8.31 + *
    8.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    8.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
    8.34 + *
    8.35 + * If you wish your version of this file to be governed by only the CDDL
    8.36 + * or only the GPL Version 2, indicate your decision by adding
    8.37 + * "[Contributor] elects to include this software in this distribution
    8.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    8.39 + * single choice of license, a recipient has the option to distribute
    8.40 + * your version of this file under either the CDDL, the GPL Version 2 or
    8.41 + * to extend the choice of license to its licensees as provided above.
    8.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    8.43 + * Version 2 license, then the option applies only if the new code is
    8.44 + * made subject to such option by the copyright holder.
    8.45 + */
    8.46 +package org.netbeans.html.boot.fx;
    8.47 +
    8.48 +import java.lang.reflect.Method;
    8.49 +import java.util.logging.Level;
    8.50 +import javafx.scene.web.WebEngine;
    8.51 +import javafx.util.Callback;
    8.52 +import static org.netbeans.html.boot.fx.AbstractFXPresenter.LOG;
    8.53 +
    8.54 +/** Debugger bridge to shield us from propriatory impl APIs.
    8.55 + *
    8.56 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    8.57 + */
    8.58 +final class Dbgr {
    8.59 +    final Object dbg;
    8.60 +    final Method sendMsg;
    8.61 +    
    8.62 +    Dbgr(WebEngine eng, Callback<String,Void> callback) {
    8.63 +        Object d;
    8.64 +        Method m;
    8.65 +        try {
    8.66 +            d = eng.getClass().getMethod("impl_getDebugger").invoke(eng); // NOI18N
    8.67 +            Class<?> debugger = eng.getClass().getClassLoader().loadClass("com.sun.javafx.scene.web.Debugger"); // NOI18N
    8.68 +            debugger.getMethod("setEnabled", boolean.class).invoke(d, true); // NOI18N
    8.69 +            debugger.getMethod("setMessageCallback", Callback.class).invoke(d, callback); // NOI18N
    8.70 +            m = debugger.getMethod("sendMessage", String.class); // NOI18N
    8.71 +        } catch (Exception ex) {
    8.72 +            LOG.log(Level.INFO, null, ex);
    8.73 +            d = null;
    8.74 +            m = null;
    8.75 +        }
    8.76 +        dbg = d;
    8.77 +        sendMsg = m;
    8.78 +    }
    8.79 +
    8.80 +    void sendMessage(String msg) {
    8.81 +        try {
    8.82 +            if (dbg != null) {
    8.83 +                sendMsg.invoke(dbg, msg);
    8.84 +            }
    8.85 +        } catch (Exception ex) {
    8.86 +            LOG.log(Level.INFO, null, ex);
    8.87 +        }
    8.88 +    }
    8.89 +    
    8.90 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java	Mon Dec 16 16:59:43 2013 +0100
     9.3 @@ -0,0 +1,193 @@
     9.4 +/**
     9.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     9.6 + *
     9.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
     9.8 + *
     9.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    9.10 + * Other names may be trademarks of their respective owners.
    9.11 + *
    9.12 + * The contents of this file are subject to the terms of either the GNU
    9.13 + * General Public License Version 2 only ("GPL") or the Common
    9.14 + * Development and Distribution License("CDDL") (collectively, the
    9.15 + * "License"). You may not use this file except in compliance with the
    9.16 + * License. You can obtain a copy of the License at
    9.17 + * http://www.netbeans.org/cddl-gplv2.html
    9.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    9.19 + * specific language governing permissions and limitations under the
    9.20 + * License.  When distributing the software, include this License Header
    9.21 + * Notice in each file and include the License file at
    9.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    9.23 + * particular file as subject to the "Classpath" exception as provided
    9.24 + * by Oracle in the GPL Version 2 section of the License file that
    9.25 + * accompanied this code. If applicable, add the following below the
    9.26 + * License Header, with the fields enclosed by brackets [] replaced by
    9.27 + * your own identifying information:
    9.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    9.29 + *
    9.30 + * Contributor(s):
    9.31 + *
    9.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    9.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
    9.34 + *
    9.35 + * If you wish your version of this file to be governed by only the CDDL
    9.36 + * or only the GPL Version 2, indicate your decision by adding
    9.37 + * "[Contributor] elects to include this software in this distribution
    9.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    9.39 + * single choice of license, a recipient has the option to distribute
    9.40 + * your version of this file under either the CDDL, the GPL Version 2 or
    9.41 + * to extend the choice of license to its licensees as provided above.
    9.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    9.43 + * Version 2 license, then the option applies only if the new code is
    9.44 + * made subject to such option by the copyright holder.
    9.45 + */
    9.46 +package org.netbeans.html.boot.fx;
    9.47 +
    9.48 +import java.net.URL;
    9.49 +import java.util.concurrent.CountDownLatch;
    9.50 +import java.util.concurrent.Executors;
    9.51 +import java.util.logging.Level;
    9.52 +import java.util.logging.Logger;
    9.53 +import javafx.application.Application;
    9.54 +import javafx.application.Platform;
    9.55 +import javafx.beans.value.ChangeListener;
    9.56 +import javafx.beans.value.ObservableValue;
    9.57 +import javafx.concurrent.Worker;
    9.58 +import javafx.event.ActionEvent;
    9.59 +import javafx.event.EventHandler;
    9.60 +import javafx.geometry.Insets;
    9.61 +import javafx.geometry.Pos;
    9.62 +import javafx.scene.Scene;
    9.63 +import javafx.scene.control.Button;
    9.64 +import javafx.scene.layout.BorderPane;
    9.65 +import javafx.scene.layout.VBox;
    9.66 +import javafx.scene.text.Text;
    9.67 +import javafx.scene.web.WebEvent;
    9.68 +import javafx.scene.web.WebView;
    9.69 +import javafx.stage.Modality;
    9.70 +import javafx.stage.Stage;
    9.71 +
    9.72 +/** This is an implementation class, use {@link BrowserBuilder} API. Just
    9.73 + * include this JAR on classpath and the {@link BrowserBuilder} API will find
    9.74 + * this implementation automatically.
    9.75 + */
    9.76 +public class FXBrwsr extends Application {
    9.77 +    private static final Logger LOG = Logger.getLogger(FXBrwsr.class.getName());
    9.78 +    private static FXBrwsr INSTANCE;
    9.79 +    private static final CountDownLatch FINISHED = new CountDownLatch(1);
    9.80 +    private BorderPane root;
    9.81 +
    9.82 +    public static synchronized WebView findWebView(final URL url, final FXPresenter onLoad) {
    9.83 +        if (INSTANCE == null) {
    9.84 +            Executors.newFixedThreadPool(1).submit(new Runnable() {
    9.85 +                @Override
    9.86 +                public void run() {
    9.87 +                    try {
    9.88 +                        FXBrwsr.launch(FXBrwsr.class);
    9.89 +                    } catch (Throwable ex) {
    9.90 +                        ex.printStackTrace();
    9.91 +                    } finally {
    9.92 +                        FINISHED.countDown();
    9.93 +                    }
    9.94 +                }
    9.95 +            });
    9.96 +        }
    9.97 +        while (INSTANCE == null) {
    9.98 +            try {
    9.99 +                FXBrwsr.class.wait();
   9.100 +            } catch (InterruptedException ex) {
   9.101 +                // wait more
   9.102 +            }
   9.103 +        }
   9.104 +        if (!Platform.isFxApplicationThread()) {
   9.105 +            final WebView[] arr = {null};
   9.106 +            final CountDownLatch waitForResult = new CountDownLatch(1);
   9.107 +            Platform.runLater(new Runnable() {
   9.108 +                @Override
   9.109 +                public void run() {
   9.110 +                    arr[0] = INSTANCE.newView(url, onLoad);
   9.111 +                    waitForResult.countDown();
   9.112 +                }
   9.113 +            });
   9.114 +            for (;;) {
   9.115 +                try {
   9.116 +                    waitForResult.await();
   9.117 +                    break;
   9.118 +                } catch (InterruptedException ex) {
   9.119 +                    LOG.log(Level.INFO, null, ex);
   9.120 +                }
   9.121 +            }
   9.122 +            return arr[0];
   9.123 +        } else {
   9.124 +            return INSTANCE.newView(url, onLoad);
   9.125 +        }
   9.126 +    }
   9.127 +
   9.128 +    @Override
   9.129 +    public void start(Stage primaryStage) throws Exception {
   9.130 +        synchronized (FXBrwsr.class) {
   9.131 +            INSTANCE = this;
   9.132 +            FXBrwsr.class.notifyAll();
   9.133 +        }
   9.134 +        BorderPane r = new BorderPane();
   9.135 +        Scene scene = new Scene(r, 800, 600);
   9.136 +        primaryStage.setScene(scene);
   9.137 +        primaryStage.show();
   9.138 +        this.root = r;
   9.139 +    }
   9.140 +
   9.141 +    private WebView newView(final URL url, final FXPresenter onLoad) {
   9.142 +        final WebView view = new WebView();
   9.143 +        view.setContextMenuEnabled(false);
   9.144 +        view.getEngine().setOnAlert(new EventHandler<WebEvent<String>>() {
   9.145 +            @Override
   9.146 +            public void handle(WebEvent<String> t) {
   9.147 +                final Stage dialogStage = new Stage();
   9.148 +                dialogStage.initModality(Modality.WINDOW_MODAL);
   9.149 +                dialogStage.setTitle("Warning");
   9.150 +                final Button button = new Button("Close");
   9.151 +                final Text text = new Text(t.getData());
   9.152 +                VBox box = new VBox();
   9.153 +                box.setAlignment(Pos.CENTER);
   9.154 +                box.setSpacing(10);
   9.155 +                box.setPadding(new Insets(10));
   9.156 +                box.getChildren().addAll(text, button);
   9.157 +                dialogStage.setScene(new Scene(box));
   9.158 +                button.setCancelButton(true);
   9.159 +                button.setOnAction(new EventHandler<ActionEvent>() {
   9.160 +                    @Override
   9.161 +                    public void handle(ActionEvent t) {
   9.162 +                        dialogStage.close();
   9.163 +                    }
   9.164 +                });
   9.165 +                dialogStage.centerOnScreen();
   9.166 +                dialogStage.showAndWait();
   9.167 +            }
   9.168 +        });
   9.169 +        root.setCenter(view);
   9.170 +        final Worker<Void> w = view.getEngine().getLoadWorker();
   9.171 +        w.stateProperty().addListener(new ChangeListener<Worker.State>() {
   9.172 +            @Override
   9.173 +            public void changed(ObservableValue<? extends Worker.State> ov, Worker.State t, Worker.State newState) {
   9.174 +                if (newState.equals(Worker.State.SUCCEEDED)) {
   9.175 +                    onLoad.onPageLoad();
   9.176 +                }
   9.177 +                if (newState.equals(Worker.State.FAILED)) {
   9.178 +                    throw new IllegalStateException("Failed to load " + url);
   9.179 +                }
   9.180 +            }
   9.181 +        });
   9.182 +        return view;
   9.183 +    }
   9.184 +
   9.185 +    static void waitFinished() {
   9.186 +        for (;;) {
   9.187 +            try {
   9.188 +                FINISHED.await();
   9.189 +                break;
   9.190 +            } catch (InterruptedException ex) {
   9.191 +                LOG.log(Level.INFO, null, ex);
   9.192 +            }
   9.193 +        }
   9.194 +    }
   9.195 +    
   9.196 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java	Mon Dec 16 16:59:43 2013 +0100
    10.3 @@ -0,0 +1,134 @@
    10.4 +/**
    10.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    10.6 + *
    10.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    10.8 + *
    10.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   10.10 + * Other names may be trademarks of their respective owners.
   10.11 + *
   10.12 + * The contents of this file are subject to the terms of either the GNU
   10.13 + * General Public License Version 2 only ("GPL") or the Common
   10.14 + * Development and Distribution License("CDDL") (collectively, the
   10.15 + * "License"). You may not use this file except in compliance with the
   10.16 + * License. You can obtain a copy of the License at
   10.17 + * http://www.netbeans.org/cddl-gplv2.html
   10.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   10.19 + * specific language governing permissions and limitations under the
   10.20 + * License.  When distributing the software, include this License Header
   10.21 + * Notice in each file and include the License file at
   10.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   10.23 + * particular file as subject to the "Classpath" exception as provided
   10.24 + * by Oracle in the GPL Version 2 section of the License file that
   10.25 + * accompanied this code. If applicable, add the following below the
   10.26 + * License Header, with the fields enclosed by brackets [] replaced by
   10.27 + * your own identifying information:
   10.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   10.29 + *
   10.30 + * Contributor(s):
   10.31 + *
   10.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   10.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   10.34 + *
   10.35 + * If you wish your version of this file to be governed by only the CDDL
   10.36 + * or only the GPL Version 2, indicate your decision by adding
   10.37 + * "[Contributor] elects to include this software in this distribution
   10.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   10.39 + * single choice of license, a recipient has the option to distribute
   10.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   10.41 + * to extend the choice of license to its licensees as provided above.
   10.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   10.43 + * Version 2 license, then the option applies only if the new code is
   10.44 + * made subject to such option by the copyright holder.
   10.45 + */
   10.46 +package org.netbeans.html.boot.fx;
   10.47 +
   10.48 +import java.io.IOException;
   10.49 +import java.io.ObjectInputStream;
   10.50 +import java.io.ObjectOutputStream;
   10.51 +import java.net.InetAddress;
   10.52 +import java.net.Socket;
   10.53 +import java.nio.charset.StandardCharsets;
   10.54 +import java.util.logging.Level;
   10.55 +import java.util.logging.Logger;
   10.56 +import javafx.application.Platform;
   10.57 +import javafx.scene.web.WebEngine;
   10.58 +import javafx.util.Callback;
   10.59 +
   10.60 +/**
   10.61 + *
   10.62 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   10.63 + */
   10.64 +final class FXInspect implements Runnable {
   10.65 +    private static final Logger LOG = Logger.getLogger(FXInspect.class.getName());
   10.66 +    
   10.67 +    
   10.68 +    private final WebEngine engine;
   10.69 +    private final ObjectInputStream input;
   10.70 +    private Dbgr dbg;
   10.71 +    
   10.72 +    private FXInspect(WebEngine engine, int port) throws IOException {
   10.73 +        this.engine = engine;
   10.74 +        
   10.75 +        Socket socket = new Socket(InetAddress.getByName(null), port);
   10.76 +        ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
   10.77 +        this.input = new ObjectInputStream(socket.getInputStream());
   10.78 +        initializeDebugger(output);
   10.79 +    }
   10.80 +    
   10.81 +    static boolean initialize(WebEngine engine) {
   10.82 +        final int inspectPort = Integer.getInteger("netbeans.inspect.port", -1); // NOI18N
   10.83 +        if (inspectPort != -1) {
   10.84 +            try {
   10.85 +                FXInspect inspector = new FXInspect(engine, inspectPort);
   10.86 +                Thread t = new Thread(inspector, "FX<->NetBeans Inspector");
   10.87 +                t.start();
   10.88 +                return true;
   10.89 +            } catch (IOException ex) {
   10.90 +                LOG.log(Level.INFO, "Cannot connect to NetBeans IDE to port " + inspectPort, ex); // NOI18N
   10.91 +            }
   10.92 +        }
   10.93 +        return false;
   10.94 +    }
   10.95 +    
   10.96 +    private void initializeDebugger(final ObjectOutputStream output) {
   10.97 +        Platform.runLater(new Runnable() {
   10.98 +            @Override
   10.99 +            public void run() {
  10.100 +                dbg = new Dbgr(engine, new Callback<String,Void>() {
  10.101 +                    @Override
  10.102 +                    public Void call(String message) {
  10.103 +                        try {
  10.104 +                            byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
  10.105 +                            output.writeInt(bytes.length);
  10.106 +                            output.write(bytes);
  10.107 +                            output.flush();
  10.108 +                        } catch (IOException ioex) {
  10.109 +                            ioex.printStackTrace();
  10.110 +                        }
  10.111 +                        return null;
  10.112 +                    }
  10.113 +                });
  10.114 +            }
  10.115 +        });
  10.116 +    }
  10.117 +
  10.118 +    @Override
  10.119 +    public void run() {
  10.120 +        try {
  10.121 +            while (true) {
  10.122 +                int length = input.readInt();
  10.123 +                byte[] bytes = new byte[length];
  10.124 +                input.readFully(bytes);
  10.125 +                final String message = new String(bytes, StandardCharsets.UTF_8);
  10.126 +                Platform.runLater(new Runnable() {
  10.127 +                    @Override
  10.128 +                    public void run() {
  10.129 +                        dbg.sendMessage(message);
  10.130 +                    }
  10.131 +                });
  10.132 +            }
  10.133 +        } catch (IOException ex) {
  10.134 +            LOG.log(Level.WARNING, null, ex);
  10.135 +        }
  10.136 +    }
  10.137 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java	Mon Dec 16 16:59:43 2013 +0100
    11.3 @@ -0,0 +1,98 @@
    11.4 +/**
    11.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    11.6 + *
    11.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    11.8 + *
    11.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   11.10 + * Other names may be trademarks of their respective owners.
   11.11 + *
   11.12 + * The contents of this file are subject to the terms of either the GNU
   11.13 + * General Public License Version 2 only ("GPL") or the Common
   11.14 + * Development and Distribution License("CDDL") (collectively, the
   11.15 + * "License"). You may not use this file except in compliance with the
   11.16 + * License. You can obtain a copy of the License at
   11.17 + * http://www.netbeans.org/cddl-gplv2.html
   11.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   11.19 + * specific language governing permissions and limitations under the
   11.20 + * License.  When distributing the software, include this License Header
   11.21 + * Notice in each file and include the License file at
   11.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   11.23 + * particular file as subject to the "Classpath" exception as provided
   11.24 + * by Oracle in the GPL Version 2 section of the License file that
   11.25 + * accompanied this code. If applicable, add the following below the
   11.26 + * License Header, with the fields enclosed by brackets [] replaced by
   11.27 + * your own identifying information:
   11.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   11.29 + *
   11.30 + * Contributor(s):
   11.31 + *
   11.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   11.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   11.34 + *
   11.35 + * If you wish your version of this file to be governed by only the CDDL
   11.36 + * or only the GPL Version 2, indicate your decision by adding
   11.37 + * "[Contributor] elects to include this software in this distribution
   11.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   11.39 + * single choice of license, a recipient has the option to distribute
   11.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   11.41 + * to extend the choice of license to its licensees as provided above.
   11.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   11.43 + * Version 2 license, then the option applies only if the new code is
   11.44 + * made subject to such option by the copyright holder.
   11.45 + */
   11.46 +package org.netbeans.html.boot.fx;
   11.47 +
   11.48 +import java.io.BufferedReader;
   11.49 +import java.io.File;
   11.50 +import java.io.Reader;
   11.51 +import java.lang.reflect.Method;
   11.52 +import java.net.URL;
   11.53 +import java.net.URLClassLoader;
   11.54 +import java.util.ArrayList;
   11.55 +import java.util.Arrays;
   11.56 +import java.util.List;
   11.57 +import java.util.logging.Level;
   11.58 +import java.util.logging.Logger;
   11.59 +import javafx.application.Platform;
   11.60 +import javafx.scene.web.WebEngine;
   11.61 +import javafx.scene.web.WebView;
   11.62 +import net.java.html.boot.BrowserBuilder;
   11.63 +import netscape.javascript.JSObject;
   11.64 +import org.apidesign.html.boot.spi.Fn;
   11.65 +import org.openide.util.lookup.ServiceProvider;
   11.66 +
   11.67 +/** This is an implementation class, use {@link BrowserBuilder} API. Just
   11.68 + * include this JAR on classpath and the {@link BrowserBuilder} API will find
   11.69 + * this implementation automatically.
   11.70 + *
   11.71 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   11.72 + */
   11.73 +@ServiceProvider(service = Fn.Presenter.class)
   11.74 +public final class FXPresenter extends AbstractFXPresenter {
   11.75 +    static {
   11.76 +        try {
   11.77 +            try {
   11.78 +                Class<?> c = Class.forName("javafx.application.Platform");
   11.79 +                // OK, on classpath
   11.80 +            } catch (ClassNotFoundException classNotFoundException) {
   11.81 +                Method m = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
   11.82 +                m.setAccessible(true);
   11.83 +                File f = new File(System.getProperty("java.home"), "lib/jfxrt.jar");
   11.84 +                if (f.exists()) {
   11.85 +                    URL l = f.toURI().toURL();
   11.86 +                    m.invoke(ClassLoader.getSystemClassLoader(), l);
   11.87 +                }
   11.88 +            }
   11.89 +        } catch (Exception ex) {
   11.90 +            throw new LinkageError("Can't add jfxrt.jar on the classpath", ex);
   11.91 +        }
   11.92 +    }
   11.93 +
   11.94 +    protected void waitFinished() {
   11.95 +        FXBrwsr.waitFinished();
   11.96 +    }
   11.97 +
   11.98 +    protected WebView findView(final URL resource) {
   11.99 +        return FXBrwsr.findWebView(resource, this);
  11.100 +    }
  11.101 +}
    12.1 --- a/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java	Mon Dec 16 15:48:09 2013 +0100
    12.2 +++ b/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java	Mon Dec 16 16:59:43 2013 +0100
    12.3 @@ -95,7 +95,7 @@
    12.4              }
    12.5              
    12.6              private void doTest() throws Throwable {
    12.7 -                URL u = FXBrowsersOnResourceTest.class.getResource("/org/apidesign/html/boot/fx/empty.html");
    12.8 +                URL u = FXBrowsersOnResourceTest.class.getResource("/org/netbeans/html/boot/fx/empty.html");
    12.9                  assertNotNull(u, "URL found");
   12.10                  FXBrowsers.load(App.getV1(), u, OnPages.class, "first");
   12.11                  
   12.12 @@ -131,7 +131,7 @@
   12.13              
   12.14              assertEquals(increment(), 1, "Now it is one");
   12.15              
   12.16 -            URL u = FXBrowsersOnResourceTest.class.getResource("/org/apidesign/html/boot/fx/empty.html");
   12.17 +            URL u = FXBrowsersOnResourceTest.class.getResource("/org/netbeans/html/boot/fx/empty.html");
   12.18              assertNotNull(u, "URL found");
   12.19              FXBrowsers.load(App.getV2(), u, OnPages.class, "second", "Hello");
   12.20              
    13.1 --- a/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersTest.java	Mon Dec 16 15:48:09 2013 +0100
    13.2 +++ b/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersTest.java	Mon Dec 16 16:59:43 2013 +0100
    13.3 @@ -95,7 +95,7 @@
    13.4              }
    13.5              
    13.6              private void doTest() throws Throwable {
    13.7 -                URL u = FXBrowsersTest.class.getResource("/org/apidesign/html/boot/fx/empty.html");
    13.8 +                URL u = FXBrowsersTest.class.getResource("/org/netbeans/html/boot/fx/empty.html");
    13.9                  assertNotNull(u, "URL found");
   13.10                  FXBrowsers.load(App.getV1(), u, OnPages.class, "first");
   13.11                  
   13.12 @@ -130,7 +130,7 @@
   13.13              
   13.14              assertEquals(increment(), 1, "Now it is one");
   13.15              
   13.16 -            URL u = FXBrowsersTest.class.getResource("/org/apidesign/html/boot/fx/empty.html");
   13.17 +            URL u = FXBrowsersTest.class.getResource("/org/netbeans/html/boot/fx/empty.html");
   13.18              assertNotNull(u, "URL found");
   13.19              FXBrowsers.load(App.getV2(), u, OnPages.class, "second", "Hello");
   13.20              
    14.1 --- a/boot-fx/src/test/java/org/apidesign/html/boot/fx/BootstrapTest.java	Mon Dec 16 15:48:09 2013 +0100
    14.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.3 @@ -1,109 +0,0 @@
    14.4 -/**
    14.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    14.6 - *
    14.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    14.8 - *
    14.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   14.10 - * Other names may be trademarks of their respective owners.
   14.11 - *
   14.12 - * The contents of this file are subject to the terms of either the GNU
   14.13 - * General Public License Version 2 only ("GPL") or the Common
   14.14 - * Development and Distribution License("CDDL") (collectively, the
   14.15 - * "License"). You may not use this file except in compliance with the
   14.16 - * License. You can obtain a copy of the License at
   14.17 - * http://www.netbeans.org/cddl-gplv2.html
   14.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   14.19 - * specific language governing permissions and limitations under the
   14.20 - * License.  When distributing the software, include this License Header
   14.21 - * Notice in each file and include the License file at
   14.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   14.23 - * particular file as subject to the "Classpath" exception as provided
   14.24 - * by Oracle in the GPL Version 2 section of the License file that
   14.25 - * accompanied this code. If applicable, add the following below the
   14.26 - * License Header, with the fields enclosed by brackets [] replaced by
   14.27 - * your own identifying information:
   14.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   14.29 - *
   14.30 - * Contributor(s):
   14.31 - *
   14.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   14.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   14.34 - *
   14.35 - * If you wish your version of this file to be governed by only the CDDL
   14.36 - * or only the GPL Version 2, indicate your decision by adding
   14.37 - * "[Contributor] elects to include this software in this distribution
   14.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   14.39 - * single choice of license, a recipient has the option to distribute
   14.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   14.41 - * to extend the choice of license to its licensees as provided above.
   14.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   14.43 - * Version 2 license, then the option applies only if the new code is
   14.44 - * made subject to such option by the copyright holder.
   14.45 - */
   14.46 -package org.apidesign.html.boot.fx;
   14.47 -
   14.48 -import java.lang.annotation.Annotation;
   14.49 -import java.lang.reflect.Method;
   14.50 -import java.util.ArrayList;
   14.51 -import java.util.List;
   14.52 -import java.util.concurrent.Executors;
   14.53 -import net.java.html.boot.BrowserBuilder;
   14.54 -import org.apidesign.html.boot.impl.FnContext;
   14.55 -import org.apidesign.html.boot.spi.Fn;
   14.56 -import org.testng.annotations.Factory;
   14.57 -import org.testng.annotations.Test;
   14.58 -
   14.59 -/**
   14.60 - *
   14.61 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   14.62 - */
   14.63 -public class BootstrapTest {
   14.64 -    private static Class<?> browserClass;
   14.65 -    private static Fn.Presenter browserPresenter;
   14.66 -    
   14.67 -    public BootstrapTest() {
   14.68 -    }
   14.69 -
   14.70 -    @Factory public static Object[] compatibilityTests() throws Exception {
   14.71 -        final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(BootstrapTest.class).
   14.72 -            loadPage("empty.html").
   14.73 -            invoke("initialized");
   14.74 -
   14.75 -        Executors.newSingleThreadExecutor().submit(new Runnable() {
   14.76 -            @Override
   14.77 -            public void run() {
   14.78 -                bb.showAndWait();
   14.79 -            }
   14.80 -        });
   14.81 -
   14.82 -        List<Object> res = new ArrayList<Object>();
   14.83 -        Class<? extends Annotation> test = 
   14.84 -            loadClass().getClassLoader().loadClass(Test.class.getName()).
   14.85 -            asSubclass(Annotation.class);
   14.86 -        for (Method m : loadClass().getMethods()) {
   14.87 -            if (m.getAnnotation(test) != null) {
   14.88 -                res.add(new KOFx(browserPresenter, m));
   14.89 -            }
   14.90 -        }
   14.91 -        return res.toArray();
   14.92 -    }
   14.93 -
   14.94 -    static synchronized Class<?> loadClass() throws InterruptedException {
   14.95 -        while (browserClass == null) {
   14.96 -            BootstrapTest.class.wait();
   14.97 -        }
   14.98 -        return browserClass;
   14.99 -    }
  14.100 -    
  14.101 -    public static synchronized void ready(Class<?> browserCls) throws Exception {
  14.102 -        browserClass = browserCls;
  14.103 -        browserPresenter = FnContext.currentPresenter();
  14.104 -        BootstrapTest.class.notifyAll();
  14.105 -    }
  14.106 -    
  14.107 -    public static void initialized() throws Exception {
  14.108 -        Class<?> classpathClass = ClassLoader.getSystemClassLoader().loadClass(BootstrapTest.class.getName());
  14.109 -        Method m = classpathClass.getMethod("ready", Class.class);
  14.110 -        m.invoke(null, FXPresenterTst.class);
  14.111 -    }
  14.112 -}
    15.1 --- a/boot-fx/src/test/java/org/apidesign/html/boot/fx/FXPresenterTst.java	Mon Dec 16 15:48:09 2013 +0100
    15.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.3 @@ -1,71 +0,0 @@
    15.4 -/**
    15.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    15.6 - *
    15.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    15.8 - *
    15.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   15.10 - * Other names may be trademarks of their respective owners.
   15.11 - *
   15.12 - * The contents of this file are subject to the terms of either the GNU
   15.13 - * General Public License Version 2 only ("GPL") or the Common
   15.14 - * Development and Distribution License("CDDL") (collectively, the
   15.15 - * "License"). You may not use this file except in compliance with the
   15.16 - * License. You can obtain a copy of the License at
   15.17 - * http://www.netbeans.org/cddl-gplv2.html
   15.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   15.19 - * specific language governing permissions and limitations under the
   15.20 - * License.  When distributing the software, include this License Header
   15.21 - * Notice in each file and include the License file at
   15.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   15.23 - * particular file as subject to the "Classpath" exception as provided
   15.24 - * by Oracle in the GPL Version 2 section of the License file that
   15.25 - * accompanied this code. If applicable, add the following below the
   15.26 - * License Header, with the fields enclosed by brackets [] replaced by
   15.27 - * your own identifying information:
   15.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   15.29 - *
   15.30 - * Contributor(s):
   15.31 - *
   15.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   15.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   15.34 - *
   15.35 - * If you wish your version of this file to be governed by only the CDDL
   15.36 - * or only the GPL Version 2, indicate your decision by adding
   15.37 - * "[Contributor] elects to include this software in this distribution
   15.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   15.39 - * single choice of license, a recipient has the option to distribute
   15.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   15.41 - * to extend the choice of license to its licensees as provided above.
   15.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   15.43 - * Version 2 license, then the option applies only if the new code is
   15.44 - * made subject to such option by the copyright holder.
   15.45 - */
   15.46 -package org.apidesign.html.boot.fx;
   15.47 -
   15.48 -import net.java.html.js.JavaScriptBody;
   15.49 -import static org.testng.Assert.*;
   15.50 -import org.testng.annotations.Test;
   15.51 -
   15.52 -/**
   15.53 - *
   15.54 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   15.55 - */
   15.56 -public class FXPresenterTst {
   15.57 -    @Test public void showClassLoader() {
   15.58 -        R run = new R();
   15.59 -        callback(run);
   15.60 -        assertEquals(run.cnt, 1, "Can call even private implementation classes");
   15.61 -    }
   15.62 -    
   15.63 -    @JavaScriptBody(args = { "r" }, javacall = true, body = "r.@java.lang.Runnable::run()();")
   15.64 -    private static native void callback(Runnable r);
   15.65 -
   15.66 -    private static class R implements Runnable {
   15.67 -        int cnt;
   15.68 -
   15.69 -        @Override
   15.70 -        public void run() {
   15.71 -            cnt++;
   15.72 -        }
   15.73 -    }
   15.74 -}
    16.1 --- a/boot-fx/src/test/java/org/apidesign/html/boot/fx/KOFx.java	Mon Dec 16 15:48:09 2013 +0100
    16.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.3 @@ -1,125 +0,0 @@
    16.4 -/**
    16.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    16.6 - *
    16.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    16.8 - *
    16.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   16.10 - * Other names may be trademarks of their respective owners.
   16.11 - *
   16.12 - * The contents of this file are subject to the terms of either the GNU
   16.13 - * General Public License Version 2 only ("GPL") or the Common
   16.14 - * Development and Distribution License("CDDL") (collectively, the
   16.15 - * "License"). You may not use this file except in compliance with the
   16.16 - * License. You can obtain a copy of the License at
   16.17 - * http://www.netbeans.org/cddl-gplv2.html
   16.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   16.19 - * specific language governing permissions and limitations under the
   16.20 - * License.  When distributing the software, include this License Header
   16.21 - * Notice in each file and include the License file at
   16.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   16.23 - * particular file as subject to the "Classpath" exception as provided
   16.24 - * by Oracle in the GPL Version 2 section of the License file that
   16.25 - * accompanied this code. If applicable, add the following below the
   16.26 - * License Header, with the fields enclosed by brackets [] replaced by
   16.27 - * your own identifying information:
   16.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   16.29 - *
   16.30 - * Contributor(s):
   16.31 - *
   16.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   16.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   16.34 - *
   16.35 - * If you wish your version of this file to be governed by only the CDDL
   16.36 - * or only the GPL Version 2, indicate your decision by adding
   16.37 - * "[Contributor] elects to include this software in this distribution
   16.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   16.39 - * single choice of license, a recipient has the option to distribute
   16.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   16.41 - * to extend the choice of license to its licensees as provided above.
   16.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   16.43 - * Version 2 license, then the option applies only if the new code is
   16.44 - * made subject to such option by the copyright holder.
   16.45 - */
   16.46 -package org.apidesign.html.boot.fx;
   16.47 -
   16.48 -import java.lang.reflect.InvocationTargetException;
   16.49 -import java.lang.reflect.Method;
   16.50 -import javafx.application.Platform;
   16.51 -import org.apidesign.html.boot.impl.FnContext;
   16.52 -import org.apidesign.html.boot.spi.Fn;
   16.53 -import org.testng.IHookCallBack;
   16.54 -import org.testng.IHookable;
   16.55 -import org.testng.ITest;
   16.56 -import org.testng.ITestResult;
   16.57 -import org.testng.annotations.Test;
   16.58 -
   16.59 -/**
   16.60 - *
   16.61 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   16.62 - */
   16.63 -public final class KOFx implements ITest, IHookable, Runnable {
   16.64 -    private final Fn.Presenter p;
   16.65 -    private final Method m;
   16.66 -    private Object result;
   16.67 -    private Object inst;
   16.68 -
   16.69 -    KOFx(Fn.Presenter p, Method m) {
   16.70 -        this.p = p;
   16.71 -        this.m = m;
   16.72 -    }
   16.73 -
   16.74 -    @Override
   16.75 -    public String getTestName() {
   16.76 -        return m.getName();
   16.77 -    }
   16.78 -
   16.79 -    @Test
   16.80 -    public synchronized void executeTest() throws Exception {
   16.81 -        if (result == null) {
   16.82 -            Platform.runLater(this);
   16.83 -            wait();
   16.84 -        }
   16.85 -        if (result instanceof Exception) {
   16.86 -            throw (Exception)result;
   16.87 -        }
   16.88 -        if (result instanceof Error) {
   16.89 -            throw (Error)result;
   16.90 -        }
   16.91 -    }
   16.92 -
   16.93 -    @Override
   16.94 -    public synchronized void run() {
   16.95 -        boolean notify = true;
   16.96 -        try {
   16.97 -            FnContext.currentPresenter(p);
   16.98 -            if (inst == null) {
   16.99 -                inst = m.getDeclaringClass().newInstance();
  16.100 -            }
  16.101 -            result = m.invoke(inst);
  16.102 -            if (result == null) {
  16.103 -                result = this;
  16.104 -            }
  16.105 -        } catch (InvocationTargetException ex) {
  16.106 -            Throwable r = ex.getTargetException();
  16.107 -            if (r instanceof InterruptedException) {
  16.108 -                notify = false;
  16.109 -                Platform.runLater(this);
  16.110 -                return;
  16.111 -            }
  16.112 -            result = r;
  16.113 -        } catch (Exception ex) {
  16.114 -            result = ex;
  16.115 -        } finally {
  16.116 -            if (notify) {
  16.117 -                notifyAll();
  16.118 -            }
  16.119 -            FnContext.currentPresenter(null);
  16.120 -        }
  16.121 -    }
  16.122 -
  16.123 -    @Override
  16.124 -    public void run(IHookCallBack ihcb, ITestResult itr) {
  16.125 -        ihcb.runTestMethod(itr);
  16.126 -    }
  16.127 -    
  16.128 -}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/BootstrapTest.java	Mon Dec 16 16:59:43 2013 +0100
    17.3 @@ -0,0 +1,109 @@
    17.4 +/**
    17.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    17.6 + *
    17.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    17.8 + *
    17.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   17.10 + * Other names may be trademarks of their respective owners.
   17.11 + *
   17.12 + * The contents of this file are subject to the terms of either the GNU
   17.13 + * General Public License Version 2 only ("GPL") or the Common
   17.14 + * Development and Distribution License("CDDL") (collectively, the
   17.15 + * "License"). You may not use this file except in compliance with the
   17.16 + * License. You can obtain a copy of the License at
   17.17 + * http://www.netbeans.org/cddl-gplv2.html
   17.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   17.19 + * specific language governing permissions and limitations under the
   17.20 + * License.  When distributing the software, include this License Header
   17.21 + * Notice in each file and include the License file at
   17.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   17.23 + * particular file as subject to the "Classpath" exception as provided
   17.24 + * by Oracle in the GPL Version 2 section of the License file that
   17.25 + * accompanied this code. If applicable, add the following below the
   17.26 + * License Header, with the fields enclosed by brackets [] replaced by
   17.27 + * your own identifying information:
   17.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   17.29 + *
   17.30 + * Contributor(s):
   17.31 + *
   17.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   17.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   17.34 + *
   17.35 + * If you wish your version of this file to be governed by only the CDDL
   17.36 + * or only the GPL Version 2, indicate your decision by adding
   17.37 + * "[Contributor] elects to include this software in this distribution
   17.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   17.39 + * single choice of license, a recipient has the option to distribute
   17.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   17.41 + * to extend the choice of license to its licensees as provided above.
   17.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   17.43 + * Version 2 license, then the option applies only if the new code is
   17.44 + * made subject to such option by the copyright holder.
   17.45 + */
   17.46 +package org.netbeans.html.boot.fx;
   17.47 +
   17.48 +import java.lang.annotation.Annotation;
   17.49 +import java.lang.reflect.Method;
   17.50 +import java.util.ArrayList;
   17.51 +import java.util.List;
   17.52 +import java.util.concurrent.Executors;
   17.53 +import net.java.html.boot.BrowserBuilder;
   17.54 +import org.netbeans.html.boot.impl.FnContext;
   17.55 +import org.apidesign.html.boot.spi.Fn;
   17.56 +import org.testng.annotations.Factory;
   17.57 +import org.testng.annotations.Test;
   17.58 +
   17.59 +/**
   17.60 + *
   17.61 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   17.62 + */
   17.63 +public class BootstrapTest {
   17.64 +    private static Class<?> browserClass;
   17.65 +    private static Fn.Presenter browserPresenter;
   17.66 +    
   17.67 +    public BootstrapTest() {
   17.68 +    }
   17.69 +
   17.70 +    @Factory public static Object[] compatibilityTests() throws Exception {
   17.71 +        final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(BootstrapTest.class).
   17.72 +            loadPage("empty.html").
   17.73 +            invoke("initialized");
   17.74 +
   17.75 +        Executors.newSingleThreadExecutor().submit(new Runnable() {
   17.76 +            @Override
   17.77 +            public void run() {
   17.78 +                bb.showAndWait();
   17.79 +            }
   17.80 +        });
   17.81 +
   17.82 +        List<Object> res = new ArrayList<Object>();
   17.83 +        Class<? extends Annotation> test = 
   17.84 +            loadClass().getClassLoader().loadClass(Test.class.getName()).
   17.85 +            asSubclass(Annotation.class);
   17.86 +        for (Method m : loadClass().getMethods()) {
   17.87 +            if (m.getAnnotation(test) != null) {
   17.88 +                res.add(new KOFx(browserPresenter, m));
   17.89 +            }
   17.90 +        }
   17.91 +        return res.toArray();
   17.92 +    }
   17.93 +
   17.94 +    static synchronized Class<?> loadClass() throws InterruptedException {
   17.95 +        while (browserClass == null) {
   17.96 +            BootstrapTest.class.wait();
   17.97 +        }
   17.98 +        return browserClass;
   17.99 +    }
  17.100 +    
  17.101 +    public static synchronized void ready(Class<?> browserCls) throws Exception {
  17.102 +        browserClass = browserCls;
  17.103 +        browserPresenter = FnContext.currentPresenter();
  17.104 +        BootstrapTest.class.notifyAll();
  17.105 +    }
  17.106 +    
  17.107 +    public static void initialized() throws Exception {
  17.108 +        Class<?> classpathClass = ClassLoader.getSystemClassLoader().loadClass(BootstrapTest.class.getName());
  17.109 +        Method m = classpathClass.getMethod("ready", Class.class);
  17.110 +        m.invoke(null, FXPresenterTst.class);
  17.111 +    }
  17.112 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXPresenterTst.java	Mon Dec 16 16:59:43 2013 +0100
    18.3 @@ -0,0 +1,71 @@
    18.4 +/**
    18.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    18.6 + *
    18.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    18.8 + *
    18.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   18.10 + * Other names may be trademarks of their respective owners.
   18.11 + *
   18.12 + * The contents of this file are subject to the terms of either the GNU
   18.13 + * General Public License Version 2 only ("GPL") or the Common
   18.14 + * Development and Distribution License("CDDL") (collectively, the
   18.15 + * "License"). You may not use this file except in compliance with the
   18.16 + * License. You can obtain a copy of the License at
   18.17 + * http://www.netbeans.org/cddl-gplv2.html
   18.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   18.19 + * specific language governing permissions and limitations under the
   18.20 + * License.  When distributing the software, include this License Header
   18.21 + * Notice in each file and include the License file at
   18.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   18.23 + * particular file as subject to the "Classpath" exception as provided
   18.24 + * by Oracle in the GPL Version 2 section of the License file that
   18.25 + * accompanied this code. If applicable, add the following below the
   18.26 + * License Header, with the fields enclosed by brackets [] replaced by
   18.27 + * your own identifying information:
   18.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   18.29 + *
   18.30 + * Contributor(s):
   18.31 + *
   18.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   18.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   18.34 + *
   18.35 + * If you wish your version of this file to be governed by only the CDDL
   18.36 + * or only the GPL Version 2, indicate your decision by adding
   18.37 + * "[Contributor] elects to include this software in this distribution
   18.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   18.39 + * single choice of license, a recipient has the option to distribute
   18.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   18.41 + * to extend the choice of license to its licensees as provided above.
   18.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   18.43 + * Version 2 license, then the option applies only if the new code is
   18.44 + * made subject to such option by the copyright holder.
   18.45 + */
   18.46 +package org.netbeans.html.boot.fx;
   18.47 +
   18.48 +import net.java.html.js.JavaScriptBody;
   18.49 +import static org.testng.Assert.*;
   18.50 +import org.testng.annotations.Test;
   18.51 +
   18.52 +/**
   18.53 + *
   18.54 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   18.55 + */
   18.56 +public class FXPresenterTst {
   18.57 +    @Test public void showClassLoader() {
   18.58 +        R run = new R();
   18.59 +        callback(run);
   18.60 +        assertEquals(run.cnt, 1, "Can call even private implementation classes");
   18.61 +    }
   18.62 +    
   18.63 +    @JavaScriptBody(args = { "r" }, javacall = true, body = "r.@java.lang.Runnable::run()();")
   18.64 +    private static native void callback(Runnable r);
   18.65 +
   18.66 +    private static class R implements Runnable {
   18.67 +        int cnt;
   18.68 +
   18.69 +        @Override
   18.70 +        public void run() {
   18.71 +            cnt++;
   18.72 +        }
   18.73 +    }
   18.74 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/KOFx.java	Mon Dec 16 16:59:43 2013 +0100
    19.3 @@ -0,0 +1,125 @@
    19.4 +/**
    19.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    19.6 + *
    19.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    19.8 + *
    19.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   19.10 + * Other names may be trademarks of their respective owners.
   19.11 + *
   19.12 + * The contents of this file are subject to the terms of either the GNU
   19.13 + * General Public License Version 2 only ("GPL") or the Common
   19.14 + * Development and Distribution License("CDDL") (collectively, the
   19.15 + * "License"). You may not use this file except in compliance with the
   19.16 + * License. You can obtain a copy of the License at
   19.17 + * http://www.netbeans.org/cddl-gplv2.html
   19.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   19.19 + * specific language governing permissions and limitations under the
   19.20 + * License.  When distributing the software, include this License Header
   19.21 + * Notice in each file and include the License file at
   19.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   19.23 + * particular file as subject to the "Classpath" exception as provided
   19.24 + * by Oracle in the GPL Version 2 section of the License file that
   19.25 + * accompanied this code. If applicable, add the following below the
   19.26 + * License Header, with the fields enclosed by brackets [] replaced by
   19.27 + * your own identifying information:
   19.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   19.29 + *
   19.30 + * Contributor(s):
   19.31 + *
   19.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   19.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   19.34 + *
   19.35 + * If you wish your version of this file to be governed by only the CDDL
   19.36 + * or only the GPL Version 2, indicate your decision by adding
   19.37 + * "[Contributor] elects to include this software in this distribution
   19.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   19.39 + * single choice of license, a recipient has the option to distribute
   19.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   19.41 + * to extend the choice of license to its licensees as provided above.
   19.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   19.43 + * Version 2 license, then the option applies only if the new code is
   19.44 + * made subject to such option by the copyright holder.
   19.45 + */
   19.46 +package org.netbeans.html.boot.fx;
   19.47 +
   19.48 +import java.lang.reflect.InvocationTargetException;
   19.49 +import java.lang.reflect.Method;
   19.50 +import javafx.application.Platform;
   19.51 +import org.netbeans.html.boot.impl.FnContext;
   19.52 +import org.apidesign.html.boot.spi.Fn;
   19.53 +import org.testng.IHookCallBack;
   19.54 +import org.testng.IHookable;
   19.55 +import org.testng.ITest;
   19.56 +import org.testng.ITestResult;
   19.57 +import org.testng.annotations.Test;
   19.58 +
   19.59 +/**
   19.60 + *
   19.61 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   19.62 + */
   19.63 +public final class KOFx implements ITest, IHookable, Runnable {
   19.64 +    private final Fn.Presenter p;
   19.65 +    private final Method m;
   19.66 +    private Object result;
   19.67 +    private Object inst;
   19.68 +
   19.69 +    KOFx(Fn.Presenter p, Method m) {
   19.70 +        this.p = p;
   19.71 +        this.m = m;
   19.72 +    }
   19.73 +
   19.74 +    @Override
   19.75 +    public String getTestName() {
   19.76 +        return m.getName();
   19.77 +    }
   19.78 +
   19.79 +    @Test
   19.80 +    public synchronized void executeTest() throws Exception {
   19.81 +        if (result == null) {
   19.82 +            Platform.runLater(this);
   19.83 +            wait();
   19.84 +        }
   19.85 +        if (result instanceof Exception) {
   19.86 +            throw (Exception)result;
   19.87 +        }
   19.88 +        if (result instanceof Error) {
   19.89 +            throw (Error)result;
   19.90 +        }
   19.91 +    }
   19.92 +
   19.93 +    @Override
   19.94 +    public synchronized void run() {
   19.95 +        boolean notify = true;
   19.96 +        try {
   19.97 +            FnContext.currentPresenter(p);
   19.98 +            if (inst == null) {
   19.99 +                inst = m.getDeclaringClass().newInstance();
  19.100 +            }
  19.101 +            result = m.invoke(inst);
  19.102 +            if (result == null) {
  19.103 +                result = this;
  19.104 +            }
  19.105 +        } catch (InvocationTargetException ex) {
  19.106 +            Throwable r = ex.getTargetException();
  19.107 +            if (r instanceof InterruptedException) {
  19.108 +                notify = false;
  19.109 +                Platform.runLater(this);
  19.110 +                return;
  19.111 +            }
  19.112 +            result = r;
  19.113 +        } catch (Exception ex) {
  19.114 +            result = ex;
  19.115 +        } finally {
  19.116 +            if (notify) {
  19.117 +                notifyAll();
  19.118 +            }
  19.119 +            FnContext.currentPresenter(null);
  19.120 +        }
  19.121 +    }
  19.122 +
  19.123 +    @Override
  19.124 +    public void run(IHookCallBack ihcb, ITestResult itr) {
  19.125 +        ihcb.runTestMethod(itr);
  19.126 +    }
  19.127 +    
  19.128 +}
    20.1 --- a/boot-fx/src/test/resources/org/apidesign/html/boot/fx/empty.html	Mon Dec 16 15:48:09 2013 +0100
    20.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.3 @@ -1,55 +0,0 @@
    20.4 -<!--
    20.5 -
    20.6 -    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    20.7 -
    20.8 -    Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    20.9 -
   20.10 -    Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   20.11 -    Other names may be trademarks of their respective owners.
   20.12 -
   20.13 -    The contents of this file are subject to the terms of either the GNU
   20.14 -    General Public License Version 2 only ("GPL") or the Common
   20.15 -    Development and Distribution License("CDDL") (collectively, the
   20.16 -    "License"). You may not use this file except in compliance with the
   20.17 -    License. You can obtain a copy of the License at
   20.18 -    http://www.netbeans.org/cddl-gplv2.html
   20.19 -    or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   20.20 -    specific language governing permissions and limitations under the
   20.21 -    License.  When distributing the software, include this License Header
   20.22 -    Notice in each file and include the License file at
   20.23 -    nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   20.24 -    particular file as subject to the "Classpath" exception as provided
   20.25 -    by Oracle in the GPL Version 2 section of the License file that
   20.26 -    accompanied this code. If applicable, add the following below the
   20.27 -    License Header, with the fields enclosed by brackets [] replaced by
   20.28 -    your own identifying information:
   20.29 -    "Portions Copyrighted [year] [name of copyright owner]"
   20.30 -
   20.31 -    Contributor(s):
   20.32 -
   20.33 -    The Original Software is NetBeans. The Initial Developer of the Original
   20.34 -    Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   20.35 -
   20.36 -    If you wish your version of this file to be governed by only the CDDL
   20.37 -    or only the GPL Version 2, indicate your decision by adding
   20.38 -    "[Contributor] elects to include this software in this distribution
   20.39 -    under the [CDDL or GPL Version 2] license." If you do not indicate a
   20.40 -    single choice of license, a recipient has the option to distribute
   20.41 -    your version of this file under either the CDDL, the GPL Version 2 or
   20.42 -    to extend the choice of license to its licensees as provided above.
   20.43 -    However, if you add GPL Version 2 code and therefore, elected the GPL
   20.44 -    Version 2 license, then the option applies only if the new code is
   20.45 -    made subject to such option by the copyright holder.
   20.46 -
   20.47 --->
   20.48 -<!DOCTYPE html>
   20.49 -<html>
   20.50 -    <head>
   20.51 -        <title>FX Presenter Harness</title>
   20.52 -        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
   20.53 -        <meta name="viewport" content="width=device-width">
   20.54 -    </head>
   20.55 -    <body>
   20.56 -        <div>FX Presenter Harness</div>
   20.57 -    </body>
   20.58 -</html>
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/boot-fx/src/test/resources/org/netbeans/html/boot/fx/empty.html	Mon Dec 16 16:59:43 2013 +0100
    21.3 @@ -0,0 +1,55 @@
    21.4 +<!--
    21.5 +
    21.6 +    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    21.7 +
    21.8 +    Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    21.9 +
   21.10 +    Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   21.11 +    Other names may be trademarks of their respective owners.
   21.12 +
   21.13 +    The contents of this file are subject to the terms of either the GNU
   21.14 +    General Public License Version 2 only ("GPL") or the Common
   21.15 +    Development and Distribution License("CDDL") (collectively, the
   21.16 +    "License"). You may not use this file except in compliance with the
   21.17 +    License. You can obtain a copy of the License at
   21.18 +    http://www.netbeans.org/cddl-gplv2.html
   21.19 +    or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   21.20 +    specific language governing permissions and limitations under the
   21.21 +    License.  When distributing the software, include this License Header
   21.22 +    Notice in each file and include the License file at
   21.23 +    nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   21.24 +    particular file as subject to the "Classpath" exception as provided
   21.25 +    by Oracle in the GPL Version 2 section of the License file that
   21.26 +    accompanied this code. If applicable, add the following below the
   21.27 +    License Header, with the fields enclosed by brackets [] replaced by
   21.28 +    your own identifying information:
   21.29 +    "Portions Copyrighted [year] [name of copyright owner]"
   21.30 +
   21.31 +    Contributor(s):
   21.32 +
   21.33 +    The Original Software is NetBeans. The Initial Developer of the Original
   21.34 +    Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   21.35 +
   21.36 +    If you wish your version of this file to be governed by only the CDDL
   21.37 +    or only the GPL Version 2, indicate your decision by adding
   21.38 +    "[Contributor] elects to include this software in this distribution
   21.39 +    under the [CDDL or GPL Version 2] license." If you do not indicate a
   21.40 +    single choice of license, a recipient has the option to distribute
   21.41 +    your version of this file under either the CDDL, the GPL Version 2 or
   21.42 +    to extend the choice of license to its licensees as provided above.
   21.43 +    However, if you add GPL Version 2 code and therefore, elected the GPL
   21.44 +    Version 2 license, then the option applies only if the new code is
   21.45 +    made subject to such option by the copyright holder.
   21.46 +
   21.47 +-->
   21.48 +<!DOCTYPE html>
   21.49 +<html>
   21.50 +    <head>
   21.51 +        <title>FX Presenter Harness</title>
   21.52 +        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
   21.53 +        <meta name="viewport" content="width=device-width">
   21.54 +    </head>
   21.55 +    <body>
   21.56 +        <div>FX Presenter Harness</div>
   21.57 +    </body>
   21.58 +</html>
    22.1 --- a/boot/src/main/java/net/java/html/boot/BrowserBuilder.java	Mon Dec 16 15:48:09 2013 +0100
    22.2 +++ b/boot/src/main/java/net/java/html/boot/BrowserBuilder.java	Mon Dec 16 16:59:43 2013 +0100
    22.3 @@ -54,10 +54,10 @@
    22.4  import java.util.logging.Level;
    22.5  import java.util.logging.Logger;
    22.6  import net.java.html.js.JavaScriptBody;
    22.7 -import org.apidesign.html.boot.impl.FnUtils;
    22.8 +import org.netbeans.html.boot.impl.FnUtils;
    22.9  import org.apidesign.html.boot.spi.Fn;
   22.10 -import org.apidesign.html.boot.impl.FindResources;
   22.11 -import org.apidesign.html.boot.impl.FnContext;
   22.12 +import org.netbeans.html.boot.impl.FindResources;
   22.13 +import org.netbeans.html.boot.impl.FnContext;
   22.14  
   22.15  /** Use this builder to launch your Java/HTML based application. Typical
   22.16   * usage in a main method of your application looks like this: 
    23.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/FindResources.java	Mon Dec 16 15:48:09 2013 +0100
    23.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.3 @@ -1,56 +0,0 @@
    23.4 -/**
    23.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    23.6 - *
    23.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    23.8 - *
    23.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   23.10 - * Other names may be trademarks of their respective owners.
   23.11 - *
   23.12 - * The contents of this file are subject to the terms of either the GNU
   23.13 - * General Public License Version 2 only ("GPL") or the Common
   23.14 - * Development and Distribution License("CDDL") (collectively, the
   23.15 - * "License"). You may not use this file except in compliance with the
   23.16 - * License. You can obtain a copy of the License at
   23.17 - * http://www.netbeans.org/cddl-gplv2.html
   23.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   23.19 - * specific language governing permissions and limitations under the
   23.20 - * License.  When distributing the software, include this License Header
   23.21 - * Notice in each file and include the License file at
   23.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   23.23 - * particular file as subject to the "Classpath" exception as provided
   23.24 - * by Oracle in the GPL Version 2 section of the License file that
   23.25 - * accompanied this code. If applicable, add the following below the
   23.26 - * License Header, with the fields enclosed by brackets [] replaced by
   23.27 - * your own identifying information:
   23.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   23.29 - *
   23.30 - * Contributor(s):
   23.31 - *
   23.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   23.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   23.34 - *
   23.35 - * If you wish your version of this file to be governed by only the CDDL
   23.36 - * or only the GPL Version 2, indicate your decision by adding
   23.37 - * "[Contributor] elects to include this software in this distribution
   23.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   23.39 - * single choice of license, a recipient has the option to distribute
   23.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   23.41 - * to extend the choice of license to its licensees as provided above.
   23.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   23.43 - * Version 2 license, then the option applies only if the new code is
   23.44 - * made subject to such option by the copyright holder.
   23.45 - */
   23.46 -package org.apidesign.html.boot.impl;
   23.47 -
   23.48 -import java.net.URL;
   23.49 -import java.util.Collection;
   23.50 -
   23.51 -/**
   23.52 - *
   23.53 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   23.54 - */
   23.55 -public interface FindResources {
   23.56 -
   23.57 -    public void findResources(String path, Collection<? super URL> results, boolean oneIsEnough);
   23.58 -    
   23.59 -}
    24.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/FnContext.java	Mon Dec 16 15:48:09 2013 +0100
    24.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.3 @@ -1,98 +0,0 @@
    24.4 -/**
    24.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    24.6 - *
    24.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    24.8 - *
    24.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   24.10 - * Other names may be trademarks of their respective owners.
   24.11 - *
   24.12 - * The contents of this file are subject to the terms of either the GNU
   24.13 - * General Public License Version 2 only ("GPL") or the Common
   24.14 - * Development and Distribution License("CDDL") (collectively, the
   24.15 - * "License"). You may not use this file except in compliance with the
   24.16 - * License. You can obtain a copy of the License at
   24.17 - * http://www.netbeans.org/cddl-gplv2.html
   24.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   24.19 - * specific language governing permissions and limitations under the
   24.20 - * License.  When distributing the software, include this License Header
   24.21 - * Notice in each file and include the License file at
   24.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   24.23 - * particular file as subject to the "Classpath" exception as provided
   24.24 - * by Oracle in the GPL Version 2 section of the License file that
   24.25 - * accompanied this code. If applicable, add the following below the
   24.26 - * License Header, with the fields enclosed by brackets [] replaced by
   24.27 - * your own identifying information:
   24.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   24.29 - *
   24.30 - * Contributor(s):
   24.31 - *
   24.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   24.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   24.34 - *
   24.35 - * If you wish your version of this file to be governed by only the CDDL
   24.36 - * or only the GPL Version 2, indicate your decision by adding
   24.37 - * "[Contributor] elects to include this software in this distribution
   24.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   24.39 - * single choice of license, a recipient has the option to distribute
   24.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   24.41 - * to extend the choice of license to its licensees as provided above.
   24.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   24.43 - * Version 2 license, then the option applies only if the new code is
   24.44 - * made subject to such option by the copyright holder.
   24.45 - */
   24.46 -package org.apidesign.html.boot.impl;
   24.47 -
   24.48 -import java.io.Closeable;
   24.49 -import java.io.IOException;
   24.50 -import java.util.logging.Logger;
   24.51 -import org.apidesign.html.boot.spi.Fn;
   24.52 -
   24.53 -/**
   24.54 - *
   24.55 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   24.56 - */
   24.57 -public final class FnContext implements Closeable {
   24.58 -    private static final Logger LOG = Logger.getLogger(FnContext.class.getName());
   24.59 -
   24.60 -    private Object prev;
   24.61 -    private FnContext(Fn.Presenter p) {
   24.62 -        this.prev = p;
   24.63 -    }
   24.64 -
   24.65 -    @Override
   24.66 -    public void close() throws IOException {
   24.67 -        if (prev != this) {
   24.68 -            currentPresenter((Fn.Presenter)prev);
   24.69 -            prev = this;
   24.70 -        }
   24.71 -    }
   24.72 -/*
   24.73 -    @Override
   24.74 -    protected void finalize() throws Throwable {
   24.75 -        if (prev != null) {
   24.76 -            LOG.warning("Unclosed context!");
   24.77 -        }
   24.78 -    }
   24.79 -*/
   24.80 -    public static Closeable activate(Fn.Presenter newP) {
   24.81 -        return new FnContext(currentPresenter(newP));
   24.82 -    }
   24.83 -    
   24.84 -    
   24.85 -    private static final ThreadLocal<Fn.Presenter> CURRENT = new ThreadLocal<Fn.Presenter>();
   24.86 -
   24.87 -    public static Fn.Presenter currentPresenter(Fn.Presenter p) {
   24.88 -        Fn.Presenter prev = CURRENT.get();
   24.89 -        CURRENT.set(p);
   24.90 -        return prev;
   24.91 -    }
   24.92 -
   24.93 -    public static Fn.Presenter currentPresenter() {
   24.94 -        Fn.Presenter p = CURRENT.get();
   24.95 -        if (p == null) {
   24.96 -            throw new IllegalStateException("No current WebView context around!");
   24.97 -        }
   24.98 -        return p;
   24.99 -    }
  24.100 -    
  24.101 -}
    25.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/FnUtils.java	Mon Dec 16 15:48:09 2013 +0100
    25.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.3 @@ -1,597 +0,0 @@
    25.4 -/**
    25.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    25.6 - *
    25.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    25.8 - *
    25.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   25.10 - * Other names may be trademarks of their respective owners.
   25.11 - *
   25.12 - * The contents of this file are subject to the terms of either the GNU
   25.13 - * General Public License Version 2 only ("GPL") or the Common
   25.14 - * Development and Distribution License("CDDL") (collectively, the
   25.15 - * "License"). You may not use this file except in compliance with the
   25.16 - * License. You can obtain a copy of the License at
   25.17 - * http://www.netbeans.org/cddl-gplv2.html
   25.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   25.19 - * specific language governing permissions and limitations under the
   25.20 - * License.  When distributing the software, include this License Header
   25.21 - * Notice in each file and include the License file at
   25.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   25.23 - * particular file as subject to the "Classpath" exception as provided
   25.24 - * by Oracle in the GPL Version 2 section of the License file that
   25.25 - * accompanied this code. If applicable, add the following below the
   25.26 - * License Header, with the fields enclosed by brackets [] replaced by
   25.27 - * your own identifying information:
   25.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   25.29 - *
   25.30 - * Contributor(s):
   25.31 - *
   25.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   25.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   25.34 - *
   25.35 - * If you wish your version of this file to be governed by only the CDDL
   25.36 - * or only the GPL Version 2, indicate your decision by adding
   25.37 - * "[Contributor] elects to include this software in this distribution
   25.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   25.39 - * single choice of license, a recipient has the option to distribute
   25.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   25.41 - * to extend the choice of license to its licensees as provided above.
   25.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   25.43 - * Version 2 license, then the option applies only if the new code is
   25.44 - * made subject to such option by the copyright holder.
   25.45 - */
   25.46 -package org.apidesign.html.boot.impl;
   25.47 -
   25.48 -import java.io.Closeable;
   25.49 -import java.io.InputStream;
   25.50 -import java.io.InputStreamReader;
   25.51 -import java.io.Reader;
   25.52 -import java.net.URL;
   25.53 -import java.util.ArrayList;
   25.54 -import java.util.Collections;
   25.55 -import java.util.Enumeration;
   25.56 -import java.util.List;
   25.57 -import java.util.concurrent.Callable;
   25.58 -import org.apidesign.html.boot.spi.Fn;
   25.59 -import org.objectweb.asm.AnnotationVisitor;
   25.60 -import org.objectweb.asm.ClassReader;
   25.61 -import org.objectweb.asm.ClassVisitor;
   25.62 -import org.objectweb.asm.ClassWriter;
   25.63 -import org.objectweb.asm.Label;
   25.64 -import org.objectweb.asm.MethodVisitor;
   25.65 -import org.objectweb.asm.Opcodes;
   25.66 -import org.objectweb.asm.Type;
   25.67 -import org.objectweb.asm.signature.SignatureReader;
   25.68 -import org.objectweb.asm.signature.SignatureVisitor;
   25.69 -import org.objectweb.asm.signature.SignatureWriter;
   25.70 -
   25.71 -/**
   25.72 - *
   25.73 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   25.74 - */
   25.75 -public final class FnUtils implements Fn.Presenter {
   25.76 -    
   25.77 -    private FnUtils() {
   25.78 -    }
   25.79 -    
   25.80 -    public static boolean isJavaScriptCapable(ClassLoader l) {
   25.81 -        if (l instanceof JsClassLoader) {
   25.82 -            return true;
   25.83 -        }
   25.84 -        Class<?> clazz;
   25.85 -        try (Closeable c = Fn.activate(new FnUtils())) {
   25.86 -            clazz = Class.forName(Test.class.getName(), true, l);
   25.87 -            final Object is = ((Callable<?>)clazz.newInstance()).call();
   25.88 -            return Boolean.TRUE.equals(is);
   25.89 -        } catch (Exception ex) {
   25.90 -            return false;
   25.91 -        }
   25.92 -    }
   25.93 -    
   25.94 -    public static boolean isValid(Fn fn) {
   25.95 -        return fn != null && fn.isValid();
   25.96 -    }
   25.97 -
   25.98 -    public static ClassLoader newLoader(final FindResources f, final Fn.Presenter d, ClassLoader parent) {
   25.99 -        return new JsClassLoader(parent) {
  25.100 -            @Override
  25.101 -            protected URL findResource(String name) {
  25.102 -                List<URL> l = res(name, true);
  25.103 -                return l.isEmpty() ? null : l.get(0);
  25.104 -            }
  25.105 -            
  25.106 -            @Override
  25.107 -            protected Enumeration<URL> findResources(String name) {
  25.108 -                return Collections.enumeration(res(name, false));
  25.109 -            }
  25.110 -            
  25.111 -            private List<URL> res(String name, boolean oneIsEnough) {
  25.112 -                List<URL> l = new ArrayList<URL>();
  25.113 -                f.findResources(name, l, oneIsEnough);
  25.114 -                return l;
  25.115 -            }
  25.116 -            
  25.117 -            @Override
  25.118 -            protected Fn defineFn(String code, String... names) {
  25.119 -                return d.defineFn(code, names);
  25.120 -            }
  25.121 -
  25.122 -            @Override
  25.123 -            protected void loadScript(Reader code) throws Exception {
  25.124 -                d.loadScript(code);
  25.125 -            }
  25.126 -        };
  25.127 -    }
  25.128 -
  25.129 -    static String callback(final String body) {
  25.130 -        return new JsCallback() {
  25.131 -            @Override
  25.132 -            protected CharSequence callMethod(
  25.133 -                String ident, String fqn, String method, String params
  25.134 -            ) {
  25.135 -                StringBuilder sb = new StringBuilder();
  25.136 -                sb.append("vm.").append(mangle(fqn, method, params));
  25.137 -                sb.append("(");
  25.138 -                if (ident != null) {
  25.139 -                    sb.append(ident);
  25.140 -                }
  25.141 -                return sb;
  25.142 -            }
  25.143 -
  25.144 -        }.parse(body);
  25.145 -    }
  25.146 -
  25.147 -    static void loadScript(ClassLoader jcl, String resource) {
  25.148 -        final InputStream script = jcl.getResourceAsStream(resource);
  25.149 -        if (script == null) {
  25.150 -            throw new NullPointerException("Can't find " + resource);
  25.151 -        }
  25.152 -        try {
  25.153 -            Reader isr = null;
  25.154 -            try {
  25.155 -                isr = new InputStreamReader(script, "UTF-8");
  25.156 -                FnContext.currentPresenter().loadScript(isr);
  25.157 -            } finally {
  25.158 -                if (isr != null) {
  25.159 -                    isr.close();
  25.160 -                }
  25.161 -            }
  25.162 -        } catch (Exception ex) {
  25.163 -            throw new IllegalStateException("Can't execute " + resource, ex);
  25.164 -        } 
  25.165 -    }
  25.166 -
  25.167 -    @Override
  25.168 -    public Fn defineFn(String code, String... names) {
  25.169 -        return new TrueFn();
  25.170 -    }
  25.171 -
  25.172 -    @Override
  25.173 -    public void displayPage(URL page, Runnable onPageLoad) {
  25.174 -    }
  25.175 -
  25.176 -    @Override
  25.177 -    public void loadScript(Reader code) throws Exception {
  25.178 -    }
  25.179 -    
  25.180 -    private static final class FindInClass extends ClassVisitor {
  25.181 -        private String name;
  25.182 -        private int found;
  25.183 -        private ClassLoader loader;
  25.184 -        private String resource;
  25.185 -
  25.186 -        public FindInClass(ClassLoader l, ClassVisitor cv) {
  25.187 -            super(Opcodes.ASM4, cv);
  25.188 -            this.loader = l;
  25.189 -        }
  25.190 -
  25.191 -        @Override
  25.192 -        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
  25.193 -            this.name = name;
  25.194 -            super.visit(version, access, name, signature, superName, interfaces);
  25.195 -        }
  25.196 -
  25.197 -        @Override
  25.198 -        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
  25.199 -            if ("Lnet/java/html/js/JavaScriptResource;".equals(desc)) {
  25.200 -                return new LoadResource();
  25.201 -            }
  25.202 -            return super.visitAnnotation(desc, visible);
  25.203 -        }
  25.204 -
  25.205 -        @Override
  25.206 -        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
  25.207 -            return new FindInMethod(access, name, desc,
  25.208 -                    super.visitMethod(access & (~Opcodes.ACC_NATIVE), name, desc, signature, exceptions)
  25.209 -            );
  25.210 -        }
  25.211 -
  25.212 -        private final class FindInMethod extends MethodVisitor {
  25.213 -
  25.214 -            private final String name;
  25.215 -            private final String desc;
  25.216 -            private final int access;
  25.217 -            private List<String> args;
  25.218 -            private String body;
  25.219 -            private boolean bodyGenerated;
  25.220 -
  25.221 -            public FindInMethod(int access, String name, String desc, MethodVisitor mv) {
  25.222 -                super(Opcodes.ASM4, mv);
  25.223 -                this.access = access;
  25.224 -                this.name = name;
  25.225 -                this.desc = desc;
  25.226 -            }
  25.227 -
  25.228 -            @Override
  25.229 -            public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
  25.230 -                if ("Lnet/java/html/js/JavaScriptBody;".equals(desc) // NOI18N
  25.231 -                        || "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;".equals(desc) // NOI18N
  25.232 -                        ) {
  25.233 -                    found++;
  25.234 -                    return new FindInAnno();
  25.235 -                }
  25.236 -                return super.visitAnnotation(desc, visible);
  25.237 -            }
  25.238 -
  25.239 -            private void generateJSBody(List<String> args, String body) {
  25.240 -                this.args = args;
  25.241 -                this.body = body;
  25.242 -            }
  25.243 -
  25.244 -            @Override
  25.245 -            public void visitCode() {
  25.246 -                if (body == null) {
  25.247 -                    return;
  25.248 -                }
  25.249 -                generateBody();
  25.250 -            }
  25.251 -
  25.252 -            private boolean generateBody() {
  25.253 -                if (bodyGenerated) {
  25.254 -                    return false;
  25.255 -                }
  25.256 -                bodyGenerated = true;
  25.257 -
  25.258 -                super.visitFieldInsn(
  25.259 -                        Opcodes.GETSTATIC, FindInClass.this.name,
  25.260 -                        "$$fn$$" + name + "_" + found,
  25.261 -                        "Lorg/apidesign/html/boot/spi/Fn;"
  25.262 -                );
  25.263 -                super.visitInsn(Opcodes.DUP);
  25.264 -                super.visitMethodInsn(
  25.265 -                        Opcodes.INVOKESTATIC,
  25.266 -                        "org/apidesign/html/boot/spi/Fn", "isValid",
  25.267 -                        "(Lorg/apidesign/html/boot/spi/Fn;)Z"
  25.268 -                );
  25.269 -                Label ifNotNull = new Label();
  25.270 -                super.visitJumpInsn(Opcodes.IFNE, ifNotNull);
  25.271 -
  25.272 -                // init Fn
  25.273 -                super.visitInsn(Opcodes.POP);
  25.274 -                super.visitLdcInsn(Type.getObjectType(FindInClass.this.name));
  25.275 -                super.visitLdcInsn(body);
  25.276 -                super.visitIntInsn(Opcodes.SIPUSH, args.size());
  25.277 -                super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String");
  25.278 -                boolean needsVM = false;
  25.279 -                for (int i = 0; i < args.size(); i++) {
  25.280 -                    assert !needsVM;
  25.281 -                    String argName = args.get(i);
  25.282 -                    needsVM = "vm".equals(argName);
  25.283 -                    super.visitInsn(Opcodes.DUP);
  25.284 -                    super.visitIntInsn(Opcodes.BIPUSH, i);
  25.285 -                    super.visitLdcInsn(argName);
  25.286 -                    super.visitInsn(Opcodes.AASTORE);
  25.287 -                }
  25.288 -                super.visitMethodInsn(Opcodes.INVOKESTATIC,
  25.289 -                        "org/apidesign/html/boot/spi/Fn", "define",
  25.290 -                        "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/String;)Lorg/apidesign/html/boot/spi/Fn;"
  25.291 -                );
  25.292 -                if (resource != null) {
  25.293 -                    super.visitLdcInsn(Type.getObjectType(FindInClass.this.name));
  25.294 -                    super.visitLdcInsn(resource);
  25.295 -                    super.visitMethodInsn(Opcodes.INVOKESTATIC,
  25.296 -                            "org/apidesign/html/boot/spi/Fn", "preload",
  25.297 -                            "(Lorg/apidesign/html/boot/spi/Fn;Ljava/lang/Class;Ljava/lang/String;)Lorg/apidesign/html/boot/spi/Fn;"
  25.298 -                    );
  25.299 -                }
  25.300 -                super.visitInsn(Opcodes.DUP);
  25.301 -                super.visitFieldInsn(
  25.302 -                        Opcodes.PUTSTATIC, FindInClass.this.name,
  25.303 -                        "$$fn$$" + name + "_" + found,
  25.304 -                        "Lorg/apidesign/html/boot/spi/Fn;"
  25.305 -                );
  25.306 -                // end of Fn init
  25.307 -
  25.308 -                super.visitLabel(ifNotNull);
  25.309 -
  25.310 -                final int offset;
  25.311 -                if ((access & Opcodes.ACC_STATIC) == 0) {
  25.312 -                    offset = 1;
  25.313 -                    super.visitIntInsn(Opcodes.ALOAD, 0);
  25.314 -                } else {
  25.315 -                    offset = 0;
  25.316 -                    super.visitInsn(Opcodes.ACONST_NULL);
  25.317 -                }
  25.318 -
  25.319 -                super.visitIntInsn(Opcodes.SIPUSH, args.size());
  25.320 -                super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
  25.321 -
  25.322 -                class SV extends SignatureVisitor {
  25.323 -
  25.324 -                    private boolean nowReturn;
  25.325 -                    private Type returnType;
  25.326 -                    private int index;
  25.327 -                    private int loadIndex = offset;
  25.328 -
  25.329 -                    public SV() {
  25.330 -                        super(Opcodes.ASM4);
  25.331 -                    }
  25.332 -
  25.333 -                    @Override
  25.334 -                    public void visitBaseType(char descriptor) {
  25.335 -                        final Type t = Type.getType("" + descriptor);
  25.336 -                        if (nowReturn) {
  25.337 -                            returnType = t;
  25.338 -                            return;
  25.339 -                        }
  25.340 -                        FindInMethod.super.visitInsn(Opcodes.DUP);
  25.341 -                        FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++);
  25.342 -                        FindInMethod.super.visitVarInsn(t.getOpcode(Opcodes.ILOAD), loadIndex++);
  25.343 -                        String factory;
  25.344 -                        switch (descriptor) {
  25.345 -                            case 'I':
  25.346 -                                factory = "java/lang/Integer";
  25.347 -                                break;
  25.348 -                            case 'J':
  25.349 -                                factory = "java/lang/Long";
  25.350 -                                loadIndex++;
  25.351 -                                break;
  25.352 -                            case 'S':
  25.353 -                                factory = "java/lang/Short";
  25.354 -                                break;
  25.355 -                            case 'F':
  25.356 -                                factory = "java/lang/Float";
  25.357 -                                break;
  25.358 -                            case 'D':
  25.359 -                                factory = "java/lang/Double";
  25.360 -                                loadIndex++;
  25.361 -                                break;
  25.362 -                            case 'Z':
  25.363 -                                factory = "java/lang/Boolean";
  25.364 -                                break;
  25.365 -                            case 'C':
  25.366 -                                factory = "java/lang/Character";
  25.367 -                                break;
  25.368 -                            case 'B':
  25.369 -                                factory = "java/lang/Byte";
  25.370 -                                break;
  25.371 -                            default:
  25.372 -                                throw new IllegalStateException(t.toString());
  25.373 -                        }
  25.374 -                        FindInMethod.super.visitMethodInsn(Opcodes.INVOKESTATIC,
  25.375 -                                factory, "valueOf", "(" + descriptor + ")L" + factory + ";"
  25.376 -                        );
  25.377 -                        FindInMethod.super.visitInsn(Opcodes.AASTORE);
  25.378 -                    }
  25.379 -
  25.380 -                    @Override
  25.381 -                    public SignatureVisitor visitArrayType() {
  25.382 -                        if (nowReturn) {
  25.383 -                            throw new IllegalStateException("Not supported yet");
  25.384 -                        }
  25.385 -                        loadObject();
  25.386 -                        return new SignatureWriter();
  25.387 -                    }
  25.388 -
  25.389 -                    @Override
  25.390 -                    public void visitClassType(String name) {
  25.391 -                        if (nowReturn) {
  25.392 -                            returnType = Type.getObjectType(name);
  25.393 -                            return;
  25.394 -                        }
  25.395 -                        loadObject();
  25.396 -                    }
  25.397 -
  25.398 -                    @Override
  25.399 -                    public SignatureVisitor visitReturnType() {
  25.400 -                        nowReturn = true;
  25.401 -                        return this;
  25.402 -                    }
  25.403 -
  25.404 -                    private void loadObject() {
  25.405 -                        FindInMethod.super.visitInsn(Opcodes.DUP);
  25.406 -                        FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++);
  25.407 -                        FindInMethod.super.visitVarInsn(Opcodes.ALOAD, loadIndex++);
  25.408 -                        FindInMethod.super.visitInsn(Opcodes.AASTORE);
  25.409 -                    }
  25.410 -
  25.411 -                }
  25.412 -                SV sv = new SV();
  25.413 -                SignatureReader sr = new SignatureReader(desc);
  25.414 -                sr.accept(sv);
  25.415 -
  25.416 -                if (needsVM) {
  25.417 -                    FindInMethod.super.visitInsn(Opcodes.DUP);
  25.418 -                    FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, sv.index);
  25.419 -                    int lastSlash = FindInClass.this.name.lastIndexOf('/');
  25.420 -                    String jsCallbacks = FindInClass.this.name.substring(0, lastSlash + 1) + "$JsCallbacks$";
  25.421 -                    FindInMethod.super.visitFieldInsn(Opcodes.GETSTATIC, jsCallbacks, "VM", "L" + jsCallbacks + ";");
  25.422 -                    FindInMethod.super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, jsCallbacks, "current", "()L" + jsCallbacks + ";");
  25.423 -                    FindInMethod.super.visitInsn(Opcodes.AASTORE);
  25.424 -                }
  25.425 -
  25.426 -                super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
  25.427 -                        "org/apidesign/html/boot/spi/Fn", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
  25.428 -                );
  25.429 -                switch (sv.returnType.getSort()) {
  25.430 -                    case Type.VOID:
  25.431 -                        super.visitInsn(Opcodes.RETURN);
  25.432 -                        break;
  25.433 -                    case Type.ARRAY:
  25.434 -                    case Type.OBJECT:
  25.435 -                        super.visitTypeInsn(Opcodes.CHECKCAST, sv.returnType.getInternalName());
  25.436 -                        super.visitInsn(Opcodes.ARETURN);
  25.437 -                        break;
  25.438 -                    case Type.BOOLEAN:
  25.439 -                        super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Boolean");
  25.440 -                        super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
  25.441 -                                "java/lang/Boolean", "booleanValue", "()Z"
  25.442 -                        );
  25.443 -                        super.visitInsn(Opcodes.IRETURN);
  25.444 -                        break;
  25.445 -                    default:
  25.446 -                        super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number");
  25.447 -                        super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
  25.448 -                                "java/lang/Number", sv.returnType.getClassName() + "Value", "()" + sv.returnType.getDescriptor()
  25.449 -                        );
  25.450 -                        super.visitInsn(sv.returnType.getOpcode(Opcodes.IRETURN));
  25.451 -                }
  25.452 -                return true;
  25.453 -            }
  25.454 -
  25.455 -            @Override
  25.456 -            public void visitEnd() {
  25.457 -                super.visitEnd();
  25.458 -                if (body != null) {
  25.459 -                    if (generateBody()) {
  25.460 -                        // native method
  25.461 -                        super.visitMaxs(1, 0);
  25.462 -                    }
  25.463 -                    FindInClass.this.visitField(
  25.464 -                            Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
  25.465 -                            "$$fn$$" + name + "_" + found,
  25.466 -                            "Lorg/apidesign/html/boot/spi/Fn;",
  25.467 -                            null, null
  25.468 -                    );
  25.469 -                }
  25.470 -            }
  25.471 -
  25.472 -            private final class FindInAnno extends AnnotationVisitor {
  25.473 -
  25.474 -                private List<String> args = new ArrayList<String>();
  25.475 -                private String body;
  25.476 -                private boolean javacall = false;
  25.477 -
  25.478 -                public FindInAnno() {
  25.479 -                    super(Opcodes.ASM4);
  25.480 -                }
  25.481 -
  25.482 -                @Override
  25.483 -                public void visit(String name, Object value) {
  25.484 -                    if (name == null) {
  25.485 -                        args.add((String) value);
  25.486 -                        return;
  25.487 -                    }
  25.488 -                    if (name.equals("javacall")) { // NOI18N
  25.489 -                        javacall = (Boolean) value;
  25.490 -                        return;
  25.491 -                    }
  25.492 -                    assert name.equals("body");
  25.493 -                    body = (String) value;
  25.494 -                }
  25.495 -
  25.496 -                @Override
  25.497 -                public AnnotationVisitor visitArray(String name) {
  25.498 -                    return this;
  25.499 -                }
  25.500 -
  25.501 -                @Override
  25.502 -                public void visitEnd() {
  25.503 -                    if (body != null) {
  25.504 -                        if (javacall) {
  25.505 -                            body = callback(body);
  25.506 -                            args.add("vm");
  25.507 -                        }
  25.508 -                        generateJSBody(args, body);
  25.509 -                    }
  25.510 -                }
  25.511 -            }
  25.512 -        }
  25.513 -
  25.514 -        private final class LoadResource extends AnnotationVisitor {
  25.515 -
  25.516 -            public LoadResource() {
  25.517 -                super(Opcodes.ASM4);
  25.518 -            }
  25.519 -
  25.520 -            @Override
  25.521 -            public void visit(String attrName, Object value) {
  25.522 -                String relPath = (String) value;
  25.523 -                if (relPath.startsWith("/")) {
  25.524 -                    resource = relPath;
  25.525 -                } else {
  25.526 -                    int last = name.lastIndexOf('/');
  25.527 -                    String fullPath = name.substring(0, last + 1) + relPath;
  25.528 -                    resource = fullPath;
  25.529 -                }
  25.530 -            }
  25.531 -        }
  25.532 -    }
  25.533 -
  25.534 -    private static class ClassWriterEx extends ClassWriter {
  25.535 -
  25.536 -        private ClassLoader loader;
  25.537 -
  25.538 -        public ClassWriterEx(ClassLoader l, ClassReader classReader, int flags) {
  25.539 -            super(classReader, flags);
  25.540 -            this.loader = l;
  25.541 -        }
  25.542 -
  25.543 -        @Override
  25.544 -        protected String getCommonSuperClass(final String type1, final String type2) {
  25.545 -            Class<?> c, d;
  25.546 -            try {
  25.547 -                c = Class.forName(type1.replace('/', '.'), false, loader);
  25.548 -                d = Class.forName(type2.replace('/', '.'), false, loader);
  25.549 -            } catch (Exception e) {
  25.550 -                throw new RuntimeException(e.toString());
  25.551 -            }
  25.552 -            if (c.isAssignableFrom(d)) {
  25.553 -                return type1;
  25.554 -            }
  25.555 -            if (d.isAssignableFrom(c)) {
  25.556 -                return type2;
  25.557 -            }
  25.558 -            if (c.isInterface() || d.isInterface()) {
  25.559 -                return "java/lang/Object";
  25.560 -            } else {
  25.561 -                do {
  25.562 -                    c = c.getSuperclass();
  25.563 -                } while (!c.isAssignableFrom(d));
  25.564 -                return c.getName().replace('.', '/');
  25.565 -            }
  25.566 -        }
  25.567 -    }
  25.568 -
  25.569 -    static byte[] transform(ClassLoader loader, byte[] arr) {
  25.570 -        ClassReader cr = new ClassReader(arr) {
  25.571 -            // to allow us to compile with -profile compact1 on 
  25.572 -            // JDK8 while processing the class as JDK7, the highest
  25.573 -            // class format asm 4.1 understands to
  25.574 -            @Override
  25.575 -            public short readShort(int index) {
  25.576 -                short s = super.readShort(index);
  25.577 -                if (index == 6 && s > Opcodes.V1_7) {
  25.578 -                    return Opcodes.V1_7;
  25.579 -                }
  25.580 -                return s;
  25.581 -            }
  25.582 -        };
  25.583 -        FindInClass tst = new FindInClass(loader, null);
  25.584 -        cr.accept(tst, 0);
  25.585 -        if (tst.found > 0) {
  25.586 -            ClassWriter w = new ClassWriterEx(loader, cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
  25.587 -            FindInClass fic = new FindInClass(loader, w);
  25.588 -            cr.accept(fic, 0);
  25.589 -            arr = w.toByteArray();
  25.590 -        }
  25.591 -        return arr;
  25.592 -    }
  25.593 -
  25.594 -    private static final class TrueFn extends Fn {
  25.595 -        @Override
  25.596 -        public Object invoke(Object thiz, Object... args) throws Exception {
  25.597 -            return Boolean.TRUE;
  25.598 -        }
  25.599 -    } // end of TrueFn
  25.600 -}
    26.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/JavaScriptProcesor.java	Mon Dec 16 15:48:09 2013 +0100
    26.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.3 @@ -1,369 +0,0 @@
    26.4 -/**
    26.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    26.6 - *
    26.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    26.8 - *
    26.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   26.10 - * Other names may be trademarks of their respective owners.
   26.11 - *
   26.12 - * The contents of this file are subject to the terms of either the GNU
   26.13 - * General Public License Version 2 only ("GPL") or the Common
   26.14 - * Development and Distribution License("CDDL") (collectively, the
   26.15 - * "License"). You may not use this file except in compliance with the
   26.16 - * License. You can obtain a copy of the License at
   26.17 - * http://www.netbeans.org/cddl-gplv2.html
   26.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   26.19 - * specific language governing permissions and limitations under the
   26.20 - * License.  When distributing the software, include this License Header
   26.21 - * Notice in each file and include the License file at
   26.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   26.23 - * particular file as subject to the "Classpath" exception as provided
   26.24 - * by Oracle in the GPL Version 2 section of the License file that
   26.25 - * accompanied this code. If applicable, add the following below the
   26.26 - * License Header, with the fields enclosed by brackets [] replaced by
   26.27 - * your own identifying information:
   26.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   26.29 - *
   26.30 - * Contributor(s):
   26.31 - *
   26.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   26.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   26.34 - *
   26.35 - * If you wish your version of this file to be governed by only the CDDL
   26.36 - * or only the GPL Version 2, indicate your decision by adding
   26.37 - * "[Contributor] elects to include this software in this distribution
   26.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   26.39 - * single choice of license, a recipient has the option to distribute
   26.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   26.41 - * to extend the choice of license to its licensees as provided above.
   26.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   26.43 - * Version 2 license, then the option applies only if the new code is
   26.44 - * made subject to such option by the copyright holder.
   26.45 - */
   26.46 -package org.apidesign.html.boot.impl;
   26.47 -
   26.48 -import java.io.IOException;
   26.49 -import java.io.Writer;
   26.50 -import java.util.Collections;
   26.51 -import java.util.HashMap;
   26.52 -import java.util.HashSet;
   26.53 -import java.util.List;
   26.54 -import java.util.Map;
   26.55 -import java.util.Set;
   26.56 -import java.util.TreeMap;
   26.57 -import javax.annotation.processing.AbstractProcessor;
   26.58 -import javax.annotation.processing.Completion;
   26.59 -import javax.annotation.processing.Completions;
   26.60 -import javax.annotation.processing.Messager;
   26.61 -import javax.annotation.processing.Processor;
   26.62 -import javax.annotation.processing.RoundEnvironment;
   26.63 -import javax.lang.model.SourceVersion;
   26.64 -import javax.lang.model.element.AnnotationMirror;
   26.65 -import javax.lang.model.element.Element;
   26.66 -import javax.lang.model.element.ElementKind;
   26.67 -import javax.lang.model.element.ExecutableElement;
   26.68 -import javax.lang.model.element.Modifier;
   26.69 -import javax.lang.model.element.PackageElement;
   26.70 -import javax.lang.model.element.TypeElement;
   26.71 -import javax.lang.model.element.VariableElement;
   26.72 -import javax.lang.model.type.ArrayType;
   26.73 -import javax.lang.model.type.ExecutableType;
   26.74 -import javax.lang.model.type.TypeKind;
   26.75 -import javax.lang.model.type.TypeMirror;
   26.76 -import javax.tools.Diagnostic;
   26.77 -import javax.tools.FileObject;
   26.78 -import javax.tools.StandardLocation;
   26.79 -import net.java.html.js.JavaScriptBody;
   26.80 -import net.java.html.js.JavaScriptResource;
   26.81 -import org.openide.util.lookup.ServiceProvider;
   26.82 -
   26.83 -/**
   26.84 - *
   26.85 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   26.86 - */
   26.87 -@ServiceProvider(service = Processor.class)
   26.88 -public final class JavaScriptProcesor extends AbstractProcessor {
   26.89 -    private final Map<String,Map<String,ExecutableElement>> javacalls = 
   26.90 -        new HashMap<String,Map<String,ExecutableElement>>();
   26.91 -    
   26.92 -    @Override
   26.93 -    public Set<String> getSupportedAnnotationTypes() {
   26.94 -        Set<String> set = new HashSet<String>();
   26.95 -        set.add(JavaScriptBody.class.getName());
   26.96 -        set.add(JavaScriptResource.class.getName());
   26.97 -        return set;
   26.98 -    }
   26.99 -    
  26.100 -    @Override
  26.101 -    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
  26.102 -        final Messager msg = processingEnv.getMessager();
  26.103 -        for (Element e : roundEnv.getElementsAnnotatedWith(JavaScriptBody.class)) {
  26.104 -            if (e.getKind() != ElementKind.METHOD && e.getKind() != ElementKind.CONSTRUCTOR) {
  26.105 -                continue;
  26.106 -            }
  26.107 -            ExecutableElement ee = (ExecutableElement)e;
  26.108 -            List<? extends VariableElement> params = ee.getParameters();
  26.109 -            
  26.110 -            JavaScriptBody jsb = e.getAnnotation(JavaScriptBody.class);
  26.111 -            if (jsb == null) {
  26.112 -                continue;
  26.113 -            }
  26.114 -            String[] arr = jsb.args();
  26.115 -            if (params.size() != arr.length) {
  26.116 -                msg.printMessage(Diagnostic.Kind.ERROR, "Number of args arguments does not match real arguments!", e);
  26.117 -            }
  26.118 -            if (!jsb.javacall() && jsb.body().contains(".@")) {
  26.119 -                msg.printMessage(Diagnostic.Kind.WARNING, "Usage of .@ usually requires javacall=true", e);
  26.120 -            }
  26.121 -            if (jsb.javacall()) {
  26.122 -                JsCallback verify = new VerifyCallback(e);
  26.123 -                try {
  26.124 -                    verify.parse(jsb.body());
  26.125 -                } catch (IllegalStateException ex) {
  26.126 -                    msg.printMessage(Diagnostic.Kind.ERROR, ex.getLocalizedMessage(), e);
  26.127 -                }
  26.128 -            }
  26.129 -        }
  26.130 -        for (Element e : roundEnv.getElementsAnnotatedWith(JavaScriptResource.class)) {
  26.131 -            JavaScriptResource r = e.getAnnotation(JavaScriptResource.class);
  26.132 -            if (r == null) {
  26.133 -                continue;
  26.134 -            }
  26.135 -            final String res;
  26.136 -            if (r.value().startsWith("/")) {
  26.137 -                res = r.value();
  26.138 -            } else {
  26.139 -                res = findPkg(e).replace('.', '/') + "/" + r.value();
  26.140 -            }
  26.141 -            
  26.142 -            try {
  26.143 -                FileObject os = processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", res);
  26.144 -                os.openInputStream().close();
  26.145 -            } catch (IOException ex1) {
  26.146 -                try {
  26.147 -                    FileObject os2 = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", res);
  26.148 -                    os2.openInputStream().close();
  26.149 -                } catch (IOException ex2) {
  26.150 -                    msg.printMessage(Diagnostic.Kind.ERROR, "Cannot find " + res + " in " + res + " package", e);
  26.151 -                }
  26.152 -            }
  26.153 -        }
  26.154 -
  26.155 -        if (roundEnv.processingOver()) {
  26.156 -            generateCallbackClass(javacalls);
  26.157 -            javacalls.clear();
  26.158 -        }
  26.159 -        return true;
  26.160 -    }
  26.161 -
  26.162 -    @Override
  26.163 -    public Iterable<? extends Completion> getCompletions(Element e, 
  26.164 -        AnnotationMirror annotation, ExecutableElement member, String userText
  26.165 -    ) {
  26.166 -        StringBuilder sb = new StringBuilder();
  26.167 -        if (e.getKind() == ElementKind.METHOD && member.getSimpleName().contentEquals("args")) {
  26.168 -            ExecutableElement ee = (ExecutableElement) e;
  26.169 -            String sep = "";
  26.170 -            sb.append("{ ");
  26.171 -            for (VariableElement ve : ee.getParameters()) {
  26.172 -                sb.append(sep).append('"').append(ve.getSimpleName())
  26.173 -                    .append('"');
  26.174 -                sep = ", ";
  26.175 -            }
  26.176 -            sb.append(" }");
  26.177 -            return Collections.nCopies(1, Completions.of(sb.toString()));
  26.178 -        }
  26.179 -        return null;
  26.180 -    }
  26.181 -
  26.182 -    private class VerifyCallback extends JsCallback {
  26.183 -        private final Element e;
  26.184 -        public VerifyCallback(Element e) {
  26.185 -            this.e = e;
  26.186 -        }
  26.187 -
  26.188 -        @Override
  26.189 -        protected CharSequence callMethod(String ident, String fqn, String method, String params) {
  26.190 -            final TypeElement type = processingEnv.getElementUtils().getTypeElement(fqn);
  26.191 -            if (type == null) {
  26.192 -                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, 
  26.193 -                    "Callback to non-existing class " + fqn, e
  26.194 -                );
  26.195 -                return "";
  26.196 -            }
  26.197 -            ExecutableElement found = null;
  26.198 -            StringBuilder foundParams = new StringBuilder();
  26.199 -            for (Element m : type.getEnclosedElements()) {
  26.200 -                if (m.getKind() != ElementKind.METHOD) {
  26.201 -                    continue;
  26.202 -                }
  26.203 -                if (m.getSimpleName().contentEquals(method)) {
  26.204 -                    String paramTypes = findParamTypes((ExecutableElement)m);
  26.205 -                    if (paramTypes.equals(params)) {
  26.206 -                        found = (ExecutableElement) m;
  26.207 -                        break;
  26.208 -                    }
  26.209 -                    foundParams.append(paramTypes).append("\n");
  26.210 -                }
  26.211 -            }
  26.212 -            if (found == null) {
  26.213 -                if (foundParams.length() == 0) {
  26.214 -                    processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, 
  26.215 -                        "Callback to class " + fqn + " with unknown method " + method, e
  26.216 -                    );
  26.217 -                } else {
  26.218 -                    processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, 
  26.219 -                        "Callback to " + fqn + "." + method + " with wrong parameters: " + 
  26.220 -                        params + ". Only known parameters are " + foundParams, e
  26.221 -                    );
  26.222 -                }
  26.223 -            } else {
  26.224 -                Map<String,ExecutableElement> mangledOnes = javacalls.get(findPkg(e));
  26.225 -                if (mangledOnes == null) {
  26.226 -                    mangledOnes = new TreeMap<String, ExecutableElement>();
  26.227 -                    javacalls.put(findPkg(e), mangledOnes);
  26.228 -                }
  26.229 -                String mangled = JsCallback.mangle(fqn, method, findParamTypes(found));
  26.230 -                mangledOnes.put(mangled, found);
  26.231 -            }
  26.232 -            return "";
  26.233 -        }
  26.234 -
  26.235 -        private String findParamTypes(ExecutableElement method) {
  26.236 -            ExecutableType t = (ExecutableType) method.asType();
  26.237 -            StringBuilder sb = new StringBuilder();
  26.238 -            sb.append('(');
  26.239 -            for (TypeMirror tm : t.getParameterTypes()) {
  26.240 -                if (tm.getKind().isPrimitive()) {
  26.241 -                    switch (tm.getKind()) {
  26.242 -                        case INT: sb.append('I'); break;
  26.243 -                        case BOOLEAN: sb.append('Z'); break;
  26.244 -                        case BYTE: sb.append('B'); break;
  26.245 -                        case CHAR: sb.append('C'); break;
  26.246 -                        case SHORT: sb.append('S'); break;
  26.247 -                        case DOUBLE: sb.append('D'); break;
  26.248 -                        case FLOAT: sb.append('F'); break;
  26.249 -                        case LONG: sb.append('J'); break;
  26.250 -                        default:
  26.251 -                            throw new IllegalStateException("Uknown " + tm.getKind());
  26.252 -                    }
  26.253 -                } else {
  26.254 -                    while (tm.getKind() == TypeKind.ARRAY) {
  26.255 -                        sb.append('[');
  26.256 -                        tm = ((ArrayType)tm).getComponentType();
  26.257 -                    }
  26.258 -                    sb.append('L');
  26.259 -                    sb.append(tm.toString().replace('.', '/'));
  26.260 -                    sb.append(';');
  26.261 -                }
  26.262 -            }
  26.263 -            sb.append(')');
  26.264 -            return sb.toString();
  26.265 -        }
  26.266 -    }
  26.267 -    
  26.268 -    private void generateCallbackClass(Map<String,Map<String, ExecutableElement>> process) {
  26.269 -        for (Map.Entry<String, Map<String, ExecutableElement>> pkgEn : process.entrySet()) {
  26.270 -            String pkgName = pkgEn.getKey();
  26.271 -            Map<String, ExecutableElement> map = pkgEn.getValue();
  26.272 -            StringBuilder source = new StringBuilder();
  26.273 -            source.append("package ").append(pkgName).append(";\n");
  26.274 -            source.append("public final class $JsCallbacks$ {\n");
  26.275 -            source.append("  static final $JsCallbacks$ VM = new $JsCallbacks$(null);\n");
  26.276 -            source.append("  private final org.apidesign.html.boot.spi.Fn.Presenter p;\n");
  26.277 -            source.append("  private $JsCallbacks$ last;\n");
  26.278 -            source.append("  private $JsCallbacks$(org.apidesign.html.boot.spi.Fn.Presenter p) {\n");
  26.279 -            source.append("    this.p = p;\n");
  26.280 -            source.append("  }\n");
  26.281 -            source.append("  final $JsCallbacks$ current() {\n");
  26.282 -            source.append("    org.apidesign.html.boot.spi.Fn.Presenter now = org.apidesign.html.boot.spi.Fn.activePresenter();\n");
  26.283 -            source.append("    if (now == p) return this;\n");
  26.284 -            source.append("    if (last != null && now == last.p) return last;\n");
  26.285 -            source.append("    return last = new $JsCallbacks$(now);\n");
  26.286 -            source.append("  }\n");
  26.287 -            for (Map.Entry<String, ExecutableElement> entry : map.entrySet()) {
  26.288 -                final String mangled = entry.getKey();
  26.289 -                final ExecutableElement m = entry.getValue();
  26.290 -                final boolean isStatic = m.getModifiers().contains(Modifier.STATIC);
  26.291 -                
  26.292 -                source.append("\n  public java.lang.Object ")
  26.293 -                    .append(mangled)
  26.294 -                    .append("(");
  26.295 -                
  26.296 -                String sep = "";
  26.297 -                if (!isStatic) {
  26.298 -                    source.append(((TypeElement)m.getEnclosingElement()).getQualifiedName());
  26.299 -                    source.append(" self");
  26.300 -                    sep = ", ";
  26.301 -                }
  26.302 -                
  26.303 -                int cnt = 0;
  26.304 -                for (VariableElement ve : m.getParameters()) {
  26.305 -                    source.append(sep);
  26.306 -                    source.append(ve.asType());
  26.307 -                    source.append(" arg").append(++cnt);
  26.308 -                    sep = ", ";
  26.309 -                }
  26.310 -                source.append(") throws Throwable {\n");
  26.311 -                if (processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_7) >= 0) {
  26.312 -                    source.append("    try (java.io.Closeable a = org.apidesign.html.boot.spi.Fn.activate(p)) { \n");
  26.313 -                } else {
  26.314 -                    source.append("    java.io.Closeable a = org.apidesign.html.boot.spi.Fn.activate(p); try {\n");
  26.315 -                }
  26.316 -                source.append("    ");
  26.317 -                if (m.getReturnType().getKind() != TypeKind.VOID) {
  26.318 -                    source.append("return ");
  26.319 -                }
  26.320 -                if (isStatic) {
  26.321 -                    source.append(((TypeElement)m.getEnclosingElement()).getQualifiedName());
  26.322 -                    source.append('.');
  26.323 -                } else {
  26.324 -                    source.append("self.");
  26.325 -                }
  26.326 -                source.append(m.getSimpleName());
  26.327 -                source.append("(");
  26.328 -                cnt = 0;
  26.329 -                sep = "";
  26.330 -                for (VariableElement ve : m.getParameters()) {
  26.331 -                    source.append(sep);
  26.332 -                    source.append("arg").append(++cnt);
  26.333 -                    sep = ", ";
  26.334 -                }
  26.335 -                source.append(");\n");
  26.336 -                if (m.getReturnType().getKind() == TypeKind.VOID) {
  26.337 -                    source.append("    return null;\n");
  26.338 -                }
  26.339 -                if (processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_7) >= 0) {
  26.340 -                    source.append("    }\n");
  26.341 -                } else {
  26.342 -                    
  26.343 -                    source.append("    } finally {\n");
  26.344 -                    source.append("      a.close();\n");
  26.345 -                    source.append("    }\n");
  26.346 -                }
  26.347 -                source.append("  }\n");
  26.348 -            }
  26.349 -            source.append("}\n");
  26.350 -            final String srcName = pkgName + ".$JsCallbacks$";
  26.351 -            try {
  26.352 -                Writer w = processingEnv.getFiler().createSourceFile(srcName,
  26.353 -                    map.values().toArray(new Element[map.size()])
  26.354 -                ).openWriter();
  26.355 -                w.write(source.toString());
  26.356 -                w.close();
  26.357 -            } catch (IOException ex) {
  26.358 -                processingEnv.getMessager().printMessage(
  26.359 -                    Diagnostic.Kind.ERROR, "Can't write " + srcName + ": " + ex.getMessage()
  26.360 -                );
  26.361 -            }
  26.362 -        }
  26.363 -    }
  26.364 -    
  26.365 -    private static String findPkg(Element e) {
  26.366 -        while (e.getKind() != ElementKind.PACKAGE) {
  26.367 -            e = e.getEnclosingElement();
  26.368 -        }
  26.369 -        return ((PackageElement)e).getQualifiedName().toString();
  26.370 -    }
  26.371 -    
  26.372 -}
    27.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/JsAgent.java	Mon Dec 16 15:48:09 2013 +0100
    27.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.3 @@ -1,67 +0,0 @@
    27.4 -/**
    27.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    27.6 - *
    27.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    27.8 - *
    27.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   27.10 - * Other names may be trademarks of their respective owners.
   27.11 - *
   27.12 - * The contents of this file are subject to the terms of either the GNU
   27.13 - * General Public License Version 2 only ("GPL") or the Common
   27.14 - * Development and Distribution License("CDDL") (collectively, the
   27.15 - * "License"). You may not use this file except in compliance with the
   27.16 - * License. You can obtain a copy of the License at
   27.17 - * http://www.netbeans.org/cddl-gplv2.html
   27.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   27.19 - * specific language governing permissions and limitations under the
   27.20 - * License.  When distributing the software, include this License Header
   27.21 - * Notice in each file and include the License file at
   27.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   27.23 - * particular file as subject to the "Classpath" exception as provided
   27.24 - * by Oracle in the GPL Version 2 section of the License file that
   27.25 - * accompanied this code. If applicable, add the following below the
   27.26 - * License Header, with the fields enclosed by brackets [] replaced by
   27.27 - * your own identifying information:
   27.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   27.29 - *
   27.30 - * Contributor(s):
   27.31 - *
   27.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   27.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   27.34 - *
   27.35 - * If you wish your version of this file to be governed by only the CDDL
   27.36 - * or only the GPL Version 2, indicate your decision by adding
   27.37 - * "[Contributor] elects to include this software in this distribution
   27.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   27.39 - * single choice of license, a recipient has the option to distribute
   27.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   27.41 - * to extend the choice of license to its licensees as provided above.
   27.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   27.43 - * Version 2 license, then the option applies only if the new code is
   27.44 - * made subject to such option by the copyright holder.
   27.45 - */
   27.46 -package org.apidesign.html.boot.impl;
   27.47 -
   27.48 -import java.lang.instrument.ClassFileTransformer;
   27.49 -import java.lang.instrument.IllegalClassFormatException;
   27.50 -import java.lang.instrument.Instrumentation;
   27.51 -import java.security.ProtectionDomain;
   27.52 -
   27.53 -/**
   27.54 - *
   27.55 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   27.56 - */
   27.57 -public final class JsAgent implements ClassFileTransformer {
   27.58 -    public static void agentmain(String args, Instrumentation instr) {
   27.59 -        instr.addTransformer(new JsAgent());
   27.60 -    }
   27.61 -
   27.62 -    @Override
   27.63 -    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
   27.64 -        try {
   27.65 -            return FnUtils.transform(loader, classfileBuffer);
   27.66 -        } catch (Exception ex) {
   27.67 -            return classfileBuffer;
   27.68 -        }
   27.69 -    }
   27.70 -}
    28.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/JsCallback.java	Mon Dec 16 15:48:09 2013 +0100
    28.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.3 @@ -1,160 +0,0 @@
    28.4 -/**
    28.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    28.6 - *
    28.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    28.8 - *
    28.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   28.10 - * Other names may be trademarks of their respective owners.
   28.11 - *
   28.12 - * The contents of this file are subject to the terms of either the GNU
   28.13 - * General Public License Version 2 only ("GPL") or the Common
   28.14 - * Development and Distribution License("CDDL") (collectively, the
   28.15 - * "License"). You may not use this file except in compliance with the
   28.16 - * License. You can obtain a copy of the License at
   28.17 - * http://www.netbeans.org/cddl-gplv2.html
   28.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   28.19 - * specific language governing permissions and limitations under the
   28.20 - * License.  When distributing the software, include this License Header
   28.21 - * Notice in each file and include the License file at
   28.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   28.23 - * particular file as subject to the "Classpath" exception as provided
   28.24 - * by Oracle in the GPL Version 2 section of the License file that
   28.25 - * accompanied this code. If applicable, add the following below the
   28.26 - * License Header, with the fields enclosed by brackets [] replaced by
   28.27 - * your own identifying information:
   28.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   28.29 - *
   28.30 - * Contributor(s):
   28.31 - *
   28.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   28.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   28.34 - *
   28.35 - * If you wish your version of this file to be governed by only the CDDL
   28.36 - * or only the GPL Version 2, indicate your decision by adding
   28.37 - * "[Contributor] elects to include this software in this distribution
   28.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   28.39 - * single choice of license, a recipient has the option to distribute
   28.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   28.41 - * to extend the choice of license to its licensees as provided above.
   28.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   28.43 - * Version 2 license, then the option applies only if the new code is
   28.44 - * made subject to such option by the copyright holder.
   28.45 - */
   28.46 -package org.apidesign.html.boot.impl;
   28.47 -
   28.48 -
   28.49 -/**
   28.50 - *
   28.51 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   28.52 - */
   28.53 -abstract class JsCallback {
   28.54 -    final String parse(String body) {
   28.55 -        StringBuilder sb = new StringBuilder();
   28.56 -        int pos = 0;
   28.57 -        for (;;) {
   28.58 -            int next = body.indexOf(".@", pos);
   28.59 -            if (next == -1) {
   28.60 -                sb.append(body.substring(pos));
   28.61 -                body = sb.toString();
   28.62 -                break;
   28.63 -            }
   28.64 -            int ident = next;
   28.65 -            while (ident > 0) {
   28.66 -                if (!Character.isJavaIdentifierPart(body.charAt(--ident))) {
   28.67 -                    ident++;
   28.68 -                    break;
   28.69 -                }
   28.70 -            }
   28.71 -            String refId = body.substring(ident, next);
   28.72 -            
   28.73 -            sb.append(body.substring(pos, ident));
   28.74 -            
   28.75 -            int sigBeg = body.indexOf('(', next);
   28.76 -            int sigEnd = body.indexOf(')', sigBeg);
   28.77 -            int colon4 = body.indexOf("::", next);
   28.78 -            if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) {
   28.79 -                throw new IllegalStateException(
   28.80 -                    "Wrong format of instance callback. "
   28.81 -                    + "Should be: 'inst.@pkg.Class::method(Ljava/lang/Object;)(param)':\n" 
   28.82 -                    + body
   28.83 -                );
   28.84 -            }
   28.85 -            String fqn = body.substring(next + 2, colon4);
   28.86 -            String method = body.substring(colon4 + 2, sigBeg);
   28.87 -            String params = body.substring(sigBeg, sigEnd + 1);
   28.88 -
   28.89 -            int paramBeg = body.indexOf('(', sigEnd + 1);
   28.90 -            if (paramBeg == -1) {
   28.91 -                throw new IllegalStateException(
   28.92 -                    "Wrong format of instance callback. "
   28.93 -                    + "Should be: 'inst.@pkg.Class::method(Ljava/lang/Object;)(param)':\n" 
   28.94 -                    + body
   28.95 -                );
   28.96 -            }
   28.97 -            
   28.98 -            sb.append(callMethod(refId, fqn, method, params));
   28.99 -            if (body.charAt(paramBeg + 1) != (')')) {
  28.100 -                sb.append(",");
  28.101 -            }
  28.102 -            pos = paramBeg + 1;
  28.103 -        }
  28.104 -        pos = 0;
  28.105 -        sb = null;
  28.106 -        for (;;) {
  28.107 -            int next = body.indexOf("@", pos);
  28.108 -            if (next == -1) {
  28.109 -                if (sb == null) {
  28.110 -                    return body;
  28.111 -                }
  28.112 -                sb.append(body.substring(pos));
  28.113 -                return sb.toString();
  28.114 -            }
  28.115 -            if (sb == null) {
  28.116 -                sb = new StringBuilder();
  28.117 -            }
  28.118 -            
  28.119 -            sb.append(body.substring(pos, next));
  28.120 -            
  28.121 -            int sigBeg = body.indexOf('(', next);
  28.122 -            int sigEnd = body.indexOf(')', sigBeg);
  28.123 -            int colon4 = body.indexOf("::", next);
  28.124 -            if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) {
  28.125 -                throw new IllegalStateException(
  28.126 -                    "Wrong format of static callback. "
  28.127 -                    + "Should be: '@pkg.Class::staticMethod(Ljava/lang/Object;)(param)':\n" 
  28.128 -                    + body
  28.129 -                );
  28.130 -            }
  28.131 -            String fqn = body.substring(next + 1, colon4);
  28.132 -            String method = body.substring(colon4 + 2, sigBeg);
  28.133 -            String params = body.substring(sigBeg, sigEnd + 1);
  28.134 -
  28.135 -            int paramBeg = body.indexOf('(', sigEnd + 1);
  28.136 -            
  28.137 -            sb.append(callMethod(null, fqn, method, params));
  28.138 -            pos = paramBeg + 1;
  28.139 -        }
  28.140 -    }
  28.141 -
  28.142 -    protected abstract CharSequence callMethod(
  28.143 -        String ident, String fqn, String method, String params
  28.144 -    );
  28.145 -
  28.146 -    static String mangle(String fqn, String method, String params) {
  28.147 -        if (params.startsWith("(")) {
  28.148 -            params = params.substring(1);
  28.149 -        }
  28.150 -        if (params.endsWith(")")) {
  28.151 -            params = params.substring(0, params.length() - 1);
  28.152 -        }
  28.153 -        return 
  28.154 -            replace(fqn) + "$" + replace(method) + "$" + replace(params);
  28.155 -    }
  28.156 -    
  28.157 -    private static String replace(String orig) {
  28.158 -        return orig.replace("_", "_1").
  28.159 -            replace(";", "_2").
  28.160 -            replace("[", "_3").
  28.161 -            replace('.', '_').replace('/', '_');
  28.162 -    }
  28.163 -}
    29.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/JsClassLoader.java	Mon Dec 16 15:48:09 2013 +0100
    29.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.3 @@ -1,133 +0,0 @@
    29.4 -/**
    29.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    29.6 - *
    29.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    29.8 - *
    29.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   29.10 - * Other names may be trademarks of their respective owners.
   29.11 - *
   29.12 - * The contents of this file are subject to the terms of either the GNU
   29.13 - * General Public License Version 2 only ("GPL") or the Common
   29.14 - * Development and Distribution License("CDDL") (collectively, the
   29.15 - * "License"). You may not use this file except in compliance with the
   29.16 - * License. You can obtain a copy of the License at
   29.17 - * http://www.netbeans.org/cddl-gplv2.html
   29.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   29.19 - * specific language governing permissions and limitations under the
   29.20 - * License.  When distributing the software, include this License Header
   29.21 - * Notice in each file and include the License file at
   29.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   29.23 - * particular file as subject to the "Classpath" exception as provided
   29.24 - * by Oracle in the GPL Version 2 section of the License file that
   29.25 - * accompanied this code. If applicable, add the following below the
   29.26 - * License Header, with the fields enclosed by brackets [] replaced by
   29.27 - * your own identifying information:
   29.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   29.29 - *
   29.30 - * Contributor(s):
   29.31 - *
   29.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   29.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   29.34 - *
   29.35 - * If you wish your version of this file to be governed by only the CDDL
   29.36 - * or only the GPL Version 2, indicate your decision by adding
   29.37 - * "[Contributor] elects to include this software in this distribution
   29.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   29.39 - * single choice of license, a recipient has the option to distribute
   29.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   29.41 - * to extend the choice of license to its licensees as provided above.
   29.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   29.43 - * Version 2 license, then the option applies only if the new code is
   29.44 - * made subject to such option by the copyright holder.
   29.45 - */
   29.46 -package org.apidesign.html.boot.impl;
   29.47 -
   29.48 -import org.apidesign.html.boot.spi.Fn;
   29.49 -import java.io.IOException;
   29.50 -import java.io.InputStream;
   29.51 -import java.io.Reader;
   29.52 -import java.net.URL;
   29.53 -import java.util.Enumeration;
   29.54 -
   29.55 -/** 
   29.56 - *
   29.57 - * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   29.58 - */
   29.59 -abstract class JsClassLoader extends ClassLoader {
   29.60 -    JsClassLoader(ClassLoader parent) {
   29.61 -        super(parent);
   29.62 -        setDefaultAssertionStatus(JsClassLoader.class.desiredAssertionStatus());
   29.63 -    }
   29.64 -    
   29.65 -    @Override
   29.66 -    protected abstract URL findResource(String name);
   29.67 -    
   29.68 -    @Override
   29.69 -    protected abstract Enumeration<URL> findResources(String name);
   29.70 -
   29.71 -    @Override
   29.72 -    protected Class<?> findClass(String name) throws ClassNotFoundException {
   29.73 -        if (name.startsWith("javafx")) {
   29.74 -            return Class.forName(name);
   29.75 -        }
   29.76 -        if (name.startsWith("netscape")) {
   29.77 -            return Class.forName(name);
   29.78 -        }
   29.79 -        if (name.startsWith("com.sun")) {
   29.80 -            return Class.forName(name);
   29.81 -        }
   29.82 -        if (name.equals(JsClassLoader.class.getName())) {
   29.83 -            return JsClassLoader.class;
   29.84 -        }
   29.85 -        if (name.equals(Fn.class.getName())) {
   29.86 -            return Fn.class;
   29.87 -        }
   29.88 -        if (name.equals(Fn.Presenter.class.getName())) {
   29.89 -            return Fn.Presenter.class;
   29.90 -        }
   29.91 -        if (name.equals(FnUtils.class.getName())) {
   29.92 -            return FnUtils.class;
   29.93 -        }
   29.94 -        if (
   29.95 -            name.equals("org.apidesign.html.boot.spi.Fn") ||
   29.96 -            name.equals("org.apidesign.html.boot.impl.FnUtils") ||
   29.97 -            name.equals("org.apidesign.html.boot.impl.FnContext")
   29.98 -        ) {
   29.99 -            return Class.forName(name);
  29.100 -        }
  29.101 -        URL u = findResource(name.replace('.', '/') + ".class");
  29.102 -        if (u != null) {
  29.103 -            InputStream is = null;
  29.104 -            try {
  29.105 -                is = u.openStream();
  29.106 -                byte[] arr = new byte[is.available()];
  29.107 -                int len = 0;
  29.108 -                while (len < arr.length) {
  29.109 -                    int read = is.read(arr, len, arr.length - len);
  29.110 -                    if (read == -1) {
  29.111 -                        throw new IOException("Can't read " + u);
  29.112 -                    }
  29.113 -                    len += read;
  29.114 -                }
  29.115 -                is.close();
  29.116 -                is = null;
  29.117 -                arr = FnUtils.transform(JsClassLoader.this, arr);
  29.118 -                if (arr != null) {
  29.119 -                    return defineClass(name, arr, 0, arr.length);
  29.120 -                }
  29.121 -            } catch (IOException ex) {
  29.122 -                throw new ClassNotFoundException("Can't load " + name, ex);
  29.123 -            } finally {
  29.124 -                try {
  29.125 -                    if (is != null) is.close();
  29.126 -                } catch (IOException ex) {
  29.127 -                    throw new ClassNotFoundException(null, ex);
  29.128 -                }
  29.129 -            }
  29.130 -        }
  29.131 -        return super.findClass(name);
  29.132 -    }
  29.133 -    
  29.134 -    protected abstract Fn defineFn(String code, String... names);
  29.135 -    protected abstract void loadScript(Reader code) throws Exception;
  29.136 -}
    30.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/Test.java	Mon Dec 16 15:48:09 2013 +0100
    30.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.3 @@ -1,57 +0,0 @@
    30.4 -/**
    30.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    30.6 - *
    30.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    30.8 - *
    30.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   30.10 - * Other names may be trademarks of their respective owners.
   30.11 - *
   30.12 - * The contents of this file are subject to the terms of either the GNU
   30.13 - * General Public License Version 2 only ("GPL") or the Common
   30.14 - * Development and Distribution License("CDDL") (collectively, the
   30.15 - * "License"). You may not use this file except in compliance with the
   30.16 - * License. You can obtain a copy of the License at
   30.17 - * http://www.netbeans.org/cddl-gplv2.html
   30.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   30.19 - * specific language governing permissions and limitations under the
   30.20 - * License.  When distributing the software, include this License Header
   30.21 - * Notice in each file and include the License file at
   30.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   30.23 - * particular file as subject to the "Classpath" exception as provided
   30.24 - * by Oracle in the GPL Version 2 section of the License file that
   30.25 - * accompanied this code. If applicable, add the following below the
   30.26 - * License Header, with the fields enclosed by brackets [] replaced by
   30.27 - * your own identifying information:
   30.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   30.29 - *
   30.30 - * Contributor(s):
   30.31 - *
   30.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   30.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   30.34 - *
   30.35 - * If you wish your version of this file to be governed by only the CDDL
   30.36 - * or only the GPL Version 2, indicate your decision by adding
   30.37 - * "[Contributor] elects to include this software in this distribution
   30.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   30.39 - * single choice of license, a recipient has the option to distribute
   30.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   30.41 - * to extend the choice of license to its licensees as provided above.
   30.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   30.43 - * Version 2 license, then the option applies only if the new code is
   30.44 - * made subject to such option by the copyright holder.
   30.45 - */
   30.46 -package org.apidesign.html.boot.impl;
   30.47 -
   30.48 -import java.util.concurrent.Callable;
   30.49 -import net.java.html.js.JavaScriptBody;
   30.50 -
   30.51 -/**
   30.52 - *
   30.53 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   30.54 - */
   30.55 -public final class Test implements Callable<Boolean> {
   30.56 -    @Override @JavaScriptBody(args = {}, body = "return true;")
   30.57 -    public Boolean call() {
   30.58 -        return false;
   30.59 -    }
   30.60 -}
    31.1 --- a/boot/src/main/java/org/apidesign/html/boot/spi/Fn.java	Mon Dec 16 15:48:09 2013 +0100
    31.2 +++ b/boot/src/main/java/org/apidesign/html/boot/spi/Fn.java	Mon Dec 16 16:59:43 2013 +0100
    31.3 @@ -51,9 +51,8 @@
    31.4  import java.util.HashSet;
    31.5  import java.util.Map;
    31.6  import java.util.Set;
    31.7 -import java.util.WeakHashMap;
    31.8  import net.java.html.js.JavaScriptBody;
    31.9 -import org.apidesign.html.boot.impl.FnContext;
   31.10 +import org.netbeans.html.boot.impl.FnContext;
   31.11  
   31.12  /** Represents single JavaScript function that can be invoked. 
   31.13   * Created via {@link Presenter#defineFn(java.lang.String, java.lang.String...)}.
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/FindResources.java	Mon Dec 16 16:59:43 2013 +0100
    32.3 @@ -0,0 +1,56 @@
    32.4 +/**
    32.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    32.6 + *
    32.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    32.8 + *
    32.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   32.10 + * Other names may be trademarks of their respective owners.
   32.11 + *
   32.12 + * The contents of this file are subject to the terms of either the GNU
   32.13 + * General Public License Version 2 only ("GPL") or the Common
   32.14 + * Development and Distribution License("CDDL") (collectively, the
   32.15 + * "License"). You may not use this file except in compliance with the
   32.16 + * License. You can obtain a copy of the License at
   32.17 + * http://www.netbeans.org/cddl-gplv2.html
   32.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   32.19 + * specific language governing permissions and limitations under the
   32.20 + * License.  When distributing the software, include this License Header
   32.21 + * Notice in each file and include the License file at
   32.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   32.23 + * particular file as subject to the "Classpath" exception as provided
   32.24 + * by Oracle in the GPL Version 2 section of the License file that
   32.25 + * accompanied this code. If applicable, add the following below the
   32.26 + * License Header, with the fields enclosed by brackets [] replaced by
   32.27 + * your own identifying information:
   32.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   32.29 + *
   32.30 + * Contributor(s):
   32.31 + *
   32.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   32.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   32.34 + *
   32.35 + * If you wish your version of this file to be governed by only the CDDL
   32.36 + * or only the GPL Version 2, indicate your decision by adding
   32.37 + * "[Contributor] elects to include this software in this distribution
   32.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   32.39 + * single choice of license, a recipient has the option to distribute
   32.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   32.41 + * to extend the choice of license to its licensees as provided above.
   32.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   32.43 + * Version 2 license, then the option applies only if the new code is
   32.44 + * made subject to such option by the copyright holder.
   32.45 + */
   32.46 +package org.netbeans.html.boot.impl;
   32.47 +
   32.48 +import java.net.URL;
   32.49 +import java.util.Collection;
   32.50 +
   32.51 +/**
   32.52 + *
   32.53 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   32.54 + */
   32.55 +public interface FindResources {
   32.56 +
   32.57 +    public void findResources(String path, Collection<? super URL> results, boolean oneIsEnough);
   32.58 +    
   32.59 +}
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java	Mon Dec 16 16:59:43 2013 +0100
    33.3 @@ -0,0 +1,98 @@
    33.4 +/**
    33.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    33.6 + *
    33.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    33.8 + *
    33.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   33.10 + * Other names may be trademarks of their respective owners.
   33.11 + *
   33.12 + * The contents of this file are subject to the terms of either the GNU
   33.13 + * General Public License Version 2 only ("GPL") or the Common
   33.14 + * Development and Distribution License("CDDL") (collectively, the
   33.15 + * "License"). You may not use this file except in compliance with the
   33.16 + * License. You can obtain a copy of the License at
   33.17 + * http://www.netbeans.org/cddl-gplv2.html
   33.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   33.19 + * specific language governing permissions and limitations under the
   33.20 + * License.  When distributing the software, include this License Header
   33.21 + * Notice in each file and include the License file at
   33.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   33.23 + * particular file as subject to the "Classpath" exception as provided
   33.24 + * by Oracle in the GPL Version 2 section of the License file that
   33.25 + * accompanied this code. If applicable, add the following below the
   33.26 + * License Header, with the fields enclosed by brackets [] replaced by
   33.27 + * your own identifying information:
   33.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   33.29 + *
   33.30 + * Contributor(s):
   33.31 + *
   33.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   33.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   33.34 + *
   33.35 + * If you wish your version of this file to be governed by only the CDDL
   33.36 + * or only the GPL Version 2, indicate your decision by adding
   33.37 + * "[Contributor] elects to include this software in this distribution
   33.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   33.39 + * single choice of license, a recipient has the option to distribute
   33.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   33.41 + * to extend the choice of license to its licensees as provided above.
   33.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   33.43 + * Version 2 license, then the option applies only if the new code is
   33.44 + * made subject to such option by the copyright holder.
   33.45 + */
   33.46 +package org.netbeans.html.boot.impl;
   33.47 +
   33.48 +import java.io.Closeable;
   33.49 +import java.io.IOException;
   33.50 +import java.util.logging.Logger;
   33.51 +import org.apidesign.html.boot.spi.Fn;
   33.52 +
   33.53 +/**
   33.54 + *
   33.55 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   33.56 + */
   33.57 +public final class FnContext implements Closeable {
   33.58 +    private static final Logger LOG = Logger.getLogger(FnContext.class.getName());
   33.59 +
   33.60 +    private Object prev;
   33.61 +    private FnContext(Fn.Presenter p) {
   33.62 +        this.prev = p;
   33.63 +    }
   33.64 +
   33.65 +    @Override
   33.66 +    public void close() throws IOException {
   33.67 +        if (prev != this) {
   33.68 +            currentPresenter((Fn.Presenter)prev);
   33.69 +            prev = this;
   33.70 +        }
   33.71 +    }
   33.72 +/*
   33.73 +    @Override
   33.74 +    protected void finalize() throws Throwable {
   33.75 +        if (prev != null) {
   33.76 +            LOG.warning("Unclosed context!");
   33.77 +        }
   33.78 +    }
   33.79 +*/
   33.80 +    public static Closeable activate(Fn.Presenter newP) {
   33.81 +        return new FnContext(currentPresenter(newP));
   33.82 +    }
   33.83 +    
   33.84 +    
   33.85 +    private static final ThreadLocal<Fn.Presenter> CURRENT = new ThreadLocal<Fn.Presenter>();
   33.86 +
   33.87 +    public static Fn.Presenter currentPresenter(Fn.Presenter p) {
   33.88 +        Fn.Presenter prev = CURRENT.get();
   33.89 +        CURRENT.set(p);
   33.90 +        return prev;
   33.91 +    }
   33.92 +
   33.93 +    public static Fn.Presenter currentPresenter() {
   33.94 +        Fn.Presenter p = CURRENT.get();
   33.95 +        if (p == null) {
   33.96 +            throw new IllegalStateException("No current WebView context around!");
   33.97 +        }
   33.98 +        return p;
   33.99 +    }
  33.100 +    
  33.101 +}
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java	Mon Dec 16 16:59:43 2013 +0100
    34.3 @@ -0,0 +1,597 @@
    34.4 +/**
    34.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    34.6 + *
    34.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    34.8 + *
    34.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   34.10 + * Other names may be trademarks of their respective owners.
   34.11 + *
   34.12 + * The contents of this file are subject to the terms of either the GNU
   34.13 + * General Public License Version 2 only ("GPL") or the Common
   34.14 + * Development and Distribution License("CDDL") (collectively, the
   34.15 + * "License"). You may not use this file except in compliance with the
   34.16 + * License. You can obtain a copy of the License at
   34.17 + * http://www.netbeans.org/cddl-gplv2.html
   34.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   34.19 + * specific language governing permissions and limitations under the
   34.20 + * License.  When distributing the software, include this License Header
   34.21 + * Notice in each file and include the License file at
   34.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   34.23 + * particular file as subject to the "Classpath" exception as provided
   34.24 + * by Oracle in the GPL Version 2 section of the License file that
   34.25 + * accompanied this code. If applicable, add the following below the
   34.26 + * License Header, with the fields enclosed by brackets [] replaced by
   34.27 + * your own identifying information:
   34.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   34.29 + *
   34.30 + * Contributor(s):
   34.31 + *
   34.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   34.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   34.34 + *
   34.35 + * If you wish your version of this file to be governed by only the CDDL
   34.36 + * or only the GPL Version 2, indicate your decision by adding
   34.37 + * "[Contributor] elects to include this software in this distribution
   34.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   34.39 + * single choice of license, a recipient has the option to distribute
   34.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   34.41 + * to extend the choice of license to its licensees as provided above.
   34.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   34.43 + * Version 2 license, then the option applies only if the new code is
   34.44 + * made subject to such option by the copyright holder.
   34.45 + */
   34.46 +package org.netbeans.html.boot.impl;
   34.47 +
   34.48 +import java.io.Closeable;
   34.49 +import java.io.InputStream;
   34.50 +import java.io.InputStreamReader;
   34.51 +import java.io.Reader;
   34.52 +import java.net.URL;
   34.53 +import java.util.ArrayList;
   34.54 +import java.util.Collections;
   34.55 +import java.util.Enumeration;
   34.56 +import java.util.List;
   34.57 +import java.util.concurrent.Callable;
   34.58 +import org.apidesign.html.boot.spi.Fn;
   34.59 +import org.objectweb.asm.AnnotationVisitor;
   34.60 +import org.objectweb.asm.ClassReader;
   34.61 +import org.objectweb.asm.ClassVisitor;
   34.62 +import org.objectweb.asm.ClassWriter;
   34.63 +import org.objectweb.asm.Label;
   34.64 +import org.objectweb.asm.MethodVisitor;
   34.65 +import org.objectweb.asm.Opcodes;
   34.66 +import org.objectweb.asm.Type;
   34.67 +import org.objectweb.asm.signature.SignatureReader;
   34.68 +import org.objectweb.asm.signature.SignatureVisitor;
   34.69 +import org.objectweb.asm.signature.SignatureWriter;
   34.70 +
   34.71 +/**
   34.72 + *
   34.73 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   34.74 + */
   34.75 +public final class FnUtils implements Fn.Presenter {
   34.76 +    
   34.77 +    private FnUtils() {
   34.78 +    }
   34.79 +    
   34.80 +    public static boolean isJavaScriptCapable(ClassLoader l) {
   34.81 +        if (l instanceof JsClassLoader) {
   34.82 +            return true;
   34.83 +        }
   34.84 +        Class<?> clazz;
   34.85 +        try (Closeable c = Fn.activate(new FnUtils())) {
   34.86 +            clazz = Class.forName(Test.class.getName(), true, l);
   34.87 +            final Object is = ((Callable<?>)clazz.newInstance()).call();
   34.88 +            return Boolean.TRUE.equals(is);
   34.89 +        } catch (Exception ex) {
   34.90 +            return false;
   34.91 +        }
   34.92 +    }
   34.93 +    
   34.94 +    public static boolean isValid(Fn fn) {
   34.95 +        return fn != null && fn.isValid();
   34.96 +    }
   34.97 +
   34.98 +    public static ClassLoader newLoader(final FindResources f, final Fn.Presenter d, ClassLoader parent) {
   34.99 +        return new JsClassLoader(parent) {
  34.100 +            @Override
  34.101 +            protected URL findResource(String name) {
  34.102 +                List<URL> l = res(name, true);
  34.103 +                return l.isEmpty() ? null : l.get(0);
  34.104 +            }
  34.105 +            
  34.106 +            @Override
  34.107 +            protected Enumeration<URL> findResources(String name) {
  34.108 +                return Collections.enumeration(res(name, false));
  34.109 +            }
  34.110 +            
  34.111 +            private List<URL> res(String name, boolean oneIsEnough) {
  34.112 +                List<URL> l = new ArrayList<URL>();
  34.113 +                f.findResources(name, l, oneIsEnough);
  34.114 +                return l;
  34.115 +            }
  34.116 +            
  34.117 +            @Override
  34.118 +            protected Fn defineFn(String code, String... names) {
  34.119 +                return d.defineFn(code, names);
  34.120 +            }
  34.121 +
  34.122 +            @Override
  34.123 +            protected void loadScript(Reader code) throws Exception {
  34.124 +                d.loadScript(code);
  34.125 +            }
  34.126 +        };
  34.127 +    }
  34.128 +
  34.129 +    static String callback(final String body) {
  34.130 +        return new JsCallback() {
  34.131 +            @Override
  34.132 +            protected CharSequence callMethod(
  34.133 +                String ident, String fqn, String method, String params
  34.134 +            ) {
  34.135 +                StringBuilder sb = new StringBuilder();
  34.136 +                sb.append("vm.").append(mangle(fqn, method, params));
  34.137 +                sb.append("(");
  34.138 +                if (ident != null) {
  34.139 +                    sb.append(ident);
  34.140 +                }
  34.141 +                return sb;
  34.142 +            }
  34.143 +
  34.144 +        }.parse(body);
  34.145 +    }
  34.146 +
  34.147 +    static void loadScript(ClassLoader jcl, String resource) {
  34.148 +        final InputStream script = jcl.getResourceAsStream(resource);
  34.149 +        if (script == null) {
  34.150 +            throw new NullPointerException("Can't find " + resource);
  34.151 +        }
  34.152 +        try {
  34.153 +            Reader isr = null;
  34.154 +            try {
  34.155 +                isr = new InputStreamReader(script, "UTF-8");
  34.156 +                FnContext.currentPresenter().loadScript(isr);
  34.157 +            } finally {
  34.158 +                if (isr != null) {
  34.159 +                    isr.close();
  34.160 +                }
  34.161 +            }
  34.162 +        } catch (Exception ex) {
  34.163 +            throw new IllegalStateException("Can't execute " + resource, ex);
  34.164 +        } 
  34.165 +    }
  34.166 +
  34.167 +    @Override
  34.168 +    public Fn defineFn(String code, String... names) {
  34.169 +        return new TrueFn();
  34.170 +    }
  34.171 +
  34.172 +    @Override
  34.173 +    public void displayPage(URL page, Runnable onPageLoad) {
  34.174 +    }
  34.175 +
  34.176 +    @Override
  34.177 +    public void loadScript(Reader code) throws Exception {
  34.178 +    }
  34.179 +    
  34.180 +    private static final class FindInClass extends ClassVisitor {
  34.181 +        private String name;
  34.182 +        private int found;
  34.183 +        private ClassLoader loader;
  34.184 +        private String resource;
  34.185 +
  34.186 +        public FindInClass(ClassLoader l, ClassVisitor cv) {
  34.187 +            super(Opcodes.ASM4, cv);
  34.188 +            this.loader = l;
  34.189 +        }
  34.190 +
  34.191 +        @Override
  34.192 +        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
  34.193 +            this.name = name;
  34.194 +            super.visit(version, access, name, signature, superName, interfaces);
  34.195 +        }
  34.196 +
  34.197 +        @Override
  34.198 +        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
  34.199 +            if ("Lnet/java/html/js/JavaScriptResource;".equals(desc)) {
  34.200 +                return new LoadResource();
  34.201 +            }
  34.202 +            return super.visitAnnotation(desc, visible);
  34.203 +        }
  34.204 +
  34.205 +        @Override
  34.206 +        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
  34.207 +            return new FindInMethod(access, name, desc,
  34.208 +                    super.visitMethod(access & (~Opcodes.ACC_NATIVE), name, desc, signature, exceptions)
  34.209 +            );
  34.210 +        }
  34.211 +
  34.212 +        private final class FindInMethod extends MethodVisitor {
  34.213 +
  34.214 +            private final String name;
  34.215 +            private final String desc;
  34.216 +            private final int access;
  34.217 +            private List<String> args;
  34.218 +            private String body;
  34.219 +            private boolean bodyGenerated;
  34.220 +
  34.221 +            public FindInMethod(int access, String name, String desc, MethodVisitor mv) {
  34.222 +                super(Opcodes.ASM4, mv);
  34.223 +                this.access = access;
  34.224 +                this.name = name;
  34.225 +                this.desc = desc;
  34.226 +            }
  34.227 +
  34.228 +            @Override
  34.229 +            public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
  34.230 +                if ("Lnet/java/html/js/JavaScriptBody;".equals(desc) // NOI18N
  34.231 +                        || "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;".equals(desc) // NOI18N
  34.232 +                        ) {
  34.233 +                    found++;
  34.234 +                    return new FindInAnno();
  34.235 +                }
  34.236 +                return super.visitAnnotation(desc, visible);
  34.237 +            }
  34.238 +
  34.239 +            private void generateJSBody(List<String> args, String body) {
  34.240 +                this.args = args;
  34.241 +                this.body = body;
  34.242 +            }
  34.243 +
  34.244 +            @Override
  34.245 +            public void visitCode() {
  34.246 +                if (body == null) {
  34.247 +                    return;
  34.248 +                }
  34.249 +                generateBody();
  34.250 +            }
  34.251 +
  34.252 +            private boolean generateBody() {
  34.253 +                if (bodyGenerated) {
  34.254 +                    return false;
  34.255 +                }
  34.256 +                bodyGenerated = true;
  34.257 +
  34.258 +                super.visitFieldInsn(
  34.259 +                        Opcodes.GETSTATIC, FindInClass.this.name,
  34.260 +                        "$$fn$$" + name + "_" + found,
  34.261 +                        "Lorg/apidesign/html/boot/spi/Fn;"
  34.262 +                );
  34.263 +                super.visitInsn(Opcodes.DUP);
  34.264 +                super.visitMethodInsn(
  34.265 +                        Opcodes.INVOKESTATIC,
  34.266 +                        "org/apidesign/html/boot/spi/Fn", "isValid",
  34.267 +                        "(Lorg/apidesign/html/boot/spi/Fn;)Z"
  34.268 +                );
  34.269 +                Label ifNotNull = new Label();
  34.270 +                super.visitJumpInsn(Opcodes.IFNE, ifNotNull);
  34.271 +
  34.272 +                // init Fn
  34.273 +                super.visitInsn(Opcodes.POP);
  34.274 +                super.visitLdcInsn(Type.getObjectType(FindInClass.this.name));
  34.275 +                super.visitLdcInsn(body);
  34.276 +                super.visitIntInsn(Opcodes.SIPUSH, args.size());
  34.277 +                super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String");
  34.278 +                boolean needsVM = false;
  34.279 +                for (int i = 0; i < args.size(); i++) {
  34.280 +                    assert !needsVM;
  34.281 +                    String argName = args.get(i);
  34.282 +                    needsVM = "vm".equals(argName);
  34.283 +                    super.visitInsn(Opcodes.DUP);
  34.284 +                    super.visitIntInsn(Opcodes.BIPUSH, i);
  34.285 +                    super.visitLdcInsn(argName);
  34.286 +                    super.visitInsn(Opcodes.AASTORE);
  34.287 +                }
  34.288 +                super.visitMethodInsn(Opcodes.INVOKESTATIC,
  34.289 +                        "org/apidesign/html/boot/spi/Fn", "define",
  34.290 +                        "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/String;)Lorg/apidesign/html/boot/spi/Fn;"
  34.291 +                );
  34.292 +                if (resource != null) {
  34.293 +                    super.visitLdcInsn(Type.getObjectType(FindInClass.this.name));
  34.294 +                    super.visitLdcInsn(resource);
  34.295 +                    super.visitMethodInsn(Opcodes.INVOKESTATIC,
  34.296 +                            "org/apidesign/html/boot/spi/Fn", "preload",
  34.297 +                            "(Lorg/apidesign/html/boot/spi/Fn;Ljava/lang/Class;Ljava/lang/String;)Lorg/apidesign/html/boot/spi/Fn;"
  34.298 +                    );
  34.299 +                }
  34.300 +                super.visitInsn(Opcodes.DUP);
  34.301 +                super.visitFieldInsn(
  34.302 +                        Opcodes.PUTSTATIC, FindInClass.this.name,
  34.303 +                        "$$fn$$" + name + "_" + found,
  34.304 +                        "Lorg/apidesign/html/boot/spi/Fn;"
  34.305 +                );
  34.306 +                // end of Fn init
  34.307 +
  34.308 +                super.visitLabel(ifNotNull);
  34.309 +
  34.310 +                final int offset;
  34.311 +                if ((access & Opcodes.ACC_STATIC) == 0) {
  34.312 +                    offset = 1;
  34.313 +                    super.visitIntInsn(Opcodes.ALOAD, 0);
  34.314 +                } else {
  34.315 +                    offset = 0;
  34.316 +                    super.visitInsn(Opcodes.ACONST_NULL);
  34.317 +                }
  34.318 +
  34.319 +                super.visitIntInsn(Opcodes.SIPUSH, args.size());
  34.320 +                super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
  34.321 +
  34.322 +                class SV extends SignatureVisitor {
  34.323 +
  34.324 +                    private boolean nowReturn;
  34.325 +                    private Type returnType;
  34.326 +                    private int index;
  34.327 +                    private int loadIndex = offset;
  34.328 +
  34.329 +                    public SV() {
  34.330 +                        super(Opcodes.ASM4);
  34.331 +                    }
  34.332 +
  34.333 +                    @Override
  34.334 +                    public void visitBaseType(char descriptor) {
  34.335 +                        final Type t = Type.getType("" + descriptor);
  34.336 +                        if (nowReturn) {
  34.337 +                            returnType = t;
  34.338 +                            return;
  34.339 +                        }
  34.340 +                        FindInMethod.super.visitInsn(Opcodes.DUP);
  34.341 +                        FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++);
  34.342 +                        FindInMethod.super.visitVarInsn(t.getOpcode(Opcodes.ILOAD), loadIndex++);
  34.343 +                        String factory;
  34.344 +                        switch (descriptor) {
  34.345 +                            case 'I':
  34.346 +                                factory = "java/lang/Integer";
  34.347 +                                break;
  34.348 +                            case 'J':
  34.349 +                                factory = "java/lang/Long";
  34.350 +                                loadIndex++;
  34.351 +                                break;
  34.352 +                            case 'S':
  34.353 +                                factory = "java/lang/Short";
  34.354 +                                break;
  34.355 +                            case 'F':
  34.356 +                                factory = "java/lang/Float";
  34.357 +                                break;
  34.358 +                            case 'D':
  34.359 +                                factory = "java/lang/Double";
  34.360 +                                loadIndex++;
  34.361 +                                break;
  34.362 +                            case 'Z':
  34.363 +                                factory = "java/lang/Boolean";
  34.364 +                                break;
  34.365 +                            case 'C':
  34.366 +                                factory = "java/lang/Character";
  34.367 +                                break;
  34.368 +                            case 'B':
  34.369 +                                factory = "java/lang/Byte";
  34.370 +                                break;
  34.371 +                            default:
  34.372 +                                throw new IllegalStateException(t.toString());
  34.373 +                        }
  34.374 +                        FindInMethod.super.visitMethodInsn(Opcodes.INVOKESTATIC,
  34.375 +                                factory, "valueOf", "(" + descriptor + ")L" + factory + ";"
  34.376 +                        );
  34.377 +                        FindInMethod.super.visitInsn(Opcodes.AASTORE);
  34.378 +                    }
  34.379 +
  34.380 +                    @Override
  34.381 +                    public SignatureVisitor visitArrayType() {
  34.382 +                        if (nowReturn) {
  34.383 +                            throw new IllegalStateException("Not supported yet");
  34.384 +                        }
  34.385 +                        loadObject();
  34.386 +                        return new SignatureWriter();
  34.387 +                    }
  34.388 +
  34.389 +                    @Override
  34.390 +                    public void visitClassType(String name) {
  34.391 +                        if (nowReturn) {
  34.392 +                            returnType = Type.getObjectType(name);
  34.393 +                            return;
  34.394 +                        }
  34.395 +                        loadObject();
  34.396 +                    }
  34.397 +
  34.398 +                    @Override
  34.399 +                    public SignatureVisitor visitReturnType() {
  34.400 +                        nowReturn = true;
  34.401 +                        return this;
  34.402 +                    }
  34.403 +
  34.404 +                    private void loadObject() {
  34.405 +                        FindInMethod.super.visitInsn(Opcodes.DUP);
  34.406 +                        FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++);
  34.407 +                        FindInMethod.super.visitVarInsn(Opcodes.ALOAD, loadIndex++);
  34.408 +                        FindInMethod.super.visitInsn(Opcodes.AASTORE);
  34.409 +                    }
  34.410 +
  34.411 +                }
  34.412 +                SV sv = new SV();
  34.413 +                SignatureReader sr = new SignatureReader(desc);
  34.414 +                sr.accept(sv);
  34.415 +
  34.416 +                if (needsVM) {
  34.417 +                    FindInMethod.super.visitInsn(Opcodes.DUP);
  34.418 +                    FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, sv.index);
  34.419 +                    int lastSlash = FindInClass.this.name.lastIndexOf('/');
  34.420 +                    String jsCallbacks = FindInClass.this.name.substring(0, lastSlash + 1) + "$JsCallbacks$";
  34.421 +                    FindInMethod.super.visitFieldInsn(Opcodes.GETSTATIC, jsCallbacks, "VM", "L" + jsCallbacks + ";");
  34.422 +                    FindInMethod.super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, jsCallbacks, "current", "()L" + jsCallbacks + ";");
  34.423 +                    FindInMethod.super.visitInsn(Opcodes.AASTORE);
  34.424 +                }
  34.425 +
  34.426 +                super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
  34.427 +                        "org/apidesign/html/boot/spi/Fn", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
  34.428 +                );
  34.429 +                switch (sv.returnType.getSort()) {
  34.430 +                    case Type.VOID:
  34.431 +                        super.visitInsn(Opcodes.RETURN);
  34.432 +                        break;
  34.433 +                    case Type.ARRAY:
  34.434 +                    case Type.OBJECT:
  34.435 +                        super.visitTypeInsn(Opcodes.CHECKCAST, sv.returnType.getInternalName());
  34.436 +                        super.visitInsn(Opcodes.ARETURN);
  34.437 +                        break;
  34.438 +                    case Type.BOOLEAN:
  34.439 +                        super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Boolean");
  34.440 +                        super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
  34.441 +                                "java/lang/Boolean", "booleanValue", "()Z"
  34.442 +                        );
  34.443 +                        super.visitInsn(Opcodes.IRETURN);
  34.444 +                        break;
  34.445 +                    default:
  34.446 +                        super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number");
  34.447 +                        super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
  34.448 +                                "java/lang/Number", sv.returnType.getClassName() + "Value", "()" + sv.returnType.getDescriptor()
  34.449 +                        );
  34.450 +                        super.visitInsn(sv.returnType.getOpcode(Opcodes.IRETURN));
  34.451 +                }
  34.452 +                return true;
  34.453 +            }
  34.454 +
  34.455 +            @Override
  34.456 +            public void visitEnd() {
  34.457 +                super.visitEnd();
  34.458 +                if (body != null) {
  34.459 +                    if (generateBody()) {
  34.460 +                        // native method
  34.461 +                        super.visitMaxs(1, 0);
  34.462 +                    }
  34.463 +                    FindInClass.this.visitField(
  34.464 +                            Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
  34.465 +                            "$$fn$$" + name + "_" + found,
  34.466 +                            "Lorg/apidesign/html/boot/spi/Fn;",
  34.467 +                            null, null
  34.468 +                    );
  34.469 +                }
  34.470 +            }
  34.471 +
  34.472 +            private final class FindInAnno extends AnnotationVisitor {
  34.473 +
  34.474 +                private List<String> args = new ArrayList<String>();
  34.475 +                private String body;
  34.476 +                private boolean javacall = false;
  34.477 +
  34.478 +                public FindInAnno() {
  34.479 +                    super(Opcodes.ASM4);
  34.480 +                }
  34.481 +
  34.482 +                @Override
  34.483 +                public void visit(String name, Object value) {
  34.484 +                    if (name == null) {
  34.485 +                        args.add((String) value);
  34.486 +                        return;
  34.487 +                    }
  34.488 +                    if (name.equals("javacall")) { // NOI18N
  34.489 +                        javacall = (Boolean) value;
  34.490 +                        return;
  34.491 +                    }
  34.492 +                    assert name.equals("body");
  34.493 +                    body = (String) value;
  34.494 +                }
  34.495 +
  34.496 +                @Override
  34.497 +                public AnnotationVisitor visitArray(String name) {
  34.498 +                    return this;
  34.499 +                }
  34.500 +
  34.501 +                @Override
  34.502 +                public void visitEnd() {
  34.503 +                    if (body != null) {
  34.504 +                        if (javacall) {
  34.505 +                            body = callback(body);
  34.506 +                            args.add("vm");
  34.507 +                        }
  34.508 +                        generateJSBody(args, body);
  34.509 +                    }
  34.510 +                }
  34.511 +            }
  34.512 +        }
  34.513 +
  34.514 +        private final class LoadResource extends AnnotationVisitor {
  34.515 +
  34.516 +            public LoadResource() {
  34.517 +                super(Opcodes.ASM4);
  34.518 +            }
  34.519 +
  34.520 +            @Override
  34.521 +            public void visit(String attrName, Object value) {
  34.522 +                String relPath = (String) value;
  34.523 +                if (relPath.startsWith("/")) {
  34.524 +                    resource = relPath;
  34.525 +                } else {
  34.526 +                    int last = name.lastIndexOf('/');
  34.527 +                    String fullPath = name.substring(0, last + 1) + relPath;
  34.528 +                    resource = fullPath;
  34.529 +                }
  34.530 +            }
  34.531 +        }
  34.532 +    }
  34.533 +
  34.534 +    private static class ClassWriterEx extends ClassWriter {
  34.535 +
  34.536 +        private ClassLoader loader;
  34.537 +
  34.538 +        public ClassWriterEx(ClassLoader l, ClassReader classReader, int flags) {
  34.539 +            super(classReader, flags);
  34.540 +            this.loader = l;
  34.541 +        }
  34.542 +
  34.543 +        @Override
  34.544 +        protected String getCommonSuperClass(final String type1, final String type2) {
  34.545 +            Class<?> c, d;
  34.546 +            try {
  34.547 +                c = Class.forName(type1.replace('/', '.'), false, loader);
  34.548 +                d = Class.forName(type2.replace('/', '.'), false, loader);
  34.549 +            } catch (Exception e) {
  34.550 +                throw new RuntimeException(e.toString());
  34.551 +            }
  34.552 +            if (c.isAssignableFrom(d)) {
  34.553 +                return type1;
  34.554 +            }
  34.555 +            if (d.isAssignableFrom(c)) {
  34.556 +                return type2;
  34.557 +            }
  34.558 +            if (c.isInterface() || d.isInterface()) {
  34.559 +                return "java/lang/Object";
  34.560 +            } else {
  34.561 +                do {
  34.562 +                    c = c.getSuperclass();
  34.563 +                } while (!c.isAssignableFrom(d));
  34.564 +                return c.getName().replace('.', '/');
  34.565 +            }
  34.566 +        }
  34.567 +    }
  34.568 +
  34.569 +    static byte[] transform(ClassLoader loader, byte[] arr) {
  34.570 +        ClassReader cr = new ClassReader(arr) {
  34.571 +            // to allow us to compile with -profile compact1 on 
  34.572 +            // JDK8 while processing the class as JDK7, the highest
  34.573 +            // class format asm 4.1 understands to
  34.574 +            @Override
  34.575 +            public short readShort(int index) {
  34.576 +                short s = super.readShort(index);
  34.577 +                if (index == 6 && s > Opcodes.V1_7) {
  34.578 +                    return Opcodes.V1_7;
  34.579 +                }
  34.580 +                return s;
  34.581 +            }
  34.582 +        };
  34.583 +        FindInClass tst = new FindInClass(loader, null);
  34.584 +        cr.accept(tst, 0);
  34.585 +        if (tst.found > 0) {
  34.586 +            ClassWriter w = new ClassWriterEx(loader, cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
  34.587 +            FindInClass fic = new FindInClass(loader, w);
  34.588 +            cr.accept(fic, 0);
  34.589 +            arr = w.toByteArray();
  34.590 +        }
  34.591 +        return arr;
  34.592 +    }
  34.593 +
  34.594 +    private static final class TrueFn extends Fn {
  34.595 +        @Override
  34.596 +        public Object invoke(Object thiz, Object... args) throws Exception {
  34.597 +            return Boolean.TRUE;
  34.598 +        }
  34.599 +    } // end of TrueFn
  34.600 +}
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/JavaScriptProcesor.java	Mon Dec 16 16:59:43 2013 +0100
    35.3 @@ -0,0 +1,369 @@
    35.4 +/**
    35.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    35.6 + *
    35.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    35.8 + *
    35.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   35.10 + * Other names may be trademarks of their respective owners.
   35.11 + *
   35.12 + * The contents of this file are subject to the terms of either the GNU
   35.13 + * General Public License Version 2 only ("GPL") or the Common
   35.14 + * Development and Distribution License("CDDL") (collectively, the
   35.15 + * "License"). You may not use this file except in compliance with the
   35.16 + * License. You can obtain a copy of the License at
   35.17 + * http://www.netbeans.org/cddl-gplv2.html
   35.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   35.19 + * specific language governing permissions and limitations under the
   35.20 + * License.  When distributing the software, include this License Header
   35.21 + * Notice in each file and include the License file at
   35.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   35.23 + * particular file as subject to the "Classpath" exception as provided
   35.24 + * by Oracle in the GPL Version 2 section of the License file that
   35.25 + * accompanied this code. If applicable, add the following below the
   35.26 + * License Header, with the fields enclosed by brackets [] replaced by
   35.27 + * your own identifying information:
   35.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   35.29 + *
   35.30 + * Contributor(s):
   35.31 + *
   35.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   35.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   35.34 + *
   35.35 + * If you wish your version of this file to be governed by only the CDDL
   35.36 + * or only the GPL Version 2, indicate your decision by adding
   35.37 + * "[Contributor] elects to include this software in this distribution
   35.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   35.39 + * single choice of license, a recipient has the option to distribute
   35.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   35.41 + * to extend the choice of license to its licensees as provided above.
   35.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   35.43 + * Version 2 license, then the option applies only if the new code is
   35.44 + * made subject to such option by the copyright holder.
   35.45 + */
   35.46 +package org.netbeans.html.boot.impl;
   35.47 +
   35.48 +import java.io.IOException;
   35.49 +import java.io.Writer;
   35.50 +import java.util.Collections;
   35.51 +import java.util.HashMap;
   35.52 +import java.util.HashSet;
   35.53 +import java.util.List;
   35.54 +import java.util.Map;
   35.55 +import java.util.Set;
   35.56 +import java.util.TreeMap;
   35.57 +import javax.annotation.processing.AbstractProcessor;
   35.58 +import javax.annotation.processing.Completion;
   35.59 +import javax.annotation.processing.Completions;
   35.60 +import javax.annotation.processing.Messager;
   35.61 +import javax.annotation.processing.Processor;
   35.62 +import javax.annotation.processing.RoundEnvironment;
   35.63 +import javax.lang.model.SourceVersion;
   35.64 +import javax.lang.model.element.AnnotationMirror;
   35.65 +import javax.lang.model.element.Element;
   35.66 +import javax.lang.model.element.ElementKind;
   35.67 +import javax.lang.model.element.ExecutableElement;
   35.68 +import javax.lang.model.element.Modifier;
   35.69 +import javax.lang.model.element.PackageElement;
   35.70 +import javax.lang.model.element.TypeElement;
   35.71 +import javax.lang.model.element.VariableElement;
   35.72 +import javax.lang.model.type.ArrayType;
   35.73 +import javax.lang.model.type.ExecutableType;
   35.74 +import javax.lang.model.type.TypeKind;
   35.75 +import javax.lang.model.type.TypeMirror;
   35.76 +import javax.tools.Diagnostic;
   35.77 +import javax.tools.FileObject;
   35.78 +import javax.tools.StandardLocation;
   35.79 +import net.java.html.js.JavaScriptBody;
   35.80 +import net.java.html.js.JavaScriptResource;
   35.81 +import org.openide.util.lookup.ServiceProvider;
   35.82 +
   35.83 +/**
   35.84 + *
   35.85 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   35.86 + */
   35.87 +@ServiceProvider(service = Processor.class)
   35.88 +public final class JavaScriptProcesor extends AbstractProcessor {
   35.89 +    private final Map<String,Map<String,ExecutableElement>> javacalls = 
   35.90 +        new HashMap<String,Map<String,ExecutableElement>>();
   35.91 +    
   35.92 +    @Override
   35.93 +    public Set<String> getSupportedAnnotationTypes() {
   35.94 +        Set<String> set = new HashSet<String>();
   35.95 +        set.add(JavaScriptBody.class.getName());
   35.96 +        set.add(JavaScriptResource.class.getName());
   35.97 +        return set;
   35.98 +    }
   35.99 +    
  35.100 +    @Override
  35.101 +    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
  35.102 +        final Messager msg = processingEnv.getMessager();
  35.103 +        for (Element e : roundEnv.getElementsAnnotatedWith(JavaScriptBody.class)) {
  35.104 +            if (e.getKind() != ElementKind.METHOD && e.getKind() != ElementKind.CONSTRUCTOR) {
  35.105 +                continue;
  35.106 +            }
  35.107 +            ExecutableElement ee = (ExecutableElement)e;
  35.108 +            List<? extends VariableElement> params = ee.getParameters();
  35.109 +            
  35.110 +            JavaScriptBody jsb = e.getAnnotation(JavaScriptBody.class);
  35.111 +            if (jsb == null) {
  35.112 +                continue;
  35.113 +            }
  35.114 +            String[] arr = jsb.args();
  35.115 +            if (params.size() != arr.length) {
  35.116 +                msg.printMessage(Diagnostic.Kind.ERROR, "Number of args arguments does not match real arguments!", e);
  35.117 +            }
  35.118 +            if (!jsb.javacall() && jsb.body().contains(".@")) {
  35.119 +                msg.printMessage(Diagnostic.Kind.WARNING, "Usage of .@ usually requires javacall=true", e);
  35.120 +            }
  35.121 +            if (jsb.javacall()) {
  35.122 +                JsCallback verify = new VerifyCallback(e);
  35.123 +                try {
  35.124 +                    verify.parse(jsb.body());
  35.125 +                } catch (IllegalStateException ex) {
  35.126 +                    msg.printMessage(Diagnostic.Kind.ERROR, ex.getLocalizedMessage(), e);
  35.127 +                }
  35.128 +            }
  35.129 +        }
  35.130 +        for (Element e : roundEnv.getElementsAnnotatedWith(JavaScriptResource.class)) {
  35.131 +            JavaScriptResource r = e.getAnnotation(JavaScriptResource.class);
  35.132 +            if (r == null) {
  35.133 +                continue;
  35.134 +            }
  35.135 +            final String res;
  35.136 +            if (r.value().startsWith("/")) {
  35.137 +                res = r.value();
  35.138 +            } else {
  35.139 +                res = findPkg(e).replace('.', '/') + "/" + r.value();
  35.140 +            }
  35.141 +            
  35.142 +            try {
  35.143 +                FileObject os = processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", res);
  35.144 +                os.openInputStream().close();
  35.145 +            } catch (IOException ex1) {
  35.146 +                try {
  35.147 +                    FileObject os2 = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", res);
  35.148 +                    os2.openInputStream().close();
  35.149 +                } catch (IOException ex2) {
  35.150 +                    msg.printMessage(Diagnostic.Kind.ERROR, "Cannot find " + res + " in " + res + " package", e);
  35.151 +                }
  35.152 +            }
  35.153 +        }
  35.154 +
  35.155 +        if (roundEnv.processingOver()) {
  35.156 +            generateCallbackClass(javacalls);
  35.157 +            javacalls.clear();
  35.158 +        }
  35.159 +        return true;
  35.160 +    }
  35.161 +
  35.162 +    @Override
  35.163 +    public Iterable<? extends Completion> getCompletions(Element e, 
  35.164 +        AnnotationMirror annotation, ExecutableElement member, String userText
  35.165 +    ) {
  35.166 +        StringBuilder sb = new StringBuilder();
  35.167 +        if (e.getKind() == ElementKind.METHOD && member.getSimpleName().contentEquals("args")) {
  35.168 +            ExecutableElement ee = (ExecutableElement) e;
  35.169 +            String sep = "";
  35.170 +            sb.append("{ ");
  35.171 +            for (VariableElement ve : ee.getParameters()) {
  35.172 +                sb.append(sep).append('"').append(ve.getSimpleName())
  35.173 +                    .append('"');
  35.174 +                sep = ", ";
  35.175 +            }
  35.176 +            sb.append(" }");
  35.177 +            return Collections.nCopies(1, Completions.of(sb.toString()));
  35.178 +        }
  35.179 +        return null;
  35.180 +    }
  35.181 +
  35.182 +    private class VerifyCallback extends JsCallback {
  35.183 +        private final Element e;
  35.184 +        public VerifyCallback(Element e) {
  35.185 +            this.e = e;
  35.186 +        }
  35.187 +
  35.188 +        @Override
  35.189 +        protected CharSequence callMethod(String ident, String fqn, String method, String params) {
  35.190 +            final TypeElement type = processingEnv.getElementUtils().getTypeElement(fqn);
  35.191 +            if (type == null) {
  35.192 +                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, 
  35.193 +                    "Callback to non-existing class " + fqn, e
  35.194 +                );
  35.195 +                return "";
  35.196 +            }
  35.197 +            ExecutableElement found = null;
  35.198 +            StringBuilder foundParams = new StringBuilder();
  35.199 +            for (Element m : type.getEnclosedElements()) {
  35.200 +                if (m.getKind() != ElementKind.METHOD) {
  35.201 +                    continue;
  35.202 +                }
  35.203 +                if (m.getSimpleName().contentEquals(method)) {
  35.204 +                    String paramTypes = findParamTypes((ExecutableElement)m);
  35.205 +                    if (paramTypes.equals(params)) {
  35.206 +                        found = (ExecutableElement) m;
  35.207 +                        break;
  35.208 +                    }
  35.209 +                    foundParams.append(paramTypes).append("\n");
  35.210 +                }
  35.211 +            }
  35.212 +            if (found == null) {
  35.213 +                if (foundParams.length() == 0) {
  35.214 +                    processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, 
  35.215 +                        "Callback to class " + fqn + " with unknown method " + method, e
  35.216 +                    );
  35.217 +                } else {
  35.218 +                    processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, 
  35.219 +                        "Callback to " + fqn + "." + method + " with wrong parameters: " + 
  35.220 +                        params + ". Only known parameters are " + foundParams, e
  35.221 +                    );
  35.222 +                }
  35.223 +            } else {
  35.224 +                Map<String,ExecutableElement> mangledOnes = javacalls.get(findPkg(e));
  35.225 +                if (mangledOnes == null) {
  35.226 +                    mangledOnes = new TreeMap<String, ExecutableElement>();
  35.227 +                    javacalls.put(findPkg(e), mangledOnes);
  35.228 +                }
  35.229 +                String mangled = JsCallback.mangle(fqn, method, findParamTypes(found));
  35.230 +                mangledOnes.put(mangled, found);
  35.231 +            }
  35.232 +            return "";
  35.233 +        }
  35.234 +
  35.235 +        private String findParamTypes(ExecutableElement method) {
  35.236 +            ExecutableType t = (ExecutableType) method.asType();
  35.237 +            StringBuilder sb = new StringBuilder();
  35.238 +            sb.append('(');
  35.239 +            for (TypeMirror tm : t.getParameterTypes()) {
  35.240 +                if (tm.getKind().isPrimitive()) {
  35.241 +                    switch (tm.getKind()) {
  35.242 +                        case INT: sb.append('I'); break;
  35.243 +                        case BOOLEAN: sb.append('Z'); break;
  35.244 +                        case BYTE: sb.append('B'); break;
  35.245 +                        case CHAR: sb.append('C'); break;
  35.246 +                        case SHORT: sb.append('S'); break;
  35.247 +                        case DOUBLE: sb.append('D'); break;
  35.248 +                        case FLOAT: sb.append('F'); break;
  35.249 +                        case LONG: sb.append('J'); break;
  35.250 +                        default:
  35.251 +                            throw new IllegalStateException("Uknown " + tm.getKind());
  35.252 +                    }
  35.253 +                } else {
  35.254 +                    while (tm.getKind() == TypeKind.ARRAY) {
  35.255 +                        sb.append('[');
  35.256 +                        tm = ((ArrayType)tm).getComponentType();
  35.257 +                    }
  35.258 +                    sb.append('L');
  35.259 +                    sb.append(tm.toString().replace('.', '/'));
  35.260 +                    sb.append(';');
  35.261 +                }
  35.262 +            }
  35.263 +            sb.append(')');
  35.264 +            return sb.toString();
  35.265 +        }
  35.266 +    }
  35.267 +    
  35.268 +    private void generateCallbackClass(Map<String,Map<String, ExecutableElement>> process) {
  35.269 +        for (Map.Entry<String, Map<String, ExecutableElement>> pkgEn : process.entrySet()) {
  35.270 +            String pkgName = pkgEn.getKey();
  35.271 +            Map<String, ExecutableElement> map = pkgEn.getValue();
  35.272 +            StringBuilder source = new StringBuilder();
  35.273 +            source.append("package ").append(pkgName).append(";\n");
  35.274 +            source.append("public final class $JsCallbacks$ {\n");
  35.275 +            source.append("  static final $JsCallbacks$ VM = new $JsCallbacks$(null);\n");
  35.276 +            source.append("  private final org.apidesign.html.boot.spi.Fn.Presenter p;\n");
  35.277 +            source.append("  private $JsCallbacks$ last;\n");
  35.278 +            source.append("  private $JsCallbacks$(org.apidesign.html.boot.spi.Fn.Presenter p) {\n");
  35.279 +            source.append("    this.p = p;\n");
  35.280 +            source.append("  }\n");
  35.281 +            source.append("  final $JsCallbacks$ current() {\n");
  35.282 +            source.append("    org.apidesign.html.boot.spi.Fn.Presenter now = org.apidesign.html.boot.spi.Fn.activePresenter();\n");
  35.283 +            source.append("    if (now == p) return this;\n");
  35.284 +            source.append("    if (last != null && now == last.p) return last;\n");
  35.285 +            source.append("    return last = new $JsCallbacks$(now);\n");
  35.286 +            source.append("  }\n");
  35.287 +            for (Map.Entry<String, ExecutableElement> entry : map.entrySet()) {
  35.288 +                final String mangled = entry.getKey();
  35.289 +                final ExecutableElement m = entry.getValue();
  35.290 +                final boolean isStatic = m.getModifiers().contains(Modifier.STATIC);
  35.291 +                
  35.292 +                source.append("\n  public java.lang.Object ")
  35.293 +                    .append(mangled)
  35.294 +                    .append("(");
  35.295 +                
  35.296 +                String sep = "";
  35.297 +                if (!isStatic) {
  35.298 +                    source.append(((TypeElement)m.getEnclosingElement()).getQualifiedName());
  35.299 +                    source.append(" self");
  35.300 +                    sep = ", ";
  35.301 +                }
  35.302 +                
  35.303 +                int cnt = 0;
  35.304 +                for (VariableElement ve : m.getParameters()) {
  35.305 +                    source.append(sep);
  35.306 +                    source.append(ve.asType());
  35.307 +                    source.append(" arg").append(++cnt);
  35.308 +                    sep = ", ";
  35.309 +                }
  35.310 +                source.append(") throws Throwable {\n");
  35.311 +                if (processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_7) >= 0) {
  35.312 +                    source.append("    try (java.io.Closeable a = org.apidesign.html.boot.spi.Fn.activate(p)) { \n");
  35.313 +                } else {
  35.314 +                    source.append("    java.io.Closeable a = org.apidesign.html.boot.spi.Fn.activate(p); try {\n");
  35.315 +                }
  35.316 +                source.append("    ");
  35.317 +                if (m.getReturnType().getKind() != TypeKind.VOID) {
  35.318 +                    source.append("return ");
  35.319 +                }
  35.320 +                if (isStatic) {
  35.321 +                    source.append(((TypeElement)m.getEnclosingElement()).getQualifiedName());
  35.322 +                    source.append('.');
  35.323 +                } else {
  35.324 +                    source.append("self.");
  35.325 +                }
  35.326 +                source.append(m.getSimpleName());
  35.327 +                source.append("(");
  35.328 +                cnt = 0;
  35.329 +                sep = "";
  35.330 +                for (VariableElement ve : m.getParameters()) {
  35.331 +                    source.append(sep);
  35.332 +                    source.append("arg").append(++cnt);
  35.333 +                    sep = ", ";
  35.334 +                }
  35.335 +                source.append(");\n");
  35.336 +                if (m.getReturnType().getKind() == TypeKind.VOID) {
  35.337 +                    source.append("    return null;\n");
  35.338 +                }
  35.339 +                if (processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_7) >= 0) {
  35.340 +                    source.append("    }\n");
  35.341 +                } else {
  35.342 +                    
  35.343 +                    source.append("    } finally {\n");
  35.344 +                    source.append("      a.close();\n");
  35.345 +                    source.append("    }\n");
  35.346 +                }
  35.347 +                source.append("  }\n");
  35.348 +            }
  35.349 +            source.append("}\n");
  35.350 +            final String srcName = pkgName + ".$JsCallbacks$";
  35.351 +            try {
  35.352 +                Writer w = processingEnv.getFiler().createSourceFile(srcName,
  35.353 +                    map.values().toArray(new Element[map.size()])
  35.354 +                ).openWriter();
  35.355 +                w.write(source.toString());
  35.356 +                w.close();
  35.357 +            } catch (IOException ex) {
  35.358 +                processingEnv.getMessager().printMessage(
  35.359 +                    Diagnostic.Kind.ERROR, "Can't write " + srcName + ": " + ex.getMessage()
  35.360 +                );
  35.361 +            }
  35.362 +        }
  35.363 +    }
  35.364 +    
  35.365 +    private static String findPkg(Element e) {
  35.366 +        while (e.getKind() != ElementKind.PACKAGE) {
  35.367 +            e = e.getEnclosingElement();
  35.368 +        }
  35.369 +        return ((PackageElement)e).getQualifiedName().toString();
  35.370 +    }
  35.371 +    
  35.372 +}
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/JsAgent.java	Mon Dec 16 16:59:43 2013 +0100
    36.3 @@ -0,0 +1,67 @@
    36.4 +/**
    36.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    36.6 + *
    36.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    36.8 + *
    36.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   36.10 + * Other names may be trademarks of their respective owners.
   36.11 + *
   36.12 + * The contents of this file are subject to the terms of either the GNU
   36.13 + * General Public License Version 2 only ("GPL") or the Common
   36.14 + * Development and Distribution License("CDDL") (collectively, the
   36.15 + * "License"). You may not use this file except in compliance with the
   36.16 + * License. You can obtain a copy of the License at
   36.17 + * http://www.netbeans.org/cddl-gplv2.html
   36.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   36.19 + * specific language governing permissions and limitations under the
   36.20 + * License.  When distributing the software, include this License Header
   36.21 + * Notice in each file and include the License file at
   36.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   36.23 + * particular file as subject to the "Classpath" exception as provided
   36.24 + * by Oracle in the GPL Version 2 section of the License file that
   36.25 + * accompanied this code. If applicable, add the following below the
   36.26 + * License Header, with the fields enclosed by brackets [] replaced by
   36.27 + * your own identifying information:
   36.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   36.29 + *
   36.30 + * Contributor(s):
   36.31 + *
   36.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   36.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   36.34 + *
   36.35 + * If you wish your version of this file to be governed by only the CDDL
   36.36 + * or only the GPL Version 2, indicate your decision by adding
   36.37 + * "[Contributor] elects to include this software in this distribution
   36.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   36.39 + * single choice of license, a recipient has the option to distribute
   36.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   36.41 + * to extend the choice of license to its licensees as provided above.
   36.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   36.43 + * Version 2 license, then the option applies only if the new code is
   36.44 + * made subject to such option by the copyright holder.
   36.45 + */
   36.46 +package org.netbeans.html.boot.impl;
   36.47 +
   36.48 +import java.lang.instrument.ClassFileTransformer;
   36.49 +import java.lang.instrument.IllegalClassFormatException;
   36.50 +import java.lang.instrument.Instrumentation;
   36.51 +import java.security.ProtectionDomain;
   36.52 +
   36.53 +/**
   36.54 + *
   36.55 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   36.56 + */
   36.57 +public final class JsAgent implements ClassFileTransformer {
   36.58 +    public static void agentmain(String args, Instrumentation instr) {
   36.59 +        instr.addTransformer(new JsAgent());
   36.60 +    }
   36.61 +
   36.62 +    @Override
   36.63 +    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
   36.64 +        try {
   36.65 +            return FnUtils.transform(loader, classfileBuffer);
   36.66 +        } catch (Exception ex) {
   36.67 +            return classfileBuffer;
   36.68 +        }
   36.69 +    }
   36.70 +}
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/JsCallback.java	Mon Dec 16 16:59:43 2013 +0100
    37.3 @@ -0,0 +1,160 @@
    37.4 +/**
    37.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    37.6 + *
    37.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    37.8 + *
    37.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   37.10 + * Other names may be trademarks of their respective owners.
   37.11 + *
   37.12 + * The contents of this file are subject to the terms of either the GNU
   37.13 + * General Public License Version 2 only ("GPL") or the Common
   37.14 + * Development and Distribution License("CDDL") (collectively, the
   37.15 + * "License"). You may not use this file except in compliance with the
   37.16 + * License. You can obtain a copy of the License at
   37.17 + * http://www.netbeans.org/cddl-gplv2.html
   37.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   37.19 + * specific language governing permissions and limitations under the
   37.20 + * License.  When distributing the software, include this License Header
   37.21 + * Notice in each file and include the License file at
   37.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   37.23 + * particular file as subject to the "Classpath" exception as provided
   37.24 + * by Oracle in the GPL Version 2 section of the License file that
   37.25 + * accompanied this code. If applicable, add the following below the
   37.26 + * License Header, with the fields enclosed by brackets [] replaced by
   37.27 + * your own identifying information:
   37.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   37.29 + *
   37.30 + * Contributor(s):
   37.31 + *
   37.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   37.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   37.34 + *
   37.35 + * If you wish your version of this file to be governed by only the CDDL
   37.36 + * or only the GPL Version 2, indicate your decision by adding
   37.37 + * "[Contributor] elects to include this software in this distribution
   37.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   37.39 + * single choice of license, a recipient has the option to distribute
   37.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   37.41 + * to extend the choice of license to its licensees as provided above.
   37.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   37.43 + * Version 2 license, then the option applies only if the new code is
   37.44 + * made subject to such option by the copyright holder.
   37.45 + */
   37.46 +package org.netbeans.html.boot.impl;
   37.47 +
   37.48 +
   37.49 +/**
   37.50 + *
   37.51 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   37.52 + */
   37.53 +abstract class JsCallback {
   37.54 +    final String parse(String body) {
   37.55 +        StringBuilder sb = new StringBuilder();
   37.56 +        int pos = 0;
   37.57 +        for (;;) {
   37.58 +            int next = body.indexOf(".@", pos);
   37.59 +            if (next == -1) {
   37.60 +                sb.append(body.substring(pos));
   37.61 +                body = sb.toString();
   37.62 +                break;
   37.63 +            }
   37.64 +            int ident = next;
   37.65 +            while (ident > 0) {
   37.66 +                if (!Character.isJavaIdentifierPart(body.charAt(--ident))) {
   37.67 +                    ident++;
   37.68 +                    break;
   37.69 +                }
   37.70 +            }
   37.71 +            String refId = body.substring(ident, next);
   37.72 +            
   37.73 +            sb.append(body.substring(pos, ident));
   37.74 +            
   37.75 +            int sigBeg = body.indexOf('(', next);
   37.76 +            int sigEnd = body.indexOf(')', sigBeg);
   37.77 +            int colon4 = body.indexOf("::", next);
   37.78 +            if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) {
   37.79 +                throw new IllegalStateException(
   37.80 +                    "Wrong format of instance callback. "
   37.81 +                    + "Should be: 'inst.@pkg.Class::method(Ljava/lang/Object;)(param)':\n" 
   37.82 +                    + body
   37.83 +                );
   37.84 +            }
   37.85 +            String fqn = body.substring(next + 2, colon4);
   37.86 +            String method = body.substring(colon4 + 2, sigBeg);
   37.87 +            String params = body.substring(sigBeg, sigEnd + 1);
   37.88 +
   37.89 +            int paramBeg = body.indexOf('(', sigEnd + 1);
   37.90 +            if (paramBeg == -1) {
   37.91 +                throw new IllegalStateException(
   37.92 +                    "Wrong format of instance callback. "
   37.93 +                    + "Should be: 'inst.@pkg.Class::method(Ljava/lang/Object;)(param)':\n" 
   37.94 +                    + body
   37.95 +                );
   37.96 +            }
   37.97 +            
   37.98 +            sb.append(callMethod(refId, fqn, method, params));
   37.99 +            if (body.charAt(paramBeg + 1) != (')')) {
  37.100 +                sb.append(",");
  37.101 +            }
  37.102 +            pos = paramBeg + 1;
  37.103 +        }
  37.104 +        pos = 0;
  37.105 +        sb = null;
  37.106 +        for (;;) {
  37.107 +            int next = body.indexOf("@", pos);
  37.108 +            if (next == -1) {
  37.109 +                if (sb == null) {
  37.110 +                    return body;
  37.111 +                }
  37.112 +                sb.append(body.substring(pos));
  37.113 +                return sb.toString();
  37.114 +            }
  37.115 +            if (sb == null) {
  37.116 +                sb = new StringBuilder();
  37.117 +            }
  37.118 +            
  37.119 +            sb.append(body.substring(pos, next));
  37.120 +            
  37.121 +            int sigBeg = body.indexOf('(', next);
  37.122 +            int sigEnd = body.indexOf(')', sigBeg);
  37.123 +            int colon4 = body.indexOf("::", next);
  37.124 +            if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) {
  37.125 +                throw new IllegalStateException(
  37.126 +                    "Wrong format of static callback. "
  37.127 +                    + "Should be: '@pkg.Class::staticMethod(Ljava/lang/Object;)(param)':\n" 
  37.128 +                    + body
  37.129 +                );
  37.130 +            }
  37.131 +            String fqn = body.substring(next + 1, colon4);
  37.132 +            String method = body.substring(colon4 + 2, sigBeg);
  37.133 +            String params = body.substring(sigBeg, sigEnd + 1);
  37.134 +
  37.135 +            int paramBeg = body.indexOf('(', sigEnd + 1);
  37.136 +            
  37.137 +            sb.append(callMethod(null, fqn, method, params));
  37.138 +            pos = paramBeg + 1;
  37.139 +        }
  37.140 +    }
  37.141 +
  37.142 +    protected abstract CharSequence callMethod(
  37.143 +        String ident, String fqn, String method, String params
  37.144 +    );
  37.145 +
  37.146 +    static String mangle(String fqn, String method, String params) {
  37.147 +        if (params.startsWith("(")) {
  37.148 +            params = params.substring(1);
  37.149 +        }
  37.150 +        if (params.endsWith(")")) {
  37.151 +            params = params.substring(0, params.length() - 1);
  37.152 +        }
  37.153 +        return 
  37.154 +            replace(fqn) + "$" + replace(method) + "$" + replace(params);
  37.155 +    }
  37.156 +    
  37.157 +    private static String replace(String orig) {
  37.158 +        return orig.replace("_", "_1").
  37.159 +            replace(";", "_2").
  37.160 +            replace("[", "_3").
  37.161 +            replace('.', '_').replace('/', '_');
  37.162 +    }
  37.163 +}
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/JsClassLoader.java	Mon Dec 16 16:59:43 2013 +0100
    38.3 @@ -0,0 +1,133 @@
    38.4 +/**
    38.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    38.6 + *
    38.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    38.8 + *
    38.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   38.10 + * Other names may be trademarks of their respective owners.
   38.11 + *
   38.12 + * The contents of this file are subject to the terms of either the GNU
   38.13 + * General Public License Version 2 only ("GPL") or the Common
   38.14 + * Development and Distribution License("CDDL") (collectively, the
   38.15 + * "License"). You may not use this file except in compliance with the
   38.16 + * License. You can obtain a copy of the License at
   38.17 + * http://www.netbeans.org/cddl-gplv2.html
   38.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   38.19 + * specific language governing permissions and limitations under the
   38.20 + * License.  When distributing the software, include this License Header
   38.21 + * Notice in each file and include the License file at
   38.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   38.23 + * particular file as subject to the "Classpath" exception as provided
   38.24 + * by Oracle in the GPL Version 2 section of the License file that
   38.25 + * accompanied this code. If applicable, add the following below the
   38.26 + * License Header, with the fields enclosed by brackets [] replaced by
   38.27 + * your own identifying information:
   38.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   38.29 + *
   38.30 + * Contributor(s):
   38.31 + *
   38.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   38.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   38.34 + *
   38.35 + * If you wish your version of this file to be governed by only the CDDL
   38.36 + * or only the GPL Version 2, indicate your decision by adding
   38.37 + * "[Contributor] elects to include this software in this distribution
   38.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   38.39 + * single choice of license, a recipient has the option to distribute
   38.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   38.41 + * to extend the choice of license to its licensees as provided above.
   38.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   38.43 + * Version 2 license, then the option applies only if the new code is
   38.44 + * made subject to such option by the copyright holder.
   38.45 + */
   38.46 +package org.netbeans.html.boot.impl;
   38.47 +
   38.48 +import org.apidesign.html.boot.spi.Fn;
   38.49 +import java.io.IOException;
   38.50 +import java.io.InputStream;
   38.51 +import java.io.Reader;
   38.52 +import java.net.URL;
   38.53 +import java.util.Enumeration;
   38.54 +
   38.55 +/** 
   38.56 + *
   38.57 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   38.58 + */
   38.59 +abstract class JsClassLoader extends ClassLoader {
   38.60 +    JsClassLoader(ClassLoader parent) {
   38.61 +        super(parent);
   38.62 +        setDefaultAssertionStatus(JsClassLoader.class.desiredAssertionStatus());
   38.63 +    }
   38.64 +    
   38.65 +    @Override
   38.66 +    protected abstract URL findResource(String name);
   38.67 +    
   38.68 +    @Override
   38.69 +    protected abstract Enumeration<URL> findResources(String name);
   38.70 +
   38.71 +    @Override
   38.72 +    protected Class<?> findClass(String name) throws ClassNotFoundException {
   38.73 +        if (name.startsWith("javafx")) {
   38.74 +            return Class.forName(name);
   38.75 +        }
   38.76 +        if (name.startsWith("netscape")) {
   38.77 +            return Class.forName(name);
   38.78 +        }
   38.79 +        if (name.startsWith("com.sun")) {
   38.80 +            return Class.forName(name);
   38.81 +        }
   38.82 +        if (name.equals(JsClassLoader.class.getName())) {
   38.83 +            return JsClassLoader.class;
   38.84 +        }
   38.85 +        if (name.equals(Fn.class.getName())) {
   38.86 +            return Fn.class;
   38.87 +        }
   38.88 +        if (name.equals(Fn.Presenter.class.getName())) {
   38.89 +            return Fn.Presenter.class;
   38.90 +        }
   38.91 +        if (name.equals(FnUtils.class.getName())) {
   38.92 +            return FnUtils.class;
   38.93 +        }
   38.94 +        if (
   38.95 +            name.equals("org.apidesign.html.boot.spi.Fn") ||
   38.96 +            name.equals("org.netbeans.html.boot.impl.FnUtils") ||
   38.97 +            name.equals("org.netbeans.html.boot.impl.FnContext")
   38.98 +        ) {
   38.99 +            return Class.forName(name);
  38.100 +        }
  38.101 +        URL u = findResource(name.replace('.', '/') + ".class");
  38.102 +        if (u != null) {
  38.103 +            InputStream is = null;
  38.104 +            try {
  38.105 +                is = u.openStream();
  38.106 +                byte[] arr = new byte[is.available()];
  38.107 +                int len = 0;
  38.108 +                while (len < arr.length) {
  38.109 +                    int read = is.read(arr, len, arr.length - len);
  38.110 +                    if (read == -1) {
  38.111 +                        throw new IOException("Can't read " + u);
  38.112 +                    }
  38.113 +                    len += read;
  38.114 +                }
  38.115 +                is.close();
  38.116 +                is = null;
  38.117 +                arr = FnUtils.transform(JsClassLoader.this, arr);
  38.118 +                if (arr != null) {
  38.119 +                    return defineClass(name, arr, 0, arr.length);
  38.120 +                }
  38.121 +            } catch (IOException ex) {
  38.122 +                throw new ClassNotFoundException("Can't load " + name, ex);
  38.123 +            } finally {
  38.124 +                try {
  38.125 +                    if (is != null) is.close();
  38.126 +                } catch (IOException ex) {
  38.127 +                    throw new ClassNotFoundException(null, ex);
  38.128 +                }
  38.129 +            }
  38.130 +        }
  38.131 +        return super.findClass(name);
  38.132 +    }
  38.133 +    
  38.134 +    protected abstract Fn defineFn(String code, String... names);
  38.135 +    protected abstract void loadScript(Reader code) throws Exception;
  38.136 +}
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/Test.java	Mon Dec 16 16:59:43 2013 +0100
    39.3 @@ -0,0 +1,57 @@
    39.4 +/**
    39.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    39.6 + *
    39.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    39.8 + *
    39.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   39.10 + * Other names may be trademarks of their respective owners.
   39.11 + *
   39.12 + * The contents of this file are subject to the terms of either the GNU
   39.13 + * General Public License Version 2 only ("GPL") or the Common
   39.14 + * Development and Distribution License("CDDL") (collectively, the
   39.15 + * "License"). You may not use this file except in compliance with the
   39.16 + * License. You can obtain a copy of the License at
   39.17 + * http://www.netbeans.org/cddl-gplv2.html
   39.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   39.19 + * specific language governing permissions and limitations under the
   39.20 + * License.  When distributing the software, include this License Header
   39.21 + * Notice in each file and include the License file at
   39.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   39.23 + * particular file as subject to the "Classpath" exception as provided
   39.24 + * by Oracle in the GPL Version 2 section of the License file that
   39.25 + * accompanied this code. If applicable, add the following below the
   39.26 + * License Header, with the fields enclosed by brackets [] replaced by
   39.27 + * your own identifying information:
   39.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   39.29 + *
   39.30 + * Contributor(s):
   39.31 + *
   39.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   39.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   39.34 + *
   39.35 + * If you wish your version of this file to be governed by only the CDDL
   39.36 + * or only the GPL Version 2, indicate your decision by adding
   39.37 + * "[Contributor] elects to include this software in this distribution
   39.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   39.39 + * single choice of license, a recipient has the option to distribute
   39.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   39.41 + * to extend the choice of license to its licensees as provided above.
   39.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   39.43 + * Version 2 license, then the option applies only if the new code is
   39.44 + * made subject to such option by the copyright holder.
   39.45 + */
   39.46 +package org.netbeans.html.boot.impl;
   39.47 +
   39.48 +import java.util.concurrent.Callable;
   39.49 +import net.java.html.js.JavaScriptBody;
   39.50 +
   39.51 +/**
   39.52 + *
   39.53 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   39.54 + */
   39.55 +public final class Test implements Callable<Boolean> {
   39.56 +    @Override @JavaScriptBody(args = {}, body = "return true;")
   39.57 +    public Boolean call() {
   39.58 +        return false;
   39.59 +    }
   39.60 +}
    40.1 --- a/boot/src/test/java/org/apidesign/html/boot/impl/Arithm.java	Mon Dec 16 15:48:09 2013 +0100
    40.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.3 @@ -1,53 +0,0 @@
    40.4 -/**
    40.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    40.6 - *
    40.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    40.8 - *
    40.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   40.10 - * Other names may be trademarks of their respective owners.
   40.11 - *
   40.12 - * The contents of this file are subject to the terms of either the GNU
   40.13 - * General Public License Version 2 only ("GPL") or the Common
   40.14 - * Development and Distribution License("CDDL") (collectively, the
   40.15 - * "License"). You may not use this file except in compliance with the
   40.16 - * License. You can obtain a copy of the License at
   40.17 - * http://www.netbeans.org/cddl-gplv2.html
   40.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   40.19 - * specific language governing permissions and limitations under the
   40.20 - * License.  When distributing the software, include this License Header
   40.21 - * Notice in each file and include the License file at
   40.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   40.23 - * particular file as subject to the "Classpath" exception as provided
   40.24 - * by Oracle in the GPL Version 2 section of the License file that
   40.25 - * accompanied this code. If applicable, add the following below the
   40.26 - * License Header, with the fields enclosed by brackets [] replaced by
   40.27 - * your own identifying information:
   40.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   40.29 - *
   40.30 - * Contributor(s):
   40.31 - *
   40.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   40.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   40.34 - *
   40.35 - * If you wish your version of this file to be governed by only the CDDL
   40.36 - * or only the GPL Version 2, indicate your decision by adding
   40.37 - * "[Contributor] elects to include this software in this distribution
   40.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   40.39 - * single choice of license, a recipient has the option to distribute
   40.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   40.41 - * to extend the choice of license to its licensees as provided above.
   40.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   40.43 - * Version 2 license, then the option applies only if the new code is
   40.44 - * made subject to such option by the copyright holder.
   40.45 - */
   40.46 -package org.apidesign.html.boot.impl;
   40.47 -
   40.48 -/**
   40.49 - *
   40.50 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   40.51 - */
   40.52 -public class Arithm {
   40.53 -    public int sumTwo(int a, int b) {
   40.54 -        return a + b;
   40.55 -    }
   40.56 -}
    41.1 --- a/boot/src/test/java/org/apidesign/html/boot/impl/Compile.java	Mon Dec 16 15:48:09 2013 +0100
    41.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.3 @@ -1,291 +0,0 @@
    41.4 -/**
    41.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    41.6 - *
    41.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    41.8 - *
    41.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   41.10 - * Other names may be trademarks of their respective owners.
   41.11 - *
   41.12 - * The contents of this file are subject to the terms of either the GNU
   41.13 - * General Public License Version 2 only ("GPL") or the Common
   41.14 - * Development and Distribution License("CDDL") (collectively, the
   41.15 - * "License"). You may not use this file except in compliance with the
   41.16 - * License. You can obtain a copy of the License at
   41.17 - * http://www.netbeans.org/cddl-gplv2.html
   41.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   41.19 - * specific language governing permissions and limitations under the
   41.20 - * License.  When distributing the software, include this License Header
   41.21 - * Notice in each file and include the License file at
   41.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   41.23 - * particular file as subject to the "Classpath" exception as provided
   41.24 - * by Oracle in the GPL Version 2 section of the License file that
   41.25 - * accompanied this code. If applicable, add the following below the
   41.26 - * License Header, with the fields enclosed by brackets [] replaced by
   41.27 - * your own identifying information:
   41.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   41.29 - *
   41.30 - * Contributor(s):
   41.31 - *
   41.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   41.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   41.34 - *
   41.35 - * If you wish your version of this file to be governed by only the CDDL
   41.36 - * or only the GPL Version 2, indicate your decision by adding
   41.37 - * "[Contributor] elects to include this software in this distribution
   41.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   41.39 - * single choice of license, a recipient has the option to distribute
   41.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   41.41 - * to extend the choice of license to its licensees as provided above.
   41.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   41.43 - * Version 2 license, then the option applies only if the new code is
   41.44 - * made subject to such option by the copyright holder.
   41.45 - */
   41.46 -package org.apidesign.html.boot.impl;
   41.47 -
   41.48 -import java.io.ByteArrayInputStream;
   41.49 -import java.io.ByteArrayOutputStream;
   41.50 -import java.io.IOException;
   41.51 -import java.io.InputStream;
   41.52 -import java.io.OutputStream;
   41.53 -import java.net.URI;
   41.54 -import java.net.URISyntaxException;
   41.55 -import java.util.ArrayList;
   41.56 -import java.util.Arrays;
   41.57 -import java.util.HashMap;
   41.58 -import java.util.List;
   41.59 -import java.util.Locale;
   41.60 -import java.util.Map;
   41.61 -import java.util.regex.Matcher;
   41.62 -import java.util.regex.Pattern;
   41.63 -import javax.tools.Diagnostic;
   41.64 -import javax.tools.DiagnosticListener;
   41.65 -import javax.tools.FileObject;
   41.66 -import javax.tools.ForwardingJavaFileManager;
   41.67 -import javax.tools.JavaFileManager;
   41.68 -import javax.tools.JavaFileObject;
   41.69 -import javax.tools.JavaFileObject.Kind;
   41.70 -import javax.tools.SimpleJavaFileObject;
   41.71 -import javax.tools.StandardJavaFileManager;
   41.72 -import javax.tools.StandardLocation;
   41.73 -import javax.tools.ToolProvider;
   41.74 -import static org.testng.Assert.assertTrue;
   41.75 -import static org.testng.Assert.assertFalse;
   41.76 -import static org.testng.Assert.fail;
   41.77 -
   41.78 -/**
   41.79 - *
   41.80 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   41.81 - */
   41.82 -final class Compile implements DiagnosticListener<JavaFileObject> {
   41.83 -    private final List<Diagnostic<? extends JavaFileObject>> errors = 
   41.84 -            new ArrayList<Diagnostic<? extends JavaFileObject>>();
   41.85 -    private final Map<String, byte[]> classes;
   41.86 -    private final String pkg;
   41.87 -    private final String cls;
   41.88 -    private final String html;
   41.89 -    private final String sourceLevel;
   41.90 -
   41.91 -    private Compile(String html, String code, String sl) throws IOException {
   41.92 -        this.pkg = findPkg(code);
   41.93 -        this.cls = findCls(code);
   41.94 -        this.html = html;
   41.95 -        this.sourceLevel = sl;
   41.96 -        classes = compile(html, code);
   41.97 -    }
   41.98 -
   41.99 -    /** Performs compilation of given HTML page and associated Java code
  41.100 -     */
  41.101 -    public static Compile create(String html, String code) throws IOException {
  41.102 -        return create(html, code, "1.7");
  41.103 -    }
  41.104 -    static Compile create(String html, String code, String sourceLevel) throws IOException {
  41.105 -        return new Compile(html, code, sourceLevel);
  41.106 -    }
  41.107 -    
  41.108 -    /** Checks for given class among compiled resources */
  41.109 -    public byte[] get(String res) {
  41.110 -        return classes.get(res);
  41.111 -    }
  41.112 -    
  41.113 -    /** Obtains errors created during compilation.
  41.114 -     */
  41.115 -    public List<Diagnostic<? extends JavaFileObject>> getErrors() {
  41.116 -        List<Diagnostic<? extends JavaFileObject>> err;
  41.117 -        err = new ArrayList<Diagnostic<? extends JavaFileObject>>();
  41.118 -        for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
  41.119 -            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
  41.120 -                err.add(diagnostic);
  41.121 -            }
  41.122 -        }
  41.123 -        return err;
  41.124 -    }
  41.125 -    
  41.126 -    private Map<String, byte[]> compile(final String html, final String code) throws IOException {
  41.127 -        StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
  41.128 -
  41.129 -        final Map<String, ByteArrayOutputStream> class2BAOS;
  41.130 -        class2BAOS = new HashMap<String, ByteArrayOutputStream>();
  41.131 -
  41.132 -        JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
  41.133 -            @Override
  41.134 -            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
  41.135 -                return code;
  41.136 -            }
  41.137 -        };
  41.138 -        final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
  41.139 -            @Override
  41.140 -            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
  41.141 -                return html;
  41.142 -            }
  41.143 -
  41.144 -            @Override
  41.145 -            public InputStream openInputStream() throws IOException {
  41.146 -                return new ByteArrayInputStream(html.getBytes());
  41.147 -            }
  41.148 -        };
  41.149 -        
  41.150 -        final URI scratch;
  41.151 -        try {
  41.152 -            scratch = new URI("mem://mem3");
  41.153 -        } catch (URISyntaxException ex) {
  41.154 -            throw new IOException(ex);
  41.155 -        }
  41.156 -        
  41.157 -        JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
  41.158 -            @Override
  41.159 -            public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
  41.160 -                if (kind  == Kind.CLASS) {
  41.161 -                    final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
  41.162 -
  41.163 -                    class2BAOS.put(className.replace('.', '/') + ".class", buffer);
  41.164 -                    return new SimpleJavaFileObject(sibling.toUri(), kind) {
  41.165 -                        @Override
  41.166 -                        public OutputStream openOutputStream() throws IOException {
  41.167 -                            return buffer;
  41.168 -                        }
  41.169 -                    };
  41.170 -                }
  41.171 -                
  41.172 -                if (kind == Kind.SOURCE) {
  41.173 -                    final String n = className.replace('.', '/') + ".java";
  41.174 -                    final URI un;
  41.175 -                    try {
  41.176 -                        un = new URI("mem://" + n);
  41.177 -                    } catch (URISyntaxException ex) {
  41.178 -                        throw new IOException(ex);
  41.179 -                    }
  41.180 -                    return new VirtFO(un/*sibling.toUri()*/, kind, n);
  41.181 -                }
  41.182 -                
  41.183 -                throw new IllegalStateException();
  41.184 -            }
  41.185 -
  41.186 -            @Override
  41.187 -            public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
  41.188 -                if (location == StandardLocation.SOURCE_PATH) {
  41.189 -                    if (packageName.equals(pkg)) {
  41.190 -                        return htmlFile;
  41.191 -                    }
  41.192 -                }
  41.193 -                
  41.194 -                return null;
  41.195 -            }
  41.196 -
  41.197 -            @Override
  41.198 -            public boolean isSameFile(FileObject a, FileObject b) {
  41.199 -                if (a instanceof VirtFO && b instanceof VirtFO) {
  41.200 -                    return ((VirtFO)a).getName().equals(((VirtFO)b).getName());
  41.201 -                }
  41.202 -                
  41.203 -                return super.isSameFile(a, b);
  41.204 -            }
  41.205 -
  41.206 -            class VirtFO extends SimpleJavaFileObject {
  41.207 -
  41.208 -                private final String n;
  41.209 -
  41.210 -                public VirtFO(URI uri, Kind kind, String n) {
  41.211 -                    super(uri, kind);
  41.212 -                    this.n = n;
  41.213 -                }
  41.214 -                private final ByteArrayOutputStream data = new ByteArrayOutputStream();
  41.215 -
  41.216 -                @Override
  41.217 -                public OutputStream openOutputStream() throws IOException {
  41.218 -                    return data;
  41.219 -                }
  41.220 -
  41.221 -                @Override
  41.222 -                public String getName() {
  41.223 -                    return n;
  41.224 -                }
  41.225 -
  41.226 -                @Override
  41.227 -                public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
  41.228 -                    data.close();
  41.229 -                    return new String(data.toByteArray());
  41.230 -                }
  41.231 -            }
  41.232 -        };
  41.233 -
  41.234 -        ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", sourceLevel, "-target", "1.7"), null, Arrays.asList(file)).call();
  41.235 -
  41.236 -        Map<String, byte[]> result = new HashMap<String, byte[]>();
  41.237 -
  41.238 -        for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
  41.239 -            result.put(e.getKey(), e.getValue().toByteArray());
  41.240 -        }
  41.241 -
  41.242 -        return result;
  41.243 -    }
  41.244 -
  41.245 -
  41.246 -    @Override
  41.247 -    public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
  41.248 -        errors.add(diagnostic);
  41.249 -    }
  41.250 -    private static String findPkg(String java) throws IOException {
  41.251 -        Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
  41.252 -        Matcher m = p.matcher(java);
  41.253 -        if (!m.find()) {
  41.254 -            throw new IOException("Can't find package declaration in the java file");
  41.255 -        }
  41.256 -        String pkg = m.group(1);
  41.257 -        return pkg;
  41.258 -    }
  41.259 -    private static String findCls(String java) throws IOException {
  41.260 -        Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
  41.261 -        Matcher m = p.matcher(java);
  41.262 -        if (!m.find()) {
  41.263 -            throw new IOException("Can't find package declaration in the java file");
  41.264 -        }
  41.265 -        String cls = m.group(1);
  41.266 -        return cls;
  41.267 -    }
  41.268 -
  41.269 -    String getHtml() {
  41.270 -        String fqn = "'" + pkg + '.' + cls + "'";
  41.271 -        return html.replace("'${fqn}'", fqn);
  41.272 -    }
  41.273 -    void assertErrors() {
  41.274 -        assertFalse(getErrors().isEmpty(), "There are supposed to be some errors");
  41.275 -    }
  41.276 -
  41.277 -    void assertError(String expMsg) {
  41.278 -        StringBuilder sb = new StringBuilder();
  41.279 -        sb.append("Can't find ").append(expMsg).append(" among:");
  41.280 -        for (Diagnostic<? extends JavaFileObject> e : errors) {
  41.281 -            String msg = e.getMessage(Locale.US);
  41.282 -            if (msg.contains(expMsg)) {
  41.283 -                return;
  41.284 -            }
  41.285 -            sb.append("\n");
  41.286 -            sb.append(msg);
  41.287 -        }
  41.288 -        fail(sb.toString());
  41.289 -    }
  41.290 -
  41.291 -    void assertNoErrors() {
  41.292 -        assertTrue(getErrors().isEmpty(), "No errors expected: " + getErrors());
  41.293 -    }
  41.294 -}
    42.1 --- a/boot/src/test/java/org/apidesign/html/boot/impl/FnTest.java	Mon Dec 16 15:48:09 2013 +0100
    42.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.3 @@ -1,148 +0,0 @@
    42.4 -/**
    42.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    42.6 - *
    42.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    42.8 - *
    42.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   42.10 - * Other names may be trademarks of their respective owners.
   42.11 - *
   42.12 - * The contents of this file are subject to the terms of either the GNU
   42.13 - * General Public License Version 2 only ("GPL") or the Common
   42.14 - * Development and Distribution License("CDDL") (collectively, the
   42.15 - * "License"). You may not use this file except in compliance with the
   42.16 - * License. You can obtain a copy of the License at
   42.17 - * http://www.netbeans.org/cddl-gplv2.html
   42.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   42.19 - * specific language governing permissions and limitations under the
   42.20 - * License.  When distributing the software, include this License Header
   42.21 - * Notice in each file and include the License file at
   42.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   42.23 - * particular file as subject to the "Classpath" exception as provided
   42.24 - * by Oracle in the GPL Version 2 section of the License file that
   42.25 - * accompanied this code. If applicable, add the following below the
   42.26 - * License Header, with the fields enclosed by brackets [] replaced by
   42.27 - * your own identifying information:
   42.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   42.29 - *
   42.30 - * Contributor(s):
   42.31 - *
   42.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   42.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   42.34 - *
   42.35 - * If you wish your version of this file to be governed by only the CDDL
   42.36 - * or only the GPL Version 2, indicate your decision by adding
   42.37 - * "[Contributor] elects to include this software in this distribution
   42.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   42.39 - * single choice of license, a recipient has the option to distribute
   42.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   42.41 - * to extend the choice of license to its licensees as provided above.
   42.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   42.43 - * Version 2 license, then the option applies only if the new code is
   42.44 - * made subject to such option by the copyright holder.
   42.45 - */
   42.46 -package org.apidesign.html.boot.impl;
   42.47 -
   42.48 -import java.io.Closeable;
   42.49 -import java.io.Reader;
   42.50 -import java.net.URL;
   42.51 -import java.net.URLClassLoader;
   42.52 -import java.util.ArrayList;
   42.53 -import java.util.Arrays;
   42.54 -import java.util.Collection;
   42.55 -import java.util.List;
   42.56 -import javax.script.Invocable;
   42.57 -import javax.script.ScriptEngine;
   42.58 -import javax.script.ScriptEngineManager;
   42.59 -import javax.script.ScriptException;
   42.60 -import org.apidesign.html.boot.spi.Fn;
   42.61 -import org.testng.annotations.BeforeClass;
   42.62 -import org.testng.annotations.BeforeMethod;
   42.63 -
   42.64 -/**
   42.65 - *
   42.66 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   42.67 - */
   42.68 -public class FnTest extends JsClassLoaderBase {
   42.69 -    private static Fn.Presenter presenter;
   42.70 -    
   42.71 -    public FnTest() {
   42.72 -    }
   42.73 -
   42.74 -    @BeforeClass
   42.75 -    public static void createClassLoader() throws Exception {
   42.76 -        ScriptEngineManager sem = new ScriptEngineManager();
   42.77 -        final ScriptEngine eng = sem.getEngineByMimeType("text/javascript");
   42.78 -        
   42.79 -        final URL my = FnTest.class.getProtectionDomain().getCodeSource().getLocation();
   42.80 -        ClassLoader parent = JsClassLoaderTest.class.getClassLoader().getParent();
   42.81 -        final URLClassLoader ul = new URLClassLoader(new URL[] { my }, parent);
   42.82 -        
   42.83 -        class Impl implements FindResources, Fn.Presenter {
   42.84 -            @Override
   42.85 -            public void findResources(String path, Collection<? super URL> results, boolean oneIsEnough) {
   42.86 -                URL u = ul.findResource(path);
   42.87 -                if (u != null) {
   42.88 -                    results.add(u);
   42.89 -                }
   42.90 -            }
   42.91 -
   42.92 -            @Override
   42.93 -            public Fn defineFn(String code, String... names) {
   42.94 -                StringBuilder sb = new StringBuilder();
   42.95 -                sb.append("(function() {");
   42.96 -                sb.append("return function(");
   42.97 -                String sep = "";
   42.98 -                for (String n : names) {
   42.99 -                    sb.append(sep);
  42.100 -                    sb.append(n);
  42.101 -                    sep = ", ";
  42.102 -                }
  42.103 -                sb.append(") {");
  42.104 -                sb.append(code);
  42.105 -                sb.append("};");
  42.106 -                sb.append("})()");
  42.107 -                try {
  42.108 -                    final Object val = eng.eval(sb.toString());
  42.109 -                    return new Fn(this) {
  42.110 -                        @Override
  42.111 -                        public Object invoke(Object thiz, Object... args) throws Exception {
  42.112 -                            List<Object> all = new ArrayList<Object>(args.length + 1);
  42.113 -                            all.add(thiz == null ? val : thiz);
  42.114 -                            all.addAll(Arrays.asList(args));
  42.115 -                            Invocable inv = (Invocable)eng;
  42.116 -                            try {
  42.117 -                                Object ret = inv.invokeMethod(val, "call", all.toArray());
  42.118 -                                return val.equals(ret) ? null : ret;
  42.119 -                            } catch (ScriptException ex) {
  42.120 -                                throw ex;
  42.121 -                            }
  42.122 -                        }
  42.123 -                    };
  42.124 -                } catch (ScriptException ex) {
  42.125 -                    throw new LinkageError("Can't parse: " + sb, ex);
  42.126 -                }
  42.127 -            }
  42.128 -
  42.129 -            @Override
  42.130 -            public void displayPage(URL resource, Runnable r) {
  42.131 -                throw new UnsupportedOperationException();
  42.132 -            }
  42.133 -
  42.134 -            @Override
  42.135 -            public void loadScript(Reader code) throws Exception {
  42.136 -                eng.eval(code);
  42.137 -            }
  42.138 -        }
  42.139 -        Impl impl = new Impl();
  42.140 -        ClassLoader loader = FnUtils.newLoader(impl, impl, parent);
  42.141 -        presenter = impl;
  42.142 -        
  42.143 -        Closeable close = FnContext.activate(impl);
  42.144 -        methodClass = loader.loadClass(JsMethods.class.getName());
  42.145 -        close.close();
  42.146 -    }
  42.147 -
  42.148 -    @BeforeMethod public void initPresenter() {
  42.149 -        FnContext.currentPresenter(presenter);
  42.150 -    }
  42.151 -}
    43.1 --- a/boot/src/test/java/org/apidesign/html/boot/impl/JavaScriptProcesorTest.java	Mon Dec 16 15:48:09 2013 +0100
    43.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.3 @@ -1,129 +0,0 @@
    43.4 -/**
    43.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    43.6 - *
    43.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    43.8 - *
    43.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   43.10 - * Other names may be trademarks of their respective owners.
   43.11 - *
   43.12 - * The contents of this file are subject to the terms of either the GNU
   43.13 - * General Public License Version 2 only ("GPL") or the Common
   43.14 - * Development and Distribution License("CDDL") (collectively, the
   43.15 - * "License"). You may not use this file except in compliance with the
   43.16 - * License. You can obtain a copy of the License at
   43.17 - * http://www.netbeans.org/cddl-gplv2.html
   43.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   43.19 - * specific language governing permissions and limitations under the
   43.20 - * License.  When distributing the software, include this License Header
   43.21 - * Notice in each file and include the License file at
   43.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   43.23 - * particular file as subject to the "Classpath" exception as provided
   43.24 - * by Oracle in the GPL Version 2 section of the License file that
   43.25 - * accompanied this code. If applicable, add the following below the
   43.26 - * License Header, with the fields enclosed by brackets [] replaced by
   43.27 - * your own identifying information:
   43.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   43.29 - *
   43.30 - * Contributor(s):
   43.31 - *
   43.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   43.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   43.34 - *
   43.35 - * If you wish your version of this file to be governed by only the CDDL
   43.36 - * or only the GPL Version 2, indicate your decision by adding
   43.37 - * "[Contributor] elects to include this software in this distribution
   43.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   43.39 - * single choice of license, a recipient has the option to distribute
   43.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   43.41 - * to extend the choice of license to its licensees as provided above.
   43.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   43.43 - * Version 2 license, then the option applies only if the new code is
   43.44 - * made subject to such option by the copyright holder.
   43.45 - */
   43.46 -package org.apidesign.html.boot.impl;
   43.47 -
   43.48 -import java.io.IOException;
   43.49 -import java.lang.reflect.Field;
   43.50 -import java.lang.reflect.Method;
   43.51 -import static org.testng.Assert.assertEquals;
   43.52 -import static org.testng.Assert.assertTrue;
   43.53 -import org.testng.annotations.Test;
   43.54 -
   43.55 -/**
   43.56 - *
   43.57 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   43.58 - */
   43.59 -public class JavaScriptProcesorTest {
   43.60 -    
   43.61 -    @Test public void detectCallbackToNonExistingClass() throws IOException {
   43.62 -        String code = "package x.y.z;\n"
   43.63 -            + "import net.java.html.js.JavaScriptBody;\n"
   43.64 -            + "class X {\n"
   43.65 -            + "  @JavaScriptBody(args={\"r\"}, javacall=true, body =\n"
   43.66 -            + "    \"r.@java.lang.Runable::run()();\"\n" // typo
   43.67 -            + "  )\n"
   43.68 -            + "  private static native void callback(Runnable r);\n"
   43.69 -            + "}\n";
   43.70 -        
   43.71 -        Compile c = Compile.create("", code);
   43.72 -        c.assertErrors();
   43.73 -        c.assertError("java.lang.Runable"); // typo
   43.74 -    }
   43.75 -
   43.76 -    @Test public void detectCallbackToNonExistingMethod() throws IOException {
   43.77 -        String code = "package x.y.z;\n"
   43.78 -            + "import net.java.html.js.JavaScriptBody;\n"
   43.79 -            + "class X {\n"
   43.80 -            + "  @JavaScriptBody(args={\"r\"}, javacall=true, body =\n"
   43.81 -            + "    \"r.@java.lang.Runnable::cancel()();\"\n"
   43.82 -            + "  )\n"
   43.83 -            + "  private static native void callback(Runnable r);\n"
   43.84 -            + "}\n";
   43.85 -        
   43.86 -        Compile c = Compile.create("", code);
   43.87 -        c.assertErrors();
   43.88 -        c.assertError("method cancel");
   43.89 -    }
   43.90 -
   43.91 -    @Test public void detectCallbackToNonExistingParams() throws IOException {
   43.92 -        String code = "package x.y.z;\n"
   43.93 -            + "import net.java.html.js.JavaScriptBody;\n"
   43.94 -            + "class X {\n"
   43.95 -            + "  @JavaScriptBody(args={\"r\"}, javacall=true, body =\n"
   43.96 -            + "    \"r.@java.lang.Runnable::run(I)(10);\"\n"
   43.97 -            + "  )\n"
   43.98 -            + "  private static native void callback(Runnable r);\n"
   43.99 -            + "}\n";
  43.100 -        
  43.101 -        Compile c = Compile.create("", code);
  43.102 -        c.assertErrors();
  43.103 -        c.assertError("wrong parameters: (I)");
  43.104 -    }
  43.105 -
  43.106 -    @Test public void objectTypeParamsAreOK() throws IOException {
  43.107 -        String code = "package x.y.z;\n"
  43.108 -            + "import net.java.html.js.JavaScriptBody;\n"
  43.109 -            + "class X {\n"
  43.110 -            + "  @JavaScriptBody(args={\"r\"}, javacall=true, body =\n"
  43.111 -            + "    \"r.@java.lang.Object::equals(Ljava/lang/Object;)(null);\"\n"
  43.112 -            + "  )\n"
  43.113 -            + "  private static native void testEqual(Object r);\n"
  43.114 -            + "}\n";
  43.115 -        
  43.116 -        Compile c = Compile.create("", code);
  43.117 -        c.assertNoErrors();
  43.118 -    }
  43.119 -    
  43.120 -    @Test public void generatesCallbacksThatReturnObject() throws Exception {
  43.121 -        Class<?> callbacksForTestPkg = Class.forName("org.apidesign.html.boot.impl.$JsCallbacks$");
  43.122 -        Method m = callbacksForTestPkg.getDeclaredMethod("java_lang_Runnable$run$", Runnable.class);
  43.123 -        assertEquals(m.getReturnType(), Object.class, "All methods always return object");
  43.124 -    }
  43.125 -    
  43.126 -    @Test public void hasInstanceField() throws Exception {
  43.127 -        Class<?> callbacksForTestPkg = Class.forName("org.apidesign.html.boot.impl.$JsCallbacks$");
  43.128 -        Field f = callbacksForTestPkg.getDeclaredField("VM");
  43.129 -        f.setAccessible(true);
  43.130 -        assertTrue(callbacksForTestPkg.isInstance(f.get(null)), "Singleton field VM");
  43.131 -    }
  43.132 -}
    44.1 --- a/boot/src/test/java/org/apidesign/html/boot/impl/JsClassLoaderBase.java	Mon Dec 16 15:48:09 2013 +0100
    44.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.3 @@ -1,201 +0,0 @@
    44.4 -/**
    44.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    44.6 - *
    44.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    44.8 - *
    44.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   44.10 - * Other names may be trademarks of their respective owners.
   44.11 - *
   44.12 - * The contents of this file are subject to the terms of either the GNU
   44.13 - * General Public License Version 2 only ("GPL") or the Common
   44.14 - * Development and Distribution License("CDDL") (collectively, the
   44.15 - * "License"). You may not use this file except in compliance with the
   44.16 - * License. You can obtain a copy of the License at
   44.17 - * http://www.netbeans.org/cddl-gplv2.html
   44.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   44.19 - * specific language governing permissions and limitations under the
   44.20 - * License.  When distributing the software, include this License Header
   44.21 - * Notice in each file and include the License file at
   44.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   44.23 - * particular file as subject to the "Classpath" exception as provided
   44.24 - * by Oracle in the GPL Version 2 section of the License file that
   44.25 - * accompanied this code. If applicable, add the following below the
   44.26 - * License Header, with the fields enclosed by brackets [] replaced by
   44.27 - * your own identifying information:
   44.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   44.29 - *
   44.30 - * Contributor(s):
   44.31 - *
   44.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   44.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   44.34 - *
   44.35 - * If you wish your version of this file to be governed by only the CDDL
   44.36 - * or only the GPL Version 2, indicate your decision by adding
   44.37 - * "[Contributor] elects to include this software in this distribution
   44.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   44.39 - * single choice of license, a recipient has the option to distribute
   44.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   44.41 - * to extend the choice of license to its licensees as provided above.
   44.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   44.43 - * Version 2 license, then the option applies only if the new code is
   44.44 - * made subject to such option by the copyright holder.
   44.45 - */
   44.46 -package org.apidesign.html.boot.impl;
   44.47 -
   44.48 -import java.lang.reflect.InvocationTargetException;
   44.49 -import java.lang.reflect.Method;
   44.50 -import java.lang.reflect.Modifier;
   44.51 -import static org.testng.Assert.*;
   44.52 -import org.testng.annotations.BeforeMethod;
   44.53 -import org.testng.annotations.Test;
   44.54 -
   44.55 -/**
   44.56 - *
   44.57 - * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   44.58 - */
   44.59 -public class JsClassLoaderBase {
   44.60 -    protected static Class<?> methodClass;
   44.61 -    
   44.62 -    public JsClassLoaderBase() {
   44.63 -    }
   44.64 -    
   44.65 -    @BeforeMethod
   44.66 -    public void assertClassDefined() {
   44.67 -        assertNotNull(methodClass, "BeforeClass set up code should provide methodClass");
   44.68 -    }
   44.69 -
   44.70 -    @Test public void noParamMethod() throws Throwable {
   44.71 -        Method plus = methodClass.getMethod("fortyTwo");
   44.72 -        try {
   44.73 -            final Object val = plus.invoke(null);
   44.74 -            assertTrue(val instanceof Number, "A number returned " + val);
   44.75 -            assertEquals(((Number)val).intValue(), 42);
   44.76 -        } catch (InvocationTargetException ex) {
   44.77 -            throw ex.getTargetException();
   44.78 -        }
   44.79 -    }
   44.80 -    
   44.81 -    @Test public void testExecuteScript() throws Throwable {
   44.82 -        Method plus = methodClass.getMethod("plus", int.class, int.class);
   44.83 -        try {
   44.84 -            assertEquals(plus.invoke(null, 10, 20), 30);
   44.85 -        } catch (InvocationTargetException ex) {
   44.86 -            throw ex.getTargetException();
   44.87 -        }
   44.88 -    }
   44.89 -
   44.90 -    @Test public void overloadedMethod() throws Throwable {
   44.91 -        Method plus = methodClass.getMethod("plus", int.class);
   44.92 -        try {
   44.93 -            assertEquals(plus.invoke(null, 10), 10);
   44.94 -        } catch (InvocationTargetException ex) {
   44.95 -            throw ex.getTargetException();
   44.96 -        }
   44.97 -    }
   44.98 -    
   44.99 -    @Test public void instanceMethod() throws Throwable {
  44.100 -        Method plus = methodClass.getMethod("plusInst", int.class);
  44.101 -        Object inst = methodClass.newInstance();
  44.102 -        try {
  44.103 -            assertEquals(plus.invoke(inst, 10), 10);
  44.104 -        } catch (InvocationTargetException ex) {
  44.105 -            throw ex.getTargetException();
  44.106 -        }
  44.107 -    }
  44.108 -    
  44.109 -    @Test public void staticThis() throws Throwable {
  44.110 -        Method st = methodClass.getMethod("staticThis");
  44.111 -        try {
  44.112 -            assertNull(st.invoke(null));
  44.113 -        } catch (InvocationTargetException ex) {
  44.114 -            throw ex.getTargetException();
  44.115 -        }
  44.116 -    }
  44.117 -
  44.118 -    @Test public void getThis() throws Throwable {
  44.119 -        Object th = methodClass.newInstance();
  44.120 -        Method st = methodClass.getMethod("getThis");
  44.121 -        try {
  44.122 -            assertEquals(st.invoke(th), th);
  44.123 -        } catch (InvocationTargetException ex) {
  44.124 -            throw ex.getTargetException();
  44.125 -        }
  44.126 -    }
  44.127 -    
  44.128 -    @Test public void truth() throws Throwable {
  44.129 -        Method st = methodClass.getMethod("truth");
  44.130 -        assertTrue((st.getModifiers() & Modifier.STATIC) != 0, "Is static");
  44.131 -        assertEquals(st.invoke(null), Boolean.TRUE, "Can return boolean");
  44.132 -    }
  44.133 -    
  44.134 -    @Test public void callback() throws Throwable {
  44.135 -        class R implements Runnable {
  44.136 -            int cnt;
  44.137 -            
  44.138 -            @Override
  44.139 -            public void run() {
  44.140 -                cnt++;
  44.141 -            }
  44.142 -        }
  44.143 -        R r = new R();
  44.144 -        
  44.145 -        Method inc = methodClass.getMethod("callback", Runnable.class);
  44.146 -        inc.invoke(null, r);
  44.147 -        
  44.148 -        assertEquals(r.cnt, 1, "Callback happened");
  44.149 -    }
  44.150 -    
  44.151 -    @Test public void sumArray() throws Throwable {
  44.152 -        Method st = methodClass.getMethod("sumArr", int[].class);
  44.153 -        assertEquals(st.invoke(null, new int[] { 1, 2, 3 }), 6, "1+2+3 is six");
  44.154 -    }
  44.155 -    
  44.156 -    @Test public void javaScriptResource() throws Throwable {
  44.157 -        try {
  44.158 -            Method st = methodClass.getMethod("useExternalMul", int.class, int.class);
  44.159 -            assertEquals(st.invoke(null, 6, 7), 42, "Meaning of JavaScript?");
  44.160 -        } catch (InvocationTargetException ex) {
  44.161 -            throw ex.getTargetException();
  44.162 -        }
  44.163 -    }
  44.164 -    
  44.165 -    @Test public void callJavaScriptMethodOnOwnClass() throws Throwable {
  44.166 -        try {
  44.167 -            Object thiz = methodClass.newInstance();
  44.168 -            Method st = methodClass.getMethod("returnYourSelf", methodClass);
  44.169 -            assertEquals(st.invoke(null, thiz), thiz, "Returns this");
  44.170 -        } catch (InvocationTargetException ex) {
  44.171 -            throw ex.getTargetException();
  44.172 -        }
  44.173 -    }
  44.174 -    
  44.175 -    @Test public void callStaticJavaMethod() throws Throwable {
  44.176 -        Method st = methodClass.getMethod("staticCallback", int.class, int.class);
  44.177 -        assertEquals(st.invoke(null, 6, 7), 42, "Meaning of JavaScript?");
  44.178 -    }
  44.179 -
  44.180 -    @Test public void callStaticStringParamMethod() throws Throwable {
  44.181 -        Method st = methodClass.getMethod("parseInt", String.class);
  44.182 -        assertEquals(st.invoke(null, "42"), 42, "Meaning of JavaScript?");
  44.183 -    }
  44.184 -    
  44.185 -    @Test public void firstLong() throws Throwable {
  44.186 -        Method st = methodClass.getMethod("chooseLong", boolean.class, boolean.class, long.class, long.class);
  44.187 -        assertEquals(st.invoke(null, true, false, 10, 20), 10L, "Take first value");
  44.188 -    }
  44.189 -
  44.190 -    @Test public void secondLong() throws Throwable {
  44.191 -        Method st = methodClass.getMethod("chooseLong", boolean.class, boolean.class, long.class, long.class);
  44.192 -        assertEquals(st.invoke(null, false, true, 10, 20), 20L, "Take 2nd value");
  44.193 -    }
  44.194 -
  44.195 -    @Test public void bothLong() throws Throwable {
  44.196 -        Method st = methodClass.getMethod("chooseLong", boolean.class, boolean.class, long.class, long.class);
  44.197 -        assertEquals(st.invoke(null, true, true, 10, 20), 30L, "Take both values");
  44.198 -    }
  44.199 -    
  44.200 -    @Test public void recordError() throws Throwable {
  44.201 -        Method st = methodClass.getMethod("recordError", Object.class);
  44.202 -        assertEquals(st.invoke(methodClass.newInstance(), "Hello"), "Hello", "The same parameter returned");
  44.203 -    }
  44.204 -}
  44.205 \ No newline at end of file
    45.1 --- a/boot/src/test/java/org/apidesign/html/boot/impl/JsClassLoaderTest.java	Mon Dec 16 15:48:09 2013 +0100
    45.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.3 @@ -1,155 +0,0 @@
    45.4 -/**
    45.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    45.6 - *
    45.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    45.8 - *
    45.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   45.10 - * Other names may be trademarks of their respective owners.
   45.11 - *
   45.12 - * The contents of this file are subject to the terms of either the GNU
   45.13 - * General Public License Version 2 only ("GPL") or the Common
   45.14 - * Development and Distribution License("CDDL") (collectively, the
   45.15 - * "License"). You may not use this file except in compliance with the
   45.16 - * License. You can obtain a copy of the License at
   45.17 - * http://www.netbeans.org/cddl-gplv2.html
   45.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   45.19 - * specific language governing permissions and limitations under the
   45.20 - * License.  When distributing the software, include this License Header
   45.21 - * Notice in each file and include the License file at
   45.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   45.23 - * particular file as subject to the "Classpath" exception as provided
   45.24 - * by Oracle in the GPL Version 2 section of the License file that
   45.25 - * accompanied this code. If applicable, add the following below the
   45.26 - * License Header, with the fields enclosed by brackets [] replaced by
   45.27 - * your own identifying information:
   45.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   45.29 - *
   45.30 - * Contributor(s):
   45.31 - *
   45.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   45.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   45.34 - *
   45.35 - * If you wish your version of this file to be governed by only the CDDL
   45.36 - * or only the GPL Version 2, indicate your decision by adding
   45.37 - * "[Contributor] elects to include this software in this distribution
   45.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   45.39 - * single choice of license, a recipient has the option to distribute
   45.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   45.41 - * to extend the choice of license to its licensees as provided above.
   45.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   45.43 - * Version 2 license, then the option applies only if the new code is
   45.44 - * made subject to such option by the copyright holder.
   45.45 - */
   45.46 -package org.apidesign.html.boot.impl;
   45.47 -
   45.48 -import java.io.Closeable;
   45.49 -import java.io.Reader;
   45.50 -import org.apidesign.html.boot.spi.Fn;
   45.51 -import java.net.URL;
   45.52 -import java.net.URLClassLoader;
   45.53 -import java.util.ArrayList;
   45.54 -import java.util.Arrays;
   45.55 -import java.util.Enumeration;
   45.56 -import java.util.List;
   45.57 -import javax.script.Invocable;
   45.58 -import javax.script.ScriptEngine;
   45.59 -import javax.script.ScriptEngineManager;
   45.60 -import javax.script.ScriptException;
   45.61 -import org.testng.annotations.AfterClass;
   45.62 -import org.testng.annotations.BeforeClass;
   45.63 -import org.testng.annotations.BeforeMethod;
   45.64 -
   45.65 -/**
   45.66 - *
   45.67 - * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   45.68 - */
   45.69 -public class JsClassLoaderTest extends JsClassLoaderBase{
   45.70 -    private static Fn.Presenter loader;
   45.71 -
   45.72 -    @BeforeClass
   45.73 -    public static void setUpClass() throws Exception {
   45.74 -        ScriptEngineManager sem = new ScriptEngineManager();
   45.75 -        final ScriptEngine eng = sem.getEngineByMimeType("text/javascript");
   45.76 -        
   45.77 -        final URL my = JsClassLoaderTest.class.getProtectionDomain().getCodeSource().getLocation();
   45.78 -        ClassLoader parent = JsClassLoaderTest.class.getClassLoader().getParent();
   45.79 -        final URLClassLoader ul = new URLClassLoader(new URL[] { my }, parent);
   45.80 -        class MyCL extends JsClassLoader implements Fn.Presenter {
   45.81 -
   45.82 -            public MyCL(ClassLoader parent) {
   45.83 -                super(parent);
   45.84 -            }
   45.85 -            
   45.86 -            @Override
   45.87 -            protected URL findResource(String name) {
   45.88 -                return ul.getResource(name);
   45.89 -            }
   45.90 -            @Override
   45.91 -            public Fn defineFn(String code, String... names) {
   45.92 -                StringBuilder sb = new StringBuilder();
   45.93 -                sb.append("(function() {");
   45.94 -                sb.append("return function(");
   45.95 -                String sep = "";
   45.96 -                for (String n : names) {
   45.97 -                    sb.append(sep);
   45.98 -                    sb.append(n);
   45.99 -                    sep = ", ";
  45.100 -                }
  45.101 -                sb.append(") {");
  45.102 -                sb.append(code);
  45.103 -                sb.append("};");
  45.104 -                sb.append("})()");
  45.105 -                try {
  45.106 -                    final Object val = eng.eval(sb.toString());
  45.107 -                    return new Fn(this) {
  45.108 -                        @Override
  45.109 -                        public Object invoke(Object thiz, Object... args) throws Exception {
  45.110 -                            List<Object> all = new ArrayList<Object>(args.length + 1);
  45.111 -                            all.add(thiz == null ? val : thiz);
  45.112 -                            all.addAll(Arrays.asList(args));
  45.113 -                            Invocable inv = (Invocable)eng;
  45.114 -                            try {
  45.115 -                                Object ret = inv.invokeMethod(val, "call", all.toArray());
  45.116 -                                return val.equals(ret) ? null : ret;
  45.117 -                            } catch (Exception ex) {
  45.118 -                                throw ex;
  45.119 -                            }
  45.120 -                        }
  45.121 -                    };
  45.122 -                } catch (ScriptException ex) {
  45.123 -                    throw new LinkageError("Can't parse: " + sb, ex);
  45.124 -                }
  45.125 -            }
  45.126 -
  45.127 -            @Override
  45.128 -            protected Enumeration<URL> findResources(String name) {
  45.129 -                throw new UnsupportedOperationException();
  45.130 -            }
  45.131 -
  45.132 -            @Override
  45.133 -            public void loadScript(Reader code) throws ScriptException {
  45.134 -                eng.eval(code);
  45.135 -            }
  45.136 -
  45.137 -            @Override
  45.138 -            public void displayPage(URL page, Runnable onPageLoad) {
  45.139 -                throw new UnsupportedOperationException();
  45.140 -            }
  45.141 -        };
  45.142 -        
  45.143 -        MyCL l = new MyCL(parent);
  45.144 -        Closeable close = FnContext.activate(l);
  45.145 -        methodClass = l.loadClass(JsMethods.class.getName());
  45.146 -        close.close();
  45.147 -        loader = l;
  45.148 -    }
  45.149 -    
  45.150 -    @BeforeMethod public void initPresenter() {
  45.151 -        FnContext.currentPresenter(loader);
  45.152 -    }
  45.153 -
  45.154 -    @AfterClass
  45.155 -    public static void cleanUp() {
  45.156 -        methodClass = null;
  45.157 -    }
  45.158 -}
  45.159 \ No newline at end of file
    46.1 --- a/boot/src/test/java/org/apidesign/html/boot/impl/JsMethods.java	Mon Dec 16 15:48:09 2013 +0100
    46.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.3 @@ -1,129 +0,0 @@
    46.4 -/**
    46.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    46.6 - *
    46.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    46.8 - *
    46.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   46.10 - * Other names may be trademarks of their respective owners.
   46.11 - *
   46.12 - * The contents of this file are subject to the terms of either the GNU
   46.13 - * General Public License Version 2 only ("GPL") or the Common
   46.14 - * Development and Distribution License("CDDL") (collectively, the
   46.15 - * "License"). You may not use this file except in compliance with the
   46.16 - * License. You can obtain a copy of the License at
   46.17 - * http://www.netbeans.org/cddl-gplv2.html
   46.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   46.19 - * specific language governing permissions and limitations under the
   46.20 - * License.  When distributing the software, include this License Header
   46.21 - * Notice in each file and include the License file at
   46.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   46.23 - * particular file as subject to the "Classpath" exception as provided
   46.24 - * by Oracle in the GPL Version 2 section of the License file that
   46.25 - * accompanied this code. If applicable, add the following below the
   46.26 - * License Header, with the fields enclosed by brackets [] replaced by
   46.27 - * your own identifying information:
   46.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   46.29 - *
   46.30 - * Contributor(s):
   46.31 - *
   46.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   46.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   46.34 - *
   46.35 - * If you wish your version of this file to be governed by only the CDDL
   46.36 - * or only the GPL Version 2, indicate your decision by adding
   46.37 - * "[Contributor] elects to include this software in this distribution
   46.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   46.39 - * single choice of license, a recipient has the option to distribute
   46.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   46.41 - * to extend the choice of license to its licensees as provided above.
   46.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   46.43 - * Version 2 license, then the option applies only if the new code is
   46.44 - * made subject to such option by the copyright holder.
   46.45 - */
   46.46 -package org.apidesign.html.boot.impl;
   46.47 -
   46.48 -import net.java.html.js.JavaScriptBody;
   46.49 -import net.java.html.js.JavaScriptResource;
   46.50 -
   46.51 -
   46.52 -/**
   46.53 - *
   46.54 - * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   46.55 - */
   46.56 -@JavaScriptResource("jsmethods.js")
   46.57 -public class JsMethods {
   46.58 -    private Object value;
   46.59 -    
   46.60 -    @JavaScriptBody(args = {}, body = "return 42;")
   46.61 -    public static Object fortyTwo() {
   46.62 -        return -42;
   46.63 -    }
   46.64 -    
   46.65 -    @JavaScriptBody(args = {"x", "y" }, body = "return x + y;")
   46.66 -    public static native int plus(int x, int y);
   46.67 -    
   46.68 -    @JavaScriptBody(args = {"x"}, body = "return x;")
   46.69 -    public static native int plus(int x);
   46.70 -    
   46.71 -    @JavaScriptBody(args = {}, body = "return this;")
   46.72 -    public static native Object staticThis();
   46.73 -    
   46.74 -    @JavaScriptBody(args = {}, body = "return this;")
   46.75 -    public native Object getThis();
   46.76 -    @JavaScriptBody(args = {"x"}, body = "return x;")
   46.77 -    public native int plusInst(int x);
   46.78 -    
   46.79 -    @JavaScriptBody(args = {}, body = "return true;")
   46.80 -    public static boolean truth() {
   46.81 -        return false;
   46.82 -    }
   46.83 -    
   46.84 -    @JavaScriptBody(args = { "r" }, javacall=true, body = "r.@java.lang.Runnable::run()();")
   46.85 -    public static native void callback(Runnable r);
   46.86 -    
   46.87 -    @JavaScriptBody(args = { "at", "arr" }, javacall = true, body =
   46.88 -          "var a = 0;\n"
   46.89 -        + "for (var i = 0; i < arr.length; i++) {\n"
   46.90 -        + "  a = at.@org.apidesign.html.boot.impl.Arithm::sumTwo(II)(a, arr[i]);\n"
   46.91 -        + "}\n"
   46.92 -        + "return a;"
   46.93 -    )
   46.94 -    private static native int sumArr(Arithm at, int... arr);
   46.95 -    
   46.96 -    public static int sumArr(int... arr) {
   46.97 -        return sumArr(new Arithm(), arr);
   46.98 -    }
   46.99 -    
  46.100 -    @JavaScriptBody(args = { "x", "y" }, body = "return mul(x, y);")
  46.101 -    public static native int useExternalMul(int x, int y);
  46.102 -    
  46.103 -    @JavaScriptBody(args = { "m" }, javacall = true, body = "return m.@org.apidesign.html.boot.impl.JsMethods::getThis()();")
  46.104 -    public static native JsMethods returnYourSelf(JsMethods m);
  46.105 -    
  46.106 -    @JavaScriptBody(args = { "x", "y" }, javacall = true, body = "return @org.apidesign.html.boot.impl.JsMethods::useExternalMul(II)(x, y);")
  46.107 -    public static native int staticCallback(int x, int y);
  46.108 -
  46.109 -    @JavaScriptBody(args = { "v" }, javacall = true, body = "return @java.lang.Integer::parseInt(Ljava/lang/String;)(v);")
  46.110 -    public static native int parseInt(String v);
  46.111 -    
  46.112 -    @JavaScriptBody(args = { "useA", "useB", "a", "b" }, body = "var l = 0;"
  46.113 -        + "if (useA) l += a;\n"
  46.114 -        + "if (useB) l += b;\n"
  46.115 -        + "return l;\n"
  46.116 -    )
  46.117 -    public static native long chooseLong(boolean useA, boolean useB, long a, long b);
  46.118 -    
  46.119 -    protected void onError(Object o) throws Exception {
  46.120 -        value = o;
  46.121 -    }
  46.122 -    
  46.123 -    Object getError() {
  46.124 -        return value;
  46.125 -    }
  46.126 -    
  46.127 -    @JavaScriptBody(args = { "err" }, javacall = true, body = 
  46.128 -        "this.@org.apidesign.html.boot.impl.JsMethods::onError(Ljava/lang/Object;)(err);"
  46.129 -      + "return this.@org.apidesign.html.boot.impl.JsMethods::getError()();"
  46.130 -    )
  46.131 -    public native Object recordError(Object err);
  46.132 -}
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/Arithm.java	Mon Dec 16 16:59:43 2013 +0100
    47.3 @@ -0,0 +1,53 @@
    47.4 +/**
    47.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    47.6 + *
    47.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    47.8 + *
    47.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   47.10 + * Other names may be trademarks of their respective owners.
   47.11 + *
   47.12 + * The contents of this file are subject to the terms of either the GNU
   47.13 + * General Public License Version 2 only ("GPL") or the Common
   47.14 + * Development and Distribution License("CDDL") (collectively, the
   47.15 + * "License"). You may not use this file except in compliance with the
   47.16 + * License. You can obtain a copy of the License at
   47.17 + * http://www.netbeans.org/cddl-gplv2.html
   47.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   47.19 + * specific language governing permissions and limitations under the
   47.20 + * License.  When distributing the software, include this License Header
   47.21 + * Notice in each file and include the License file at
   47.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   47.23 + * particular file as subject to the "Classpath" exception as provided
   47.24 + * by Oracle in the GPL Version 2 section of the License file that
   47.25 + * accompanied this code. If applicable, add the following below the
   47.26 + * License Header, with the fields enclosed by brackets [] replaced by
   47.27 + * your own identifying information:
   47.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   47.29 + *
   47.30 + * Contributor(s):
   47.31 + *
   47.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   47.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   47.34 + *
   47.35 + * If you wish your version of this file to be governed by only the CDDL
   47.36 + * or only the GPL Version 2, indicate your decision by adding
   47.37 + * "[Contributor] elects to include this software in this distribution
   47.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   47.39 + * single choice of license, a recipient has the option to distribute
   47.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   47.41 + * to extend the choice of license to its licensees as provided above.
   47.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   47.43 + * Version 2 license, then the option applies only if the new code is
   47.44 + * made subject to such option by the copyright holder.
   47.45 + */
   47.46 +package org.netbeans.html.boot.impl;
   47.47 +
   47.48 +/**
   47.49 + *
   47.50 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   47.51 + */
   47.52 +public class Arithm {
   47.53 +    public int sumTwo(int a, int b) {
   47.54 +        return a + b;
   47.55 +    }
   47.56 +}
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/Compile.java	Mon Dec 16 16:59:43 2013 +0100
    48.3 @@ -0,0 +1,291 @@
    48.4 +/**
    48.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    48.6 + *
    48.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    48.8 + *
    48.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   48.10 + * Other names may be trademarks of their respective owners.
   48.11 + *
   48.12 + * The contents of this file are subject to the terms of either the GNU
   48.13 + * General Public License Version 2 only ("GPL") or the Common
   48.14 + * Development and Distribution License("CDDL") (collectively, the
   48.15 + * "License"). You may not use this file except in compliance with the
   48.16 + * License. You can obtain a copy of the License at
   48.17 + * http://www.netbeans.org/cddl-gplv2.html
   48.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   48.19 + * specific language governing permissions and limitations under the
   48.20 + * License.  When distributing the software, include this License Header
   48.21 + * Notice in each file and include the License file at
   48.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   48.23 + * particular file as subject to the "Classpath" exception as provided
   48.24 + * by Oracle in the GPL Version 2 section of the License file that
   48.25 + * accompanied this code. If applicable, add the following below the
   48.26 + * License Header, with the fields enclosed by brackets [] replaced by
   48.27 + * your own identifying information:
   48.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   48.29 + *
   48.30 + * Contributor(s):
   48.31 + *
   48.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   48.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   48.34 + *
   48.35 + * If you wish your version of this file to be governed by only the CDDL
   48.36 + * or only the GPL Version 2, indicate your decision by adding
   48.37 + * "[Contributor] elects to include this software in this distribution
   48.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   48.39 + * single choice of license, a recipient has the option to distribute
   48.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   48.41 + * to extend the choice of license to its licensees as provided above.
   48.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   48.43 + * Version 2 license, then the option applies only if the new code is
   48.44 + * made subject to such option by the copyright holder.
   48.45 + */
   48.46 +package org.netbeans.html.boot.impl;
   48.47 +
   48.48 +import java.io.ByteArrayInputStream;
   48.49 +import java.io.ByteArrayOutputStream;
   48.50 +import java.io.IOException;
   48.51 +import java.io.InputStream;
   48.52 +import java.io.OutputStream;
   48.53 +import java.net.URI;
   48.54 +import java.net.URISyntaxException;
   48.55 +import java.util.ArrayList;
   48.56 +import java.util.Arrays;
   48.57 +import java.util.HashMap;
   48.58 +import java.util.List;
   48.59 +import java.util.Locale;
   48.60 +import java.util.Map;
   48.61 +import java.util.regex.Matcher;
   48.62 +import java.util.regex.Pattern;
   48.63 +import javax.tools.Diagnostic;
   48.64 +import javax.tools.DiagnosticListener;
   48.65 +import javax.tools.FileObject;
   48.66 +import javax.tools.ForwardingJavaFileManager;
   48.67 +import javax.tools.JavaFileManager;
   48.68 +import javax.tools.JavaFileObject;
   48.69 +import javax.tools.JavaFileObject.Kind;
   48.70 +import javax.tools.SimpleJavaFileObject;
   48.71 +import javax.tools.StandardJavaFileManager;
   48.72 +import javax.tools.StandardLocation;
   48.73 +import javax.tools.ToolProvider;
   48.74 +import static org.testng.Assert.assertTrue;
   48.75 +import static org.testng.Assert.assertFalse;
   48.76 +import static org.testng.Assert.fail;
   48.77 +
   48.78 +/**
   48.79 + *
   48.80 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   48.81 + */
   48.82 +final class Compile implements DiagnosticListener<JavaFileObject> {
   48.83 +    private final List<Diagnostic<? extends JavaFileObject>> errors = 
   48.84 +            new ArrayList<Diagnostic<? extends JavaFileObject>>();
   48.85 +    private final Map<String, byte[]> classes;
   48.86 +    private final String pkg;
   48.87 +    private final String cls;
   48.88 +    private final String html;
   48.89 +    private final String sourceLevel;
   48.90 +
   48.91 +    private Compile(String html, String code, String sl) throws IOException {
   48.92 +        this.pkg = findPkg(code);
   48.93 +        this.cls = findCls(code);
   48.94 +        this.html = html;
   48.95 +        this.sourceLevel = sl;
   48.96 +        classes = compile(html, code);
   48.97 +    }
   48.98 +
   48.99 +    /** Performs compilation of given HTML page and associated Java code
  48.100 +     */
  48.101 +    public static Compile create(String html, String code) throws IOException {
  48.102 +        return create(html, code, "1.7");
  48.103 +    }
  48.104 +    static Compile create(String html, String code, String sourceLevel) throws IOException {
  48.105 +        return new Compile(html, code, sourceLevel);
  48.106 +    }
  48.107 +    
  48.108 +    /** Checks for given class among compiled resources */
  48.109 +    public byte[] get(String res) {
  48.110 +        return classes.get(res);
  48.111 +    }
  48.112 +    
  48.113 +    /** Obtains errors created during compilation.
  48.114 +     */
  48.115 +    public List<Diagnostic<? extends JavaFileObject>> getErrors() {
  48.116 +        List<Diagnostic<? extends JavaFileObject>> err;
  48.117 +        err = new ArrayList<Diagnostic<? extends JavaFileObject>>();
  48.118 +        for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
  48.119 +            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
  48.120 +                err.add(diagnostic);
  48.121 +            }
  48.122 +        }
  48.123 +        return err;
  48.124 +    }
  48.125 +    
  48.126 +    private Map<String, byte[]> compile(final String html, final String code) throws IOException {
  48.127 +        StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
  48.128 +
  48.129 +        final Map<String, ByteArrayOutputStream> class2BAOS;
  48.130 +        class2BAOS = new HashMap<String, ByteArrayOutputStream>();
  48.131 +
  48.132 +        JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
  48.133 +            @Override
  48.134 +            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
  48.135 +                return code;
  48.136 +            }
  48.137 +        };
  48.138 +        final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
  48.139 +            @Override
  48.140 +            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
  48.141 +                return html;
  48.142 +            }
  48.143 +
  48.144 +            @Override
  48.145 +            public InputStream openInputStream() throws IOException {
  48.146 +                return new ByteArrayInputStream(html.getBytes());
  48.147 +            }
  48.148 +        };
  48.149 +        
  48.150 +        final URI scratch;
  48.151 +        try {
  48.152 +            scratch = new URI("mem://mem3");
  48.153 +        } catch (URISyntaxException ex) {
  48.154 +            throw new IOException(ex);
  48.155 +        }
  48.156 +        
  48.157 +        JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
  48.158 +            @Override
  48.159 +            public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
  48.160 +                if (kind  == Kind.CLASS) {
  48.161 +                    final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
  48.162 +
  48.163 +                    class2BAOS.put(className.replace('.', '/') + ".class", buffer);
  48.164 +                    return new SimpleJavaFileObject(sibling.toUri(), kind) {
  48.165 +                        @Override
  48.166 +                        public OutputStream openOutputStream() throws IOException {
  48.167 +                            return buffer;
  48.168 +                        }
  48.169 +                    };
  48.170 +                }
  48.171 +                
  48.172 +                if (kind == Kind.SOURCE) {
  48.173 +                    final String n = className.replace('.', '/') + ".java";
  48.174 +                    final URI un;
  48.175 +                    try {
  48.176 +                        un = new URI("mem://" + n);
  48.177 +                    } catch (URISyntaxException ex) {
  48.178 +                        throw new IOException(ex);
  48.179 +                    }
  48.180 +                    return new VirtFO(un/*sibling.toUri()*/, kind, n);
  48.181 +                }
  48.182 +                
  48.183 +                throw new IllegalStateException();
  48.184 +            }
  48.185 +
  48.186 +            @Override
  48.187 +            public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
  48.188 +                if (location == StandardLocation.SOURCE_PATH) {
  48.189 +                    if (packageName.equals(pkg)) {
  48.190 +                        return htmlFile;
  48.191 +                    }
  48.192 +                }
  48.193 +                
  48.194 +                return null;
  48.195 +            }
  48.196 +
  48.197 +            @Override
  48.198 +            public boolean isSameFile(FileObject a, FileObject b) {
  48.199 +                if (a instanceof VirtFO && b instanceof VirtFO) {
  48.200 +                    return ((VirtFO)a).getName().equals(((VirtFO)b).getName());
  48.201 +                }
  48.202 +                
  48.203 +                return super.isSameFile(a, b);
  48.204 +            }
  48.205 +
  48.206 +            class VirtFO extends SimpleJavaFileObject {
  48.207 +
  48.208 +                private final String n;
  48.209 +
  48.210 +                public VirtFO(URI uri, Kind kind, String n) {
  48.211 +                    super(uri, kind);
  48.212 +                    this.n = n;
  48.213 +                }
  48.214 +                private final ByteArrayOutputStream data = new ByteArrayOutputStream();
  48.215 +
  48.216 +                @Override
  48.217 +                public OutputStream openOutputStream() throws IOException {
  48.218 +                    return data;
  48.219 +                }
  48.220 +
  48.221 +                @Override
  48.222 +                public String getName() {
  48.223 +                    return n;
  48.224 +                }
  48.225 +
  48.226 +                @Override
  48.227 +                public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
  48.228 +                    data.close();
  48.229 +                    return new String(data.toByteArray());
  48.230 +                }
  48.231 +            }
  48.232 +        };
  48.233 +
  48.234 +        ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", sourceLevel, "-target", "1.7"), null, Arrays.asList(file)).call();
  48.235 +
  48.236 +        Map<String, byte[]> result = new HashMap<String, byte[]>();
  48.237 +
  48.238 +        for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
  48.239 +            result.put(e.getKey(), e.getValue().toByteArray());
  48.240 +        }
  48.241 +
  48.242 +        return result;
  48.243 +    }
  48.244 +
  48.245 +
  48.246 +    @Override
  48.247 +    public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
  48.248 +        errors.add(diagnostic);
  48.249 +    }
  48.250 +    private static String findPkg(String java) throws IOException {
  48.251 +        Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
  48.252 +        Matcher m = p.matcher(java);
  48.253 +        if (!m.find()) {
  48.254 +            throw new IOException("Can't find package declaration in the java file");
  48.255 +        }
  48.256 +        String pkg = m.group(1);
  48.257 +        return pkg;
  48.258 +    }
  48.259 +    private static String findCls(String java) throws IOException {
  48.260 +        Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
  48.261 +        Matcher m = p.matcher(java);
  48.262 +        if (!m.find()) {
  48.263 +            throw new IOException("Can't find package declaration in the java file");
  48.264 +        }
  48.265 +        String cls = m.group(1);
  48.266 +        return cls;
  48.267 +    }
  48.268 +
  48.269 +    String getHtml() {
  48.270 +        String fqn = "'" + pkg + '.' + cls + "'";
  48.271 +        return html.replace("'${fqn}'", fqn);
  48.272 +    }
  48.273 +    void assertErrors() {
  48.274 +        assertFalse(getErrors().isEmpty(), "There are supposed to be some errors");
  48.275 +    }
  48.276 +
  48.277 +    void assertError(String expMsg) {
  48.278 +        StringBuilder sb = new StringBuilder();
  48.279 +        sb.append("Can't find ").append(expMsg).append(" among:");
  48.280 +        for (Diagnostic<? extends JavaFileObject> e : errors) {
  48.281 +            String msg = e.getMessage(Locale.US);
  48.282 +            if (msg.contains(expMsg)) {
  48.283 +                return;
  48.284 +            }
  48.285 +            sb.append("\n");
  48.286 +            sb.append(msg);
  48.287 +        }
  48.288 +        fail(sb.toString());
  48.289 +    }
  48.290 +
  48.291 +    void assertNoErrors() {
  48.292 +        assertTrue(getErrors().isEmpty(), "No errors expected: " + getErrors());
  48.293 +    }
  48.294 +}
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/FnTest.java	Mon Dec 16 16:59:43 2013 +0100
    49.3 @@ -0,0 +1,148 @@
    49.4 +/**
    49.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    49.6 + *
    49.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    49.8 + *
    49.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   49.10 + * Other names may be trademarks of their respective owners.
   49.11 + *
   49.12 + * The contents of this file are subject to the terms of either the GNU
   49.13 + * General Public License Version 2 only ("GPL") or the Common
   49.14 + * Development and Distribution License("CDDL") (collectively, the
   49.15 + * "License"). You may not use this file except in compliance with the
   49.16 + * License. You can obtain a copy of the License at
   49.17 + * http://www.netbeans.org/cddl-gplv2.html
   49.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   49.19 + * specific language governing permissions and limitations under the
   49.20 + * License.  When distributing the software, include this License Header
   49.21 + * Notice in each file and include the License file at
   49.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   49.23 + * particular file as subject to the "Classpath" exception as provided
   49.24 + * by Oracle in the GPL Version 2 section of the License file that
   49.25 + * accompanied this code. If applicable, add the following below the
   49.26 + * License Header, with the fields enclosed by brackets [] replaced by
   49.27 + * your own identifying information:
   49.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   49.29 + *
   49.30 + * Contributor(s):
   49.31 + *
   49.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   49.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   49.34 + *
   49.35 + * If you wish your version of this file to be governed by only the CDDL
   49.36 + * or only the GPL Version 2, indicate your decision by adding
   49.37 + * "[Contributor] elects to include this software in this distribution
   49.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   49.39 + * single choice of license, a recipient has the option to distribute
   49.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   49.41 + * to extend the choice of license to its licensees as provided above.
   49.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   49.43 + * Version 2 license, then the option applies only if the new code is
   49.44 + * made subject to such option by the copyright holder.
   49.45 + */
   49.46 +package org.netbeans.html.boot.impl;
   49.47 +
   49.48 +import java.io.Closeable;
   49.49 +import java.io.Reader;
   49.50 +import java.net.URL;
   49.51 +import java.net.URLClassLoader;
   49.52 +import java.util.ArrayList;
   49.53 +import java.util.Arrays;
   49.54 +import java.util.Collection;
   49.55 +import java.util.List;
   49.56 +import javax.script.Invocable;
   49.57 +import javax.script.ScriptEngine;
   49.58 +import javax.script.ScriptEngineManager;
   49.59 +import javax.script.ScriptException;
   49.60 +import org.apidesign.html.boot.spi.Fn;
   49.61 +import org.testng.annotations.BeforeClass;
   49.62 +import org.testng.annotations.BeforeMethod;
   49.63 +
   49.64 +/**
   49.65 + *
   49.66 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   49.67 + */
   49.68 +public class FnTest extends JsClassLoaderBase {
   49.69 +    private static Fn.Presenter presenter;
   49.70 +    
   49.71 +    public FnTest() {
   49.72 +    }
   49.73 +
   49.74 +    @BeforeClass
   49.75 +    public static void createClassLoader() throws Exception {
   49.76 +        ScriptEngineManager sem = new ScriptEngineManager();
   49.77 +        final ScriptEngine eng = sem.getEngineByMimeType("text/javascript");
   49.78 +        
   49.79 +        final URL my = FnTest.class.getProtectionDomain().getCodeSource().getLocation();
   49.80 +        ClassLoader parent = JsClassLoaderTest.class.getClassLoader().getParent();
   49.81 +        final URLClassLoader ul = new URLClassLoader(new URL[] { my }, parent);
   49.82 +        
   49.83 +        class Impl implements FindResources, Fn.Presenter {
   49.84 +            @Override
   49.85 +            public void findResources(String path, Collection<? super URL> results, boolean oneIsEnough) {
   49.86 +                URL u = ul.findResource(path);
   49.87 +                if (u != null) {
   49.88 +                    results.add(u);
   49.89 +                }
   49.90 +            }
   49.91 +
   49.92 +            @Override
   49.93 +            public Fn defineFn(String code, String... names) {
   49.94 +                StringBuilder sb = new StringBuilder();
   49.95 +                sb.append("(function() {");
   49.96 +                sb.append("return function(");
   49.97 +                String sep = "";
   49.98 +                for (String n : names) {
   49.99 +                    sb.append(sep);
  49.100 +                    sb.append(n);
  49.101 +                    sep = ", ";
  49.102 +                }
  49.103 +                sb.append(") {");
  49.104 +                sb.append(code);
  49.105 +                sb.append("};");
  49.106 +                sb.append("})()");
  49.107 +                try {
  49.108 +                    final Object val = eng.eval(sb.toString());
  49.109 +                    return new Fn(this) {
  49.110 +                        @Override
  49.111 +                        public Object invoke(Object thiz, Object... args) throws Exception {
  49.112 +                            List<Object> all = new ArrayList<Object>(args.length + 1);
  49.113 +                            all.add(thiz == null ? val : thiz);
  49.114 +                            all.addAll(Arrays.asList(args));
  49.115 +                            Invocable inv = (Invocable)eng;
  49.116 +                            try {
  49.117 +                                Object ret = inv.invokeMethod(val, "call", all.toArray());
  49.118 +                                return val.equals(ret) ? null : ret;
  49.119 +                            } catch (ScriptException ex) {
  49.120 +                                throw ex;
  49.121 +                            }
  49.122 +                        }
  49.123 +                    };
  49.124 +                } catch (ScriptException ex) {
  49.125 +                    throw new LinkageError("Can't parse: " + sb, ex);
  49.126 +                }
  49.127 +            }
  49.128 +
  49.129 +            @Override
  49.130 +            public void displayPage(URL resource, Runnable r) {
  49.131 +                throw new UnsupportedOperationException();
  49.132 +            }
  49.133 +
  49.134 +            @Override
  49.135 +            public void loadScript(Reader code) throws Exception {
  49.136 +                eng.eval(code);
  49.137 +            }
  49.138 +        }
  49.139 +        Impl impl = new Impl();
  49.140 +        ClassLoader loader = FnUtils.newLoader(impl, impl, parent);
  49.141 +        presenter = impl;
  49.142 +        
  49.143 +        Closeable close = FnContext.activate(impl);
  49.144 +        methodClass = loader.loadClass(JsMethods.class.getName());
  49.145 +        close.close();
  49.146 +    }
  49.147 +
  49.148 +    @BeforeMethod public void initPresenter() {
  49.149 +        FnContext.currentPresenter(presenter);
  49.150 +    }
  49.151 +}
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/JavaScriptProcesorTest.java	Mon Dec 16 16:59:43 2013 +0100
    50.3 @@ -0,0 +1,129 @@
    50.4 +/**
    50.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    50.6 + *
    50.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    50.8 + *
    50.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   50.10 + * Other names may be trademarks of their respective owners.
   50.11 + *
   50.12 + * The contents of this file are subject to the terms of either the GNU
   50.13 + * General Public License Version 2 only ("GPL") or the Common
   50.14 + * Development and Distribution License("CDDL") (collectively, the
   50.15 + * "License"). You may not use this file except in compliance with the
   50.16 + * License. You can obtain a copy of the License at
   50.17 + * http://www.netbeans.org/cddl-gplv2.html
   50.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   50.19 + * specific language governing permissions and limitations under the
   50.20 + * License.  When distributing the software, include this License Header
   50.21 + * Notice in each file and include the License file at
   50.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   50.23 + * particular file as subject to the "Classpath" exception as provided
   50.24 + * by Oracle in the GPL Version 2 section of the License file that
   50.25 + * accompanied this code. If applicable, add the following below the
   50.26 + * License Header, with the fields enclosed by brackets [] replaced by
   50.27 + * your own identifying information:
   50.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   50.29 + *
   50.30 + * Contributor(s):
   50.31 + *
   50.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   50.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   50.34 + *
   50.35 + * If you wish your version of this file to be governed by only the CDDL
   50.36 + * or only the GPL Version 2, indicate your decision by adding
   50.37 + * "[Contributor] elects to include this software in this distribution
   50.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   50.39 + * single choice of license, a recipient has the option to distribute
   50.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   50.41 + * to extend the choice of license to its licensees as provided above.
   50.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   50.43 + * Version 2 license, then the option applies only if the new code is
   50.44 + * made subject to such option by the copyright holder.
   50.45 + */
   50.46 +package org.netbeans.html.boot.impl;
   50.47 +
   50.48 +import java.io.IOException;
   50.49 +import java.lang.reflect.Field;
   50.50 +import java.lang.reflect.Method;
   50.51 +import static org.testng.Assert.assertEquals;
   50.52 +import static org.testng.Assert.assertTrue;
   50.53 +import org.testng.annotations.Test;
   50.54 +
   50.55 +/**
   50.56 + *
   50.57 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   50.58 + */
   50.59 +public class JavaScriptProcesorTest {
   50.60 +    
   50.61 +    @Test public void detectCallbackToNonExistingClass() throws IOException {
   50.62 +        String code = "package x.y.z;\n"
   50.63 +            + "import net.java.html.js.JavaScriptBody;\n"
   50.64 +            + "class X {\n"
   50.65 +            + "  @JavaScriptBody(args={\"r\"}, javacall=true, body =\n"
   50.66 +            + "    \"r.@java.lang.Runable::run()();\"\n" // typo
   50.67 +            + "  )\n"
   50.68 +            + "  private static native void callback(Runnable r);\n"
   50.69 +            + "}\n";
   50.70 +        
   50.71 +        Compile c = Compile.create("", code);
   50.72 +        c.assertErrors();
   50.73 +        c.assertError("java.lang.Runable"); // typo
   50.74 +    }
   50.75 +
   50.76 +    @Test public void detectCallbackToNonExistingMethod() throws IOException {
   50.77 +        String code = "package x.y.z;\n"
   50.78 +            + "import net.java.html.js.JavaScriptBody;\n"
   50.79 +            + "class X {\n"
   50.80 +            + "  @JavaScriptBody(args={\"r\"}, javacall=true, body =\n"
   50.81 +            + "    \"r.@java.lang.Runnable::cancel()();\"\n"
   50.82 +            + "  )\n"
   50.83 +            + "  private static native void callback(Runnable r);\n"
   50.84 +            + "}\n";
   50.85 +        
   50.86 +        Compile c = Compile.create("", code);
   50.87 +        c.assertErrors();
   50.88 +        c.assertError("method cancel");
   50.89 +    }
   50.90 +
   50.91 +    @Test public void detectCallbackToNonExistingParams() throws IOException {
   50.92 +        String code = "package x.y.z;\n"
   50.93 +            + "import net.java.html.js.JavaScriptBody;\n"
   50.94 +            + "class X {\n"
   50.95 +            + "  @JavaScriptBody(args={\"r\"}, javacall=true, body =\n"
   50.96 +            + "    \"r.@java.lang.Runnable::run(I)(10);\"\n"
   50.97 +            + "  )\n"
   50.98 +            + "  private static native void callback(Runnable r);\n"
   50.99 +            + "}\n";
  50.100 +        
  50.101 +        Compile c = Compile.create("", code);
  50.102 +        c.assertErrors();
  50.103 +        c.assertError("wrong parameters: (I)");
  50.104 +    }
  50.105 +
  50.106 +    @Test public void objectTypeParamsAreOK() throws IOException {
  50.107 +        String code = "package x.y.z;\n"
  50.108 +            + "import net.java.html.js.JavaScriptBody;\n"
  50.109 +            + "class X {\n"
  50.110 +            + "  @JavaScriptBody(args={\"r\"}, javacall=true, body =\n"
  50.111 +            + "    \"r.@java.lang.Object::equals(Ljava/lang/Object;)(null);\"\n"
  50.112 +            + "  )\n"
  50.113 +            + "  private static native void testEqual(Object r);\n"
  50.114 +            + "}\n";
  50.115 +        
  50.116 +        Compile c = Compile.create("", code);
  50.117 +        c.assertNoErrors();
  50.118 +    }
  50.119 +    
  50.120 +    @Test public void generatesCallbacksThatReturnObject() throws Exception {
  50.121 +        Class<?> callbacksForTestPkg = Class.forName("org.netbeans.html.boot.impl.$JsCallbacks$");
  50.122 +        Method m = callbacksForTestPkg.getDeclaredMethod("java_lang_Runnable$run$", Runnable.class);
  50.123 +        assertEquals(m.getReturnType(), Object.class, "All methods always return object");
  50.124 +    }
  50.125 +    
  50.126 +    @Test public void hasInstanceField() throws Exception {
  50.127 +        Class<?> callbacksForTestPkg = Class.forName("org.netbeans.html.boot.impl.$JsCallbacks$");
  50.128 +        Field f = callbacksForTestPkg.getDeclaredField("VM");
  50.129 +        f.setAccessible(true);
  50.130 +        assertTrue(callbacksForTestPkg.isInstance(f.get(null)), "Singleton field VM");
  50.131 +    }
  50.132 +}
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderBase.java	Mon Dec 16 16:59:43 2013 +0100
    51.3 @@ -0,0 +1,201 @@
    51.4 +/**
    51.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    51.6 + *
    51.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    51.8 + *
    51.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   51.10 + * Other names may be trademarks of their respective owners.
   51.11 + *
   51.12 + * The contents of this file are subject to the terms of either the GNU
   51.13 + * General Public License Version 2 only ("GPL") or the Common
   51.14 + * Development and Distribution License("CDDL") (collectively, the
   51.15 + * "License"). You may not use this file except in compliance with the
   51.16 + * License. You can obtain a copy of the License at
   51.17 + * http://www.netbeans.org/cddl-gplv2.html
   51.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   51.19 + * specific language governing permissions and limitations under the
   51.20 + * License.  When distributing the software, include this License Header
   51.21 + * Notice in each file and include the License file at
   51.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   51.23 + * particular file as subject to the "Classpath" exception as provided
   51.24 + * by Oracle in the GPL Version 2 section of the License file that
   51.25 + * accompanied this code. If applicable, add the following below the
   51.26 + * License Header, with the fields enclosed by brackets [] replaced by
   51.27 + * your own identifying information:
   51.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   51.29 + *
   51.30 + * Contributor(s):
   51.31 + *
   51.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   51.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   51.34 + *
   51.35 + * If you wish your version of this file to be governed by only the CDDL
   51.36 + * or only the GPL Version 2, indicate your decision by adding
   51.37 + * "[Contributor] elects to include this software in this distribution
   51.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   51.39 + * single choice of license, a recipient has the option to distribute
   51.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   51.41 + * to extend the choice of license to its licensees as provided above.
   51.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   51.43 + * Version 2 license, then the option applies only if the new code is
   51.44 + * made subject to such option by the copyright holder.
   51.45 + */
   51.46 +package org.netbeans.html.boot.impl;
   51.47 +
   51.48 +import java.lang.reflect.InvocationTargetException;
   51.49 +import java.lang.reflect.Method;
   51.50 +import java.lang.reflect.Modifier;
   51.51 +import static org.testng.Assert.*;
   51.52 +import org.testng.annotations.BeforeMethod;
   51.53 +import org.testng.annotations.Test;
   51.54 +
   51.55 +/**
   51.56 + *
   51.57 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   51.58 + */
   51.59 +public class JsClassLoaderBase {
   51.60 +    protected static Class<?> methodClass;
   51.61 +    
   51.62 +    public JsClassLoaderBase() {
   51.63 +    }
   51.64 +    
   51.65 +    @BeforeMethod
   51.66 +    public void assertClassDefined() {
   51.67 +        assertNotNull(methodClass, "BeforeClass set up code should provide methodClass");
   51.68 +    }
   51.69 +
   51.70 +    @Test public void noParamMethod() throws Throwable {
   51.71 +        Method plus = methodClass.getMethod("fortyTwo");
   51.72 +        try {
   51.73 +            final Object val = plus.invoke(null);
   51.74 +            assertTrue(val instanceof Number, "A number returned " + val);
   51.75 +            assertEquals(((Number)val).intValue(), 42);
   51.76 +        } catch (InvocationTargetException ex) {
   51.77 +            throw ex.getTargetException();
   51.78 +        }
   51.79 +    }
   51.80 +    
   51.81 +    @Test public void testExecuteScript() throws Throwable {
   51.82 +        Method plus = methodClass.getMethod("plus", int.class, int.class);
   51.83 +        try {
   51.84 +            assertEquals(plus.invoke(null, 10, 20), 30);
   51.85 +        } catch (InvocationTargetException ex) {
   51.86 +            throw ex.getTargetException();
   51.87 +        }
   51.88 +    }
   51.89 +
   51.90 +    @Test public void overloadedMethod() throws Throwable {
   51.91 +        Method plus = methodClass.getMethod("plus", int.class);
   51.92 +        try {
   51.93 +            assertEquals(plus.invoke(null, 10), 10);
   51.94 +        } catch (InvocationTargetException ex) {
   51.95 +            throw ex.getTargetException();
   51.96 +        }
   51.97 +    }
   51.98 +    
   51.99 +    @Test public void instanceMethod() throws Throwable {
  51.100 +        Method plus = methodClass.getMethod("plusInst", int.class);
  51.101 +        Object inst = methodClass.newInstance();
  51.102 +        try {
  51.103 +            assertEquals(plus.invoke(inst, 10), 10);
  51.104 +        } catch (InvocationTargetException ex) {
  51.105 +            throw ex.getTargetException();
  51.106 +        }
  51.107 +    }
  51.108 +    
  51.109 +    @Test public void staticThis() throws Throwable {
  51.110 +        Method st = methodClass.getMethod("staticThis");
  51.111 +        try {
  51.112 +            assertNull(st.invoke(null));
  51.113 +        } catch (InvocationTargetException ex) {
  51.114 +            throw ex.getTargetException();
  51.115 +        }
  51.116 +    }
  51.117 +
  51.118 +    @Test public void getThis() throws Throwable {
  51.119 +        Object th = methodClass.newInstance();
  51.120 +        Method st = methodClass.getMethod("getThis");
  51.121 +        try {
  51.122 +            assertEquals(st.invoke(th), th);
  51.123 +        } catch (InvocationTargetException ex) {
  51.124 +            throw ex.getTargetException();
  51.125 +        }
  51.126 +    }
  51.127 +    
  51.128 +    @Test public void truth() throws Throwable {
  51.129 +        Method st = methodClass.getMethod("truth");
  51.130 +        assertTrue((st.getModifiers() & Modifier.STATIC) != 0, "Is static");
  51.131 +        assertEquals(st.invoke(null), Boolean.TRUE, "Can return boolean");
  51.132 +    }
  51.133 +    
  51.134 +    @Test public void callback() throws Throwable {
  51.135 +        class R implements Runnable {
  51.136 +            int cnt;
  51.137 +            
  51.138 +            @Override
  51.139 +            public void run() {
  51.140 +                cnt++;
  51.141 +            }
  51.142 +        }
  51.143 +        R r = new R();
  51.144 +        
  51.145 +        Method inc = methodClass.getMethod("callback", Runnable.class);
  51.146 +        inc.invoke(null, r);
  51.147 +        
  51.148 +        assertEquals(r.cnt, 1, "Callback happened");
  51.149 +    }
  51.150 +    
  51.151 +    @Test public void sumArray() throws Throwable {
  51.152 +        Method st = methodClass.getMethod("sumArr", int[].class);
  51.153 +        assertEquals(st.invoke(null, new int[] { 1, 2, 3 }), 6, "1+2+3 is six");
  51.154 +    }
  51.155 +    
  51.156 +    @Test public void javaScriptResource() throws Throwable {
  51.157 +        try {
  51.158 +            Method st = methodClass.getMethod("useExternalMul", int.class, int.class);
  51.159 +            assertEquals(st.invoke(null, 6, 7), 42, "Meaning of JavaScript?");
  51.160 +        } catch (InvocationTargetException ex) {
  51.161 +            throw ex.getTargetException();
  51.162 +        }
  51.163 +    }
  51.164 +    
  51.165 +    @Test public void callJavaScriptMethodOnOwnClass() throws Throwable {
  51.166 +        try {
  51.167 +            Object thiz = methodClass.newInstance();
  51.168 +            Method st = methodClass.getMethod("returnYourSelf", methodClass);
  51.169 +            assertEquals(st.invoke(null, thiz), thiz, "Returns this");
  51.170 +        } catch (InvocationTargetException ex) {
  51.171 +            throw ex.getTargetException();
  51.172 +        }
  51.173 +    }
  51.174 +    
  51.175 +    @Test public void callStaticJavaMethod() throws Throwable {
  51.176 +        Method st = methodClass.getMethod("staticCallback", int.class, int.class);
  51.177 +        assertEquals(st.invoke(null, 6, 7), 42, "Meaning of JavaScript?");
  51.178 +    }
  51.179 +
  51.180 +    @Test public void callStaticStringParamMethod() throws Throwable {
  51.181 +        Method st = methodClass.getMethod("parseInt", String.class);
  51.182 +        assertEquals(st.invoke(null, "42"), 42, "Meaning of JavaScript?");
  51.183 +    }
  51.184 +    
  51.185 +    @Test public void firstLong() throws Throwable {
  51.186 +        Method st = methodClass.getMethod("chooseLong", boolean.class, boolean.class, long.class, long.class);
  51.187 +        assertEquals(st.invoke(null, true, false, 10, 20), 10L, "Take first value");
  51.188 +    }
  51.189 +
  51.190 +    @Test public void secondLong() throws Throwable {
  51.191 +        Method st = methodClass.getMethod("chooseLong", boolean.class, boolean.class, long.class, long.class);
  51.192 +        assertEquals(st.invoke(null, false, true, 10, 20), 20L, "Take 2nd value");
  51.193 +    }
  51.194 +
  51.195 +    @Test public void bothLong() throws Throwable {
  51.196 +        Method st = methodClass.getMethod("chooseLong", boolean.class, boolean.class, long.class, long.class);
  51.197 +        assertEquals(st.invoke(null, true, true, 10, 20), 30L, "Take both values");
  51.198 +    }
  51.199 +    
  51.200 +    @Test public void recordError() throws Throwable {
  51.201 +        Method st = methodClass.getMethod("recordError", Object.class);
  51.202 +        assertEquals(st.invoke(methodClass.newInstance(), "Hello"), "Hello", "The same parameter returned");
  51.203 +    }
  51.204 +}
  51.205 \ No newline at end of file
    52.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.2 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderTest.java	Mon Dec 16 16:59:43 2013 +0100
    52.3 @@ -0,0 +1,155 @@
    52.4 +/**
    52.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    52.6 + *
    52.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    52.8 + *
    52.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   52.10 + * Other names may be trademarks of their respective owners.
   52.11 + *
   52.12 + * The contents of this file are subject to the terms of either the GNU
   52.13 + * General Public License Version 2 only ("GPL") or the Common
   52.14 + * Development and Distribution License("CDDL") (collectively, the
   52.15 + * "License"). You may not use this file except in compliance with the
   52.16 + * License. You can obtain a copy of the License at
   52.17 + * http://www.netbeans.org/cddl-gplv2.html
   52.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   52.19 + * specific language governing permissions and limitations under the
   52.20 + * License.  When distributing the software, include this License Header
   52.21 + * Notice in each file and include the License file at
   52.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   52.23 + * particular file as subject to the "Classpath" exception as provided
   52.24 + * by Oracle in the GPL Version 2 section of the License file that
   52.25 + * accompanied this code. If applicable, add the following below the
   52.26 + * License Header, with the fields enclosed by brackets [] replaced by
   52.27 + * your own identifying information:
   52.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   52.29 + *
   52.30 + * Contributor(s):
   52.31 + *
   52.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   52.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   52.34 + *
   52.35 + * If you wish your version of this file to be governed by only the CDDL
   52.36 + * or only the GPL Version 2, indicate your decision by adding
   52.37 + * "[Contributor] elects to include this software in this distribution
   52.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   52.39 + * single choice of license, a recipient has the option to distribute
   52.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   52.41 + * to extend the choice of license to its licensees as provided above.
   52.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   52.43 + * Version 2 license, then the option applies only if the new code is
   52.44 + * made subject to such option by the copyright holder.
   52.45 + */
   52.46 +package org.netbeans.html.boot.impl;
   52.47 +
   52.48 +import java.io.Closeable;
   52.49 +import java.io.Reader;
   52.50 +import org.apidesign.html.boot.spi.Fn;
   52.51 +import java.net.URL;
   52.52 +import java.net.URLClassLoader;
   52.53 +import java.util.ArrayList;
   52.54 +import java.util.Arrays;
   52.55 +import java.util.Enumeration;
   52.56 +import java.util.List;
   52.57 +import javax.script.Invocable;
   52.58 +import javax.script.ScriptEngine;
   52.59 +import javax.script.ScriptEngineManager;
   52.60 +import javax.script.ScriptException;
   52.61 +import org.testng.annotations.AfterClass;
   52.62 +import org.testng.annotations.BeforeClass;
   52.63 +import org.testng.annotations.BeforeMethod;
   52.64 +
   52.65 +/**
   52.66 + *
   52.67 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   52.68 + */
   52.69 +public class JsClassLoaderTest extends JsClassLoaderBase{
   52.70 +    private static Fn.Presenter loader;
   52.71 +
   52.72 +    @BeforeClass
   52.73 +    public static void setUpClass() throws Exception {
   52.74 +        ScriptEngineManager sem = new ScriptEngineManager();
   52.75 +        final ScriptEngine eng = sem.getEngineByMimeType("text/javascript");
   52.76 +        
   52.77 +        final URL my = JsClassLoaderTest.class.getProtectionDomain().getCodeSource().getLocation();
   52.78 +        ClassLoader parent = JsClassLoaderTest.class.getClassLoader().getParent();
   52.79 +        final URLClassLoader ul = new URLClassLoader(new URL[] { my }, parent);
   52.80 +        class MyCL extends JsClassLoader implements Fn.Presenter {
   52.81 +
   52.82 +            public MyCL(ClassLoader parent) {
   52.83 +                super(parent);
   52.84 +            }
   52.85 +            
   52.86 +            @Override
   52.87 +            protected URL findResource(String name) {
   52.88 +                return ul.getResource(name);
   52.89 +            }
   52.90 +            @Override
   52.91 +            public Fn defineFn(String code, String... names) {
   52.92 +                StringBuilder sb = new StringBuilder();
   52.93 +                sb.append("(function() {");
   52.94 +                sb.append("return function(");
   52.95 +                String sep = "";
   52.96 +                for (String n : names) {
   52.97 +                    sb.append(sep);
   52.98 +                    sb.append(n);
   52.99 +                    sep = ", ";
  52.100 +                }
  52.101 +                sb.append(") {");
  52.102 +                sb.append(code);
  52.103 +                sb.append("};");
  52.104 +                sb.append("})()");
  52.105 +                try {
  52.106 +                    final Object val = eng.eval(sb.toString());
  52.107 +                    return new Fn(this) {
  52.108 +                        @Override
  52.109 +                        public Object invoke(Object thiz, Object... args) throws Exception {
  52.110 +                            List<Object> all = new ArrayList<Object>(args.length + 1);
  52.111 +                            all.add(thiz == null ? val : thiz);
  52.112 +                            all.addAll(Arrays.asList(args));
  52.113 +                            Invocable inv = (Invocable)eng;
  52.114 +                            try {
  52.115 +                                Object ret = inv.invokeMethod(val, "call", all.toArray());
  52.116 +                                return val.equals(ret) ? null : ret;
  52.117 +                            } catch (Exception ex) {
  52.118 +                                throw ex;
  52.119 +                            }
  52.120 +                        }
  52.121 +                    };
  52.122 +                } catch (ScriptException ex) {
  52.123 +                    throw new LinkageError("Can't parse: " + sb, ex);
  52.124 +                }
  52.125 +            }
  52.126 +
  52.127 +            @Override
  52.128 +            protected Enumeration<URL> findResources(String name) {
  52.129 +                throw new UnsupportedOperationException();
  52.130 +            }
  52.131 +
  52.132 +            @Override
  52.133 +            public void loadScript(Reader code) throws ScriptException {
  52.134 +                eng.eval(code);
  52.135 +            }
  52.136 +
  52.137 +            @Override
  52.138 +            public void displayPage(URL page, Runnable onPageLoad) {
  52.139 +                throw new UnsupportedOperationException();
  52.140 +            }
  52.141 +        };
  52.142 +        
  52.143 +        MyCL l = new MyCL(parent);
  52.144 +        Closeable close = FnContext.activate(l);
  52.145 +        methodClass = l.loadClass(JsMethods.class.getName());
  52.146 +        close.close();
  52.147 +        loader = l;
  52.148 +    }
  52.149 +    
  52.150 +    @BeforeMethod public void initPresenter() {
  52.151 +        FnContext.currentPresenter(loader);
  52.152 +    }
  52.153 +
  52.154 +    @AfterClass
  52.155 +    public static void cleanUp() {
  52.156 +        methodClass = null;
  52.157 +    }
  52.158 +}
  52.159 \ No newline at end of file
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/boot/src/test/java/org/netbeans/html/boot/impl/JsMethods.java	Mon Dec 16 16:59:43 2013 +0100
    53.3 @@ -0,0 +1,129 @@
    53.4 +/**
    53.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    53.6 + *
    53.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    53.8 + *
    53.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   53.10 + * Other names may be trademarks of their respective owners.
   53.11 + *
   53.12 + * The contents of this file are subject to the terms of either the GNU
   53.13 + * General Public License Version 2 only ("GPL") or the Common
   53.14 + * Development and Distribution License("CDDL") (collectively, the
   53.15 + * "License"). You may not use this file except in compliance with the
   53.16 + * License. You can obtain a copy of the License at
   53.17 + * http://www.netbeans.org/cddl-gplv2.html
   53.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   53.19 + * specific language governing permissions and limitations under the
   53.20 + * License.  When distributing the software, include this License Header
   53.21 + * Notice in each file and include the License file at
   53.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   53.23 + * particular file as subject to the "Classpath" exception as provided
   53.24 + * by Oracle in the GPL Version 2 section of the License file that
   53.25 + * accompanied this code. If applicable, add the following below the
   53.26 + * License Header, with the fields enclosed by brackets [] replaced by
   53.27 + * your own identifying information:
   53.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   53.29 + *
   53.30 + * Contributor(s):
   53.31 + *
   53.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   53.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   53.34 + *
   53.35 + * If you wish your version of this file to be governed by only the CDDL
   53.36 + * or only the GPL Version 2, indicate your decision by adding
   53.37 + * "[Contributor] elects to include this software in this distribution
   53.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   53.39 + * single choice of license, a recipient has the option to distribute
   53.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   53.41 + * to extend the choice of license to its licensees as provided above.
   53.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   53.43 + * Version 2 license, then the option applies only if the new code is
   53.44 + * made subject to such option by the copyright holder.
   53.45 + */
   53.46 +package org.netbeans.html.boot.impl;
   53.47 +
   53.48 +import net.java.html.js.JavaScriptBody;
   53.49 +import net.java.html.js.JavaScriptResource;
   53.50 +
   53.51 +
   53.52 +/**
   53.53 + *
   53.54 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   53.55 + */
   53.56 +@JavaScriptResource("jsmethods.js")
   53.57 +public class JsMethods {
   53.58 +    private Object value;
   53.59 +    
   53.60 +    @JavaScriptBody(args = {}, body = "return 42;")
   53.61 +    public static Object fortyTwo() {
   53.62 +        return -42;
   53.63 +    }
   53.64 +    
   53.65 +    @JavaScriptBody(args = {"x", "y" }, body = "return x + y;")
   53.66 +    public static native int plus(int x, int y);
   53.67 +    
   53.68 +    @JavaScriptBody(args = {"x"}, body = "return x;")
   53.69 +    public static native int plus(int x);
   53.70 +    
   53.71 +    @JavaScriptBody(args = {}, body = "return this;")
   53.72 +    public static native Object staticThis();
   53.73 +    
   53.74 +    @JavaScriptBody(args = {}, body = "return this;")
   53.75 +    public native Object getThis();
   53.76 +    @JavaScriptBody(args = {"x"}, body = "return x;")
   53.77 +    public native int plusInst(int x);
   53.78 +    
   53.79 +    @JavaScriptBody(args = {}, body = "return true;")
   53.80 +    public static boolean truth() {
   53.81 +        return false;
   53.82 +    }
   53.83 +    
   53.84 +    @JavaScriptBody(args = { "r" }, javacall=true, body = "r.@java.lang.Runnable::run()();")
   53.85 +    public static native void callback(Runnable r);
   53.86 +    
   53.87 +    @JavaScriptBody(args = { "at", "arr" }, javacall = true, body =
   53.88 +          "var a = 0;\n"
   53.89 +        + "for (var i = 0; i < arr.length; i++) {\n"
   53.90 +        + "  a = at.@org.netbeans.html.boot.impl.Arithm::sumTwo(II)(a, arr[i]);\n"
   53.91 +        + "}\n"
   53.92 +        + "return a;"
   53.93 +    )
   53.94 +    private static native int sumArr(Arithm at, int... arr);
   53.95 +    
   53.96 +    public static int sumArr(int... arr) {
   53.97 +        return sumArr(new Arithm(), arr);
   53.98 +    }
   53.99 +    
  53.100 +    @JavaScriptBody(args = { "x", "y" }, body = "return mul(x, y);")
  53.101 +    public static native int useExternalMul(int x, int y);
  53.102 +    
  53.103 +    @JavaScriptBody(args = { "m" }, javacall = true, body = "return m.@org.netbeans.html.boot.impl.JsMethods::getThis()();")
  53.104 +    public static native JsMethods returnYourSelf(JsMethods m);
  53.105 +    
  53.106 +    @JavaScriptBody(args = { "x", "y" }, javacall = true, body = "return @org.netbeans.html.boot.impl.JsMethods::useExternalMul(II)(x, y);")
  53.107 +    public static native int staticCallback(int x, int y);
  53.108 +
  53.109 +    @JavaScriptBody(args = { "v" }, javacall = true, body = "return @java.lang.Integer::parseInt(Ljava/lang/String;)(v);")
  53.110 +    public static native int parseInt(String v);
  53.111 +    
  53.112 +    @JavaScriptBody(args = { "useA", "useB", "a", "b" }, body = "var l = 0;"
  53.113 +        + "if (useA) l += a;\n"
  53.114 +        + "if (useB) l += b;\n"
  53.115 +        + "return l;\n"
  53.116 +    )
  53.117 +    public static native long chooseLong(boolean useA, boolean useB, long a, long b);
  53.118 +    
  53.119 +    protected void onError(Object o) throws Exception {
  53.120 +        value = o;
  53.121 +    }
  53.122 +    
  53.123 +    Object getError() {
  53.124 +        return value;
  53.125 +    }
  53.126 +    
  53.127 +    @JavaScriptBody(args = { "err" }, javacall = true, body = 
  53.128 +        "this.@org.netbeans.html.boot.impl.JsMethods::onError(Ljava/lang/Object;)(err);"
  53.129 +      + "return this.@org.netbeans.html.boot.impl.JsMethods::getError()();"
  53.130 +    )
  53.131 +    public native Object recordError(Object err);
  53.132 +}
    54.1 --- a/boot/src/test/resources/org/apidesign/html/boot/impl/jsmethods.js	Mon Dec 16 15:48:09 2013 +0100
    54.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.3 @@ -1,43 +0,0 @@
    54.4 -/*
    54.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    54.6 - *
    54.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    54.8 - *
    54.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   54.10 - * Other names may be trademarks of their respective owners.
   54.11 - *
   54.12 - * The contents of this file are subject to the terms of either the GNU
   54.13 - * General Public License Version 2 only ("GPL") or the Common
   54.14 - * Development and Distribution License("CDDL") (collectively, the
   54.15 - * "License"). You may not use this file except in compliance with the
   54.16 - * License. You can obtain a copy of the License at
   54.17 - * http://www.netbeans.org/cddl-gplv2.html
   54.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   54.19 - * specific language governing permissions and limitations under the
   54.20 - * License.  When distributing the software, include this License Header
   54.21 - * Notice in each file and include the License file at
   54.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   54.23 - * particular file as subject to the "Classpath" exception as provided
   54.24 - * by Oracle in the GPL Version 2 section of the License file that
   54.25 - * accompanied this code. If applicable, add the following below the
   54.26 - * License Header, with the fields enclosed by brackets [] replaced by
   54.27 - * your own identifying information:
   54.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   54.29 - *
   54.30 - * Contributor(s):
   54.31 - *
   54.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   54.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   54.34 - *
   54.35 - * If you wish your version of this file to be governed by only the CDDL
   54.36 - * or only the GPL Version 2, indicate your decision by adding
   54.37 - * "[Contributor] elects to include this software in this distribution
   54.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   54.39 - * single choice of license, a recipient has the option to distribute
   54.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   54.41 - * to extend the choice of license to its licensees as provided above.
   54.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   54.43 - * Version 2 license, then the option applies only if the new code is
   54.44 - * made subject to such option by the copyright holder.
   54.45 - */
   54.46 -function mul(x, y) { return x * y; }
    55.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.2 +++ b/boot/src/test/resources/org/netbeans/html/boot/impl/jsmethods.js	Mon Dec 16 16:59:43 2013 +0100
    55.3 @@ -0,0 +1,43 @@
    55.4 +/*
    55.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    55.6 + *
    55.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    55.8 + *
    55.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   55.10 + * Other names may be trademarks of their respective owners.
   55.11 + *
   55.12 + * The contents of this file are subject to the terms of either the GNU
   55.13 + * General Public License Version 2 only ("GPL") or the Common
   55.14 + * Development and Distribution License("CDDL") (collectively, the
   55.15 + * "License"). You may not use this file except in compliance with the
   55.16 + * License. You can obtain a copy of the License at
   55.17 + * http://www.netbeans.org/cddl-gplv2.html
   55.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   55.19 + * specific language governing permissions and limitations under the
   55.20 + * License.  When distributing the software, include this License Header
   55.21 + * Notice in each file and include the License file at
   55.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   55.23 + * particular file as subject to the "Classpath" exception as provided
   55.24 + * by Oracle in the GPL Version 2 section of the License file that
   55.25 + * accompanied this code. If applicable, add the following below the
   55.26 + * License Header, with the fields enclosed by brackets [] replaced by
   55.27 + * your own identifying information:
   55.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   55.29 + *
   55.30 + * Contributor(s):
   55.31 + *
   55.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   55.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   55.34 + *
   55.35 + * If you wish your version of this file to be governed by only the CDDL
   55.36 + * or only the GPL Version 2, indicate your decision by adding
   55.37 + * "[Contributor] elects to include this software in this distribution
   55.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   55.39 + * single choice of license, a recipient has the option to distribute
   55.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   55.41 + * to extend the choice of license to its licensees as provided above.
   55.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   55.43 + * Version 2 license, then the option applies only if the new code is
   55.44 + * made subject to such option by the copyright holder.
   55.45 + */
   55.46 +function mul(x, y) { return x * y; }
    56.1 --- a/context/src/main/java/net/java/html/BrwsrCtx.java	Mon Dec 16 15:48:09 2013 +0100
    56.2 +++ b/context/src/main/java/net/java/html/BrwsrCtx.java	Mon Dec 16 16:59:43 2013 +0100
    56.3 @@ -44,8 +44,8 @@
    56.4  
    56.5  import java.util.ServiceLoader;
    56.6  import java.util.logging.Logger;
    56.7 -import org.apidesign.html.context.impl.CtxAccssr;
    56.8 -import org.apidesign.html.context.impl.CtxImpl;
    56.9 +import org.netbeans.html.context.impl.CtxAccssr;
   56.10 +import org.netbeans.html.context.impl.CtxImpl;
   56.11  import org.apidesign.html.context.spi.Contexts;
   56.12  
   56.13  /** Represents context where the <code>net.java.html.json.Model</code>
    57.1 --- a/context/src/main/java/org/apidesign/html/context/impl/CtxAccssr.java	Mon Dec 16 15:48:09 2013 +0100
    57.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    57.3 @@ -1,74 +0,0 @@
    57.4 -/**
    57.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    57.6 - *
    57.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    57.8 - *
    57.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   57.10 - * Other names may be trademarks of their respective owners.
   57.11 - *
   57.12 - * The contents of this file are subject to the terms of either the GNU
   57.13 - * General Public License Version 2 only ("GPL") or the Common
   57.14 - * Development and Distribution License("CDDL") (collectively, the
   57.15 - * "License"). You may not use this file except in compliance with the
   57.16 - * License. You can obtain a copy of the License at
   57.17 - * http://www.netbeans.org/cddl-gplv2.html
   57.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   57.19 - * specific language governing permissions and limitations under the
   57.20 - * License.  When distributing the software, include this License Header
   57.21 - * Notice in each file and include the License file at
   57.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   57.23 - * particular file as subject to the "Classpath" exception as provided
   57.24 - * by Oracle in the GPL Version 2 section of the License file that
   57.25 - * accompanied this code. If applicable, add the following below the
   57.26 - * License Header, with the fields enclosed by brackets [] replaced by
   57.27 - * your own identifying information:
   57.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   57.29 - *
   57.30 - * Contributor(s):
   57.31 - *
   57.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   57.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   57.34 - *
   57.35 - * If you wish your version of this file to be governed by only the CDDL
   57.36 - * or only the GPL Version 2, indicate your decision by adding
   57.37 - * "[Contributor] elects to include this software in this distribution
   57.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   57.39 - * single choice of license, a recipient has the option to distribute
   57.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   57.41 - * to extend the choice of license to its licensees as provided above.
   57.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   57.43 - * Version 2 license, then the option applies only if the new code is
   57.44 - * made subject to such option by the copyright holder.
   57.45 - */
   57.46 -package org.apidesign.html.context.impl;
   57.47 -
   57.48 -import net.java.html.BrwsrCtx;
   57.49 -
   57.50 -/** Internal communication between API (e.g. {@link BrwsrCtx}), SPI
   57.51 - * (e.g. {@link ContextBuilder}) and the implementation package.
   57.52 - *
   57.53 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   57.54 - */
   57.55 -public abstract class CtxAccssr {
   57.56 -    private static CtxAccssr DEFAULT;
   57.57 -    static {
   57.58 -        // run initializers
   57.59 -        try {
   57.60 -            BrwsrCtx.EMPTY.getClass();
   57.61 -        } catch (NullPointerException ex) {
   57.62 -            // ignore
   57.63 -        }
   57.64 -    }
   57.65 -    
   57.66 -    protected CtxAccssr() {
   57.67 -        if (DEFAULT != null) throw new IllegalStateException();
   57.68 -        DEFAULT = this;
   57.69 -    }
   57.70 -    
   57.71 -    protected abstract BrwsrCtx newContext(CtxImpl impl);
   57.72 -    protected abstract CtxImpl find(BrwsrCtx context);
   57.73 -    
   57.74 -    static CtxAccssr getDefault() {
   57.75 -        return DEFAULT;
   57.76 -    }
   57.77 -}
    58.1 --- a/context/src/main/java/org/apidesign/html/context/impl/CtxImpl.java	Mon Dec 16 15:48:09 2013 +0100
    58.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.3 @@ -1,110 +0,0 @@
    58.4 -/**
    58.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    58.6 - *
    58.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    58.8 - *
    58.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   58.10 - * Other names may be trademarks of their respective owners.
   58.11 - *
   58.12 - * The contents of this file are subject to the terms of either the GNU
   58.13 - * General Public License Version 2 only ("GPL") or the Common
   58.14 - * Development and Distribution License("CDDL") (collectively, the
   58.15 - * "License"). You may not use this file except in compliance with the
   58.16 - * License. You can obtain a copy of the License at
   58.17 - * http://www.netbeans.org/cddl-gplv2.html
   58.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   58.19 - * specific language governing permissions and limitations under the
   58.20 - * License.  When distributing the software, include this License Header
   58.21 - * Notice in each file and include the License file at
   58.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   58.23 - * particular file as subject to the "Classpath" exception as provided
   58.24 - * by Oracle in the GPL Version 2 section of the License file that
   58.25 - * accompanied this code. If applicable, add the following below the
   58.26 - * License Header, with the fields enclosed by brackets [] replaced by
   58.27 - * your own identifying information:
   58.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   58.29 - *
   58.30 - * Contributor(s):
   58.31 - *
   58.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   58.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   58.34 - *
   58.35 - * If you wish your version of this file to be governed by only the CDDL
   58.36 - * or only the GPL Version 2, indicate your decision by adding
   58.37 - * "[Contributor] elects to include this software in this distribution
   58.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   58.39 - * single choice of license, a recipient has the option to distribute
   58.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   58.41 - * to extend the choice of license to its licensees as provided above.
   58.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   58.43 - * Version 2 license, then the option applies only if the new code is
   58.44 - * made subject to such option by the copyright holder.
   58.45 - */
   58.46 -package org.apidesign.html.context.impl;
   58.47 -
   58.48 -import java.util.ArrayList;
   58.49 -import java.util.Collections;
   58.50 -import java.util.List;
   58.51 -import net.java.html.BrwsrCtx;
   58.52 -
   58.53 -/** Implementation detail. Holds list of technologies for particular
   58.54 - * {@link BrwsrCtx}.
   58.55 - *
   58.56 - * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   58.57 - */
   58.58 -public final class CtxImpl {
   58.59 -    private final List<Bind<?>> techs;
   58.60 -    
   58.61 -    public CtxImpl() {
   58.62 -        techs = new ArrayList<Bind<?>>();
   58.63 -    }
   58.64 -    
   58.65 -    private CtxImpl(List<Bind<?>> techs) {
   58.66 -        this.techs = techs;
   58.67 -    }
   58.68 -    
   58.69 -    public static <Tech> Tech find(BrwsrCtx context, Class<Tech> technology) {
   58.70 -        CtxImpl impl = CtxAccssr.getDefault().find(context);
   58.71 -        for (Bind<?> bind : impl.techs) {
   58.72 -            if (technology == bind.clazz) {
   58.73 -                return technology.cast(bind.impl);
   58.74 -            }
   58.75 -        }
   58.76 -        return null;
   58.77 -    }
   58.78 -
   58.79 -    public BrwsrCtx build() {
   58.80 -        Collections.sort(techs);
   58.81 -        CtxImpl impl = new CtxImpl(Collections.unmodifiableList(techs));
   58.82 -        return CtxAccssr.getDefault().newContext(impl);
   58.83 -    }
   58.84 -
   58.85 -    public <Tech> void register(Class<Tech> type, Tech impl, int priority) {
   58.86 -        techs.add(new Bind<Tech>(type, impl, priority));
   58.87 -    }
   58.88 -    
   58.89 -    private static final class Bind<Tech> implements Comparable<Bind<?>> {
   58.90 -        private final Class<Tech> clazz;
   58.91 -        private final Tech impl;
   58.92 -        private final int priority;
   58.93 -
   58.94 -        public Bind(Class<Tech> clazz, Tech impl, int priority) {
   58.95 -            this.clazz = clazz;
   58.96 -            this.impl = impl;
   58.97 -            this.priority = priority;
   58.98 -        }
   58.99 -
  58.100 -        @Override
  58.101 -        public int compareTo(Bind<?> o) {
  58.102 -            if (priority != o.priority) {
  58.103 -                return priority - o.priority;
  58.104 -            }
  58.105 -            return clazz.getName().compareTo(o.clazz.getName());
  58.106 -        }
  58.107 -
  58.108 -        @Override
  58.109 -        public String toString() {
  58.110 -            return "Bind{" + "clazz=" + clazz + "@" + clazz.getClassLoader() + ", impl=" + impl + ", priority=" + priority + '}';
  58.111 -        }
  58.112 -    }
  58.113 -}
    59.1 --- a/context/src/main/java/org/apidesign/html/context/spi/Contexts.java	Mon Dec 16 15:48:09 2013 +0100
    59.2 +++ b/context/src/main/java/org/apidesign/html/context/spi/Contexts.java	Mon Dec 16 16:59:43 2013 +0100
    59.3 @@ -43,7 +43,7 @@
    59.4  package org.apidesign.html.context.spi;
    59.5  
    59.6  import net.java.html.BrwsrCtx;
    59.7 -import org.apidesign.html.context.impl.CtxImpl;
    59.8 +import org.netbeans.html.context.impl.CtxImpl;
    59.9  
   59.10  /**
   59.11   *
    60.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.2 +++ b/context/src/main/java/org/netbeans/html/context/impl/CtxAccssr.java	Mon Dec 16 16:59:43 2013 +0100
    60.3 @@ -0,0 +1,74 @@
    60.4 +/**
    60.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    60.6 + *
    60.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    60.8 + *
    60.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   60.10 + * Other names may be trademarks of their respective owners.
   60.11 + *
   60.12 + * The contents of this file are subject to the terms of either the GNU
   60.13 + * General Public License Version 2 only ("GPL") or the Common
   60.14 + * Development and Distribution License("CDDL") (collectively, the
   60.15 + * "License"). You may not use this file except in compliance with the
   60.16 + * License. You can obtain a copy of the License at
   60.17 + * http://www.netbeans.org/cddl-gplv2.html
   60.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   60.19 + * specific language governing permissions and limitations under the
   60.20 + * License.  When distributing the software, include this License Header
   60.21 + * Notice in each file and include the License file at
   60.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   60.23 + * particular file as subject to the "Classpath" exception as provided
   60.24 + * by Oracle in the GPL Version 2 section of the License file that
   60.25 + * accompanied this code. If applicable, add the following below the
   60.26 + * License Header, with the fields enclosed by brackets [] replaced by
   60.27 + * your own identifying information:
   60.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   60.29 + *
   60.30 + * Contributor(s):
   60.31 + *
   60.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   60.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   60.34 + *
   60.35 + * If you wish your version of this file to be governed by only the CDDL
   60.36 + * or only the GPL Version 2, indicate your decision by adding
   60.37 + * "[Contributor] elects to include this software in this distribution
   60.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   60.39 + * single choice of license, a recipient has the option to distribute
   60.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   60.41 + * to extend the choice of license to its licensees as provided above.
   60.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   60.43 + * Version 2 license, then the option applies only if the new code is
   60.44 + * made subject to such option by the copyright holder.
   60.45 + */
   60.46 +package org.netbeans.html.context.impl;
   60.47 +
   60.48 +import net.java.html.BrwsrCtx;
   60.49 +
   60.50 +/** Internal communication between API (e.g. {@link BrwsrCtx}), SPI
   60.51 + * (e.g. {@link ContextBuilder}) and the implementation package.
   60.52 + *
   60.53 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   60.54 + */
   60.55 +public abstract class CtxAccssr {
   60.56 +    private static CtxAccssr DEFAULT;
   60.57 +    static {
   60.58 +        // run initializers
   60.59 +        try {
   60.60 +            BrwsrCtx.EMPTY.getClass();
   60.61 +        } catch (NullPointerException ex) {
   60.62 +            // ignore
   60.63 +        }
   60.64 +    }
   60.65 +    
   60.66 +    protected CtxAccssr() {
   60.67 +        if (DEFAULT != null) throw new IllegalStateException();
   60.68 +        DEFAULT = this;
   60.69 +    }
   60.70 +    
   60.71 +    protected abstract BrwsrCtx newContext(CtxImpl impl);
   60.72 +    protected abstract CtxImpl find(BrwsrCtx context);
   60.73 +    
   60.74 +    static CtxAccssr getDefault() {
   60.75 +        return DEFAULT;
   60.76 +    }
   60.77 +}
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java	Mon Dec 16 16:59:43 2013 +0100
    61.3 @@ -0,0 +1,110 @@
    61.4 +/**
    61.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    61.6 + *
    61.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    61.8 + *
    61.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   61.10 + * Other names may be trademarks of their respective owners.
   61.11 + *
   61.12 + * The contents of this file are subject to the terms of either the GNU
   61.13 + * General Public License Version 2 only ("GPL") or the Common
   61.14 + * Development and Distribution License("CDDL") (collectively, the
   61.15 + * "License"). You may not use this file except in compliance with the
   61.16 + * License. You can obtain a copy of the License at
   61.17 + * http://www.netbeans.org/cddl-gplv2.html
   61.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   61.19 + * specific language governing permissions and limitations under the
   61.20 + * License.  When distributing the software, include this License Header
   61.21 + * Notice in each file and include the License file at
   61.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   61.23 + * particular file as subject to the "Classpath" exception as provided
   61.24 + * by Oracle in the GPL Version 2 section of the License file that
   61.25 + * accompanied this code. If applicable, add the following below the
   61.26 + * License Header, with the fields enclosed by brackets [] replaced by
   61.27 + * your own identifying information:
   61.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   61.29 + *
   61.30 + * Contributor(s):
   61.31 + *
   61.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   61.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   61.34 + *
   61.35 + * If you wish your version of this file to be governed by only the CDDL
   61.36 + * or only the GPL Version 2, indicate your decision by adding
   61.37 + * "[Contributor] elects to include this software in this distribution
   61.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   61.39 + * single choice of license, a recipient has the option to distribute
   61.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   61.41 + * to extend the choice of license to its licensees as provided above.
   61.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   61.43 + * Version 2 license, then the option applies only if the new code is
   61.44 + * made subject to such option by the copyright holder.
   61.45 + */
   61.46 +package org.netbeans.html.context.impl;
   61.47 +
   61.48 +import java.util.ArrayList;
   61.49 +import java.util.Collections;
   61.50 +import java.util.List;
   61.51 +import net.java.html.BrwsrCtx;
   61.52 +
   61.53 +/** Implementation detail. Holds list of technologies for particular
   61.54 + * {@link BrwsrCtx}.
   61.55 + *
   61.56 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
   61.57 + */
   61.58 +public final class CtxImpl {
   61.59 +    private final List<Bind<?>> techs;
   61.60 +    
   61.61 +    public CtxImpl() {
   61.62 +        techs = new ArrayList<Bind<?>>();
   61.63 +    }
   61.64 +    
   61.65 +    private CtxImpl(List<Bind<?>> techs) {
   61.66 +        this.techs = techs;
   61.67 +    }
   61.68 +    
   61.69 +    public static <Tech> Tech find(BrwsrCtx context, Class<Tech> technology) {
   61.70 +        CtxImpl impl = CtxAccssr.getDefault().find(context);
   61.71 +        for (Bind<?> bind : impl.techs) {
   61.72 +            if (technology == bind.clazz) {
   61.73 +                return technology.cast(bind.impl);
   61.74 +            }
   61.75 +        }
   61.76 +        return null;
   61.77 +    }
   61.78 +
   61.79 +    public BrwsrCtx build() {
   61.80 +        Collections.sort(techs);
   61.81 +        CtxImpl impl = new CtxImpl(Collections.unmodifiableList(techs));
   61.82 +        return CtxAccssr.getDefault().newContext(impl);
   61.83 +    }
   61.84 +
   61.85 +    public <Tech> void register(Class<Tech> type, Tech impl, int priority) {
   61.86 +        techs.add(new Bind<Tech>(type, impl, priority));
   61.87 +    }
   61.88 +    
   61.89 +    private static final class Bind<Tech> implements Comparable<Bind<?>> {
   61.90 +        private final Class<Tech> clazz;
   61.91 +        private final Tech impl;
   61.92 +        private final int priority;
   61.93 +
   61.94 +        public Bind(Class<Tech> clazz, Tech impl, int priority) {
   61.95 +            this.clazz = clazz;
   61.96 +            this.impl = impl;
   61.97 +            this.priority = priority;
   61.98 +        }
   61.99 +
  61.100 +        @Override
  61.101 +        public int compareTo(Bind<?> o) {
  61.102 +            if (priority != o.priority) {
  61.103 +                return priority - o.priority;
  61.104 +            }
  61.105 +            return clazz.getName().compareTo(o.clazz.getName());
  61.106 +        }
  61.107 +
  61.108 +        @Override
  61.109 +        public String toString() {
  61.110 +            return "Bind{" + "clazz=" + clazz + "@" + clazz.getClassLoader() + ", impl=" + impl + ", priority=" + priority + '}';
  61.111 +        }
  61.112 +    }
  61.113 +}
    62.1 --- a/geo/src/main/java/net/java/html/geo/Position.java	Mon Dec 16 15:48:09 2013 +0100
    62.2 +++ b/geo/src/main/java/net/java/html/geo/Position.java	Mon Dec 16 16:59:43 2013 +0100
    62.3 @@ -44,7 +44,7 @@
    62.4  
    62.5  import java.util.logging.Level;
    62.6  import java.util.logging.Logger;
    62.7 -import org.apidesign.html.geo.impl.JsG;
    62.8 +import org.netbeans.html.geo.impl.JsG;
    62.9  
   62.10  /** Class that represents a geolocation position provided as a callback
   62.11   * to {@link Handle#onLocation(net.java.html.geo.Position)} method. The
    63.1 --- a/geo/src/main/java/org/apidesign/html/geo/impl/GeoProcessor.java	Mon Dec 16 15:48:09 2013 +0100
    63.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    63.3 @@ -1,289 +0,0 @@
    63.4 -/**
    63.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    63.6 - *
    63.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    63.8 - *
    63.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   63.10 - * Other names may be trademarks of their respective owners.
   63.11 - *
   63.12 - * The contents of this file are subject to the terms of either the GNU
   63.13 - * General Public License Version 2 only ("GPL") or the Common
   63.14 - * Development and Distribution License("CDDL") (collectively, the
   63.15 - * "License"). You may not use this file except in compliance with the
   63.16 - * License. You can obtain a copy of the License at
   63.17 - * http://www.netbeans.org/cddl-gplv2.html
   63.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   63.19 - * specific language governing permissions and limitations under the
   63.20 - * License.  When distributing the software, include this License Header
   63.21 - * Notice in each file and include the License file at
   63.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   63.23 - * particular file as subject to the "Classpath" exception as provided
   63.24 - * by Oracle in the GPL Version 2 section of the License file that
   63.25 - * accompanied this code. If applicable, add the following below the
   63.26 - * License Header, with the fields enclosed by brackets [] replaced by
   63.27 - * your own identifying information:
   63.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   63.29 - *
   63.30 - * Contributor(s):
   63.31 - *
   63.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   63.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   63.34 - *
   63.35 - * If you wish your version of this file to be governed by only the CDDL
   63.36 - * or only the GPL Version 2, indicate your decision by adding
   63.37 - * "[Contributor] elects to include this software in this distribution
   63.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   63.39 - * single choice of license, a recipient has the option to distribute
   63.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   63.41 - * to extend the choice of license to its licensees as provided above.
   63.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   63.43 - * Version 2 license, then the option applies only if the new code is
   63.44 - * made subject to such option by the copyright holder.
   63.45 - */
   63.46 -package org.apidesign.html.geo.impl;
   63.47 -
   63.48 -import java.io.IOException;
   63.49 -import java.io.Writer;
   63.50 -import java.util.List;
   63.51 -import java.util.Locale;
   63.52 -import java.util.Set;
   63.53 -import java.util.logging.Level;
   63.54 -import java.util.logging.Logger;
   63.55 -import javax.annotation.processing.AbstractProcessor;
   63.56 -import javax.annotation.processing.Processor;
   63.57 -import javax.annotation.processing.RoundEnvironment;
   63.58 -import javax.annotation.processing.SupportedAnnotationTypes;
   63.59 -import javax.annotation.processing.SupportedSourceVersion;
   63.60 -import javax.lang.model.SourceVersion;
   63.61 -import javax.lang.model.element.Element;
   63.62 -import javax.lang.model.element.ElementKind;
   63.63 -import javax.lang.model.element.ExecutableElement;
   63.64 -import javax.lang.model.element.Modifier;
   63.65 -import javax.lang.model.element.PackageElement;
   63.66 -import javax.lang.model.element.TypeElement;
   63.67 -import javax.lang.model.element.VariableElement;
   63.68 -import javax.lang.model.type.TypeMirror;
   63.69 -import javax.tools.Diagnostic;
   63.70 -import javax.tools.JavaFileObject;
   63.71 -import net.java.html.geo.OnLocation;
   63.72 -import net.java.html.geo.Position;
   63.73 -import org.openide.util.lookup.ServiceProvider;
   63.74 -
   63.75 -/** Annotation processor to generate callbacks from {@link GeoHandle} class.
   63.76 - *
   63.77 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   63.78 - */
   63.79 -@ServiceProvider(service=Processor.class)
   63.80 -@SupportedSourceVersion(SourceVersion.RELEASE_6)
   63.81 -@SupportedAnnotationTypes({
   63.82 -    "net.java.html.geo.OnLocation"
   63.83 -})
   63.84 -public final class GeoProcessor extends AbstractProcessor {
   63.85 -    private static final Logger LOG = Logger.getLogger(GeoProcessor.class.getName());
   63.86 -    @Override
   63.87 -    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
   63.88 -        boolean ok = true;
   63.89 -        for (Element e : roundEnv.getElementsAnnotatedWith(OnLocation.class)) {
   63.90 -            if (!processLocation(e)) {
   63.91 -                ok = false;
   63.92 -            }
   63.93 -        }
   63.94 -        return ok;
   63.95 -    }
   63.96 -
   63.97 -    private void error(String msg, Element e) {
   63.98 -        processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e);
   63.99 -    }
  63.100 -    
  63.101 -    private boolean processLocation(Element e) {
  63.102 -        if (e.getKind() != ElementKind.METHOD) {
  63.103 -            return false;
  63.104 -        }
  63.105 -        ExecutableElement me = (ExecutableElement) e;
  63.106 -        OnLocation ol = e.getAnnotation(OnLocation.class);
  63.107 -        if (ol == null) {
  63.108 -            return true;
  63.109 -        }
  63.110 -        if (me.getModifiers().contains(Modifier.PRIVATE)) {
  63.111 -            error("Method annotated by @OnLocation cannot be private", e);
  63.112 -            return false;
  63.113 -        }
  63.114 -        TypeMirror positionClass = processingEnv.getElementUtils().getTypeElement(Position.class.getName()).asType();
  63.115 -        final List<? extends VariableElement> params = me.getParameters();
  63.116 -        if (params.size() < 1 || !params.get(0).asType().equals(positionClass)) {
  63.117 -            error("Method annotated by @OnLocation first argument must be net.java.html.geo.Position!", e);
  63.118 -            return false;
  63.119 -        }
  63.120 -        String className = ol.className();
  63.121 -        if (className.isEmpty()) {
  63.122 -            String n = e.getSimpleName().toString();
  63.123 -            if (n.isEmpty()) {
  63.124 -                error("Empty method name", e);
  63.125 -                return false;
  63.126 -            }
  63.127 -            final String firstLetter = n.substring(0, 1).toUpperCase(Locale.ENGLISH);
  63.128 -            className = firstLetter + n.substring(1) + "Handle";
  63.129 -        }
  63.130 -        TypeElement te = (TypeElement)e.getEnclosingElement();
  63.131 -        PackageElement pe = (PackageElement) te.getEnclosingElement();
  63.132 -        final String pkg = pe.getQualifiedName().toString();
  63.133 -        final String fqn = pkg + "." + className;
  63.134 -        final boolean isStatic = me.getModifiers().contains(Modifier.STATIC);
  63.135 -        String sep;
  63.136 -        try {
  63.137 -            JavaFileObject fo = processingEnv.getFiler().createSourceFile(fqn, e);
  63.138 -            Writer w = fo.openWriter();
  63.139 -            w.append("package ").append(pkg).append(";\n");
  63.140 -            w.append("class ").append(className).append(" extends net.java.html.geo.Position.Handle {\n");
  63.141 -            if (!isStatic) {
  63.142 -                w.append("  private final ").append(te.getSimpleName()).append(" $i;\n");
  63.143 -            }
  63.144 -            for (int i = 1; i < params.size(); i++) {
  63.145 -                final VariableElement p = params.get(i);
  63.146 -                w.append("  private final ").append(p.asType().toString()).append(" ").append(p.getSimpleName()).append(";\n");
  63.147 -            }
  63.148 -            w.append("  private ").append(className).append("(boolean oneTime");
  63.149 -            w.append(", ").append(te.getSimpleName()).append(" i");
  63.150 -            for (int i = 1; i < params.size(); i++) {
  63.151 -                final VariableElement p = params.get(i);
  63.152 -                w.append(", ").append(p.asType().toString()).append(" ").append(p.getSimpleName());
  63.153 -            }
  63.154 -            w.append(") {\n    super(oneTime);\n");
  63.155 -            if (!isStatic) {
  63.156 -                w.append("    this.$i = i;\n");
  63.157 -            }
  63.158 -            for (int i = 1; i < params.size(); i++) {
  63.159 -                final VariableElement p = params.get(i);
  63.160 -                w.append("  this.").append(p.getSimpleName()).append(" = ").append(p.getSimpleName()).append(";\n");
  63.161 -            }
  63.162 -            w.append("}\n");
  63.163 -            w.append("  static net.java.html.geo.Position.Handle createQuery(");
  63.164 -            String inst;
  63.165 -            if (!isStatic) {
  63.166 -                w.append(te.getSimpleName()).append(" instance");
  63.167 -                inst = "instance";
  63.168 -                sep = ", ";
  63.169 -            } else {
  63.170 -                inst = "null";
  63.171 -                sep = "";
  63.172 -            }
  63.173 -            for (int i = 1; i < params.size(); i++) {
  63.174 -                final VariableElement p = params.get(i);
  63.175 -                w.append(sep).append(p.asType().toString()).append(" ").append(p.getSimpleName());
  63.176 -                sep = ", ";
  63.177 -            }
  63.178 -            w.append(") { return new ").append(className).append("(true, ").append(inst);
  63.179 -            for (int i = 1; i < params.size(); i++) {
  63.180 -                final VariableElement p = params.get(i);
  63.181 -                w.append(", ").append(p.getSimpleName());
  63.182 -            }
  63.183 -            w.append("); }\n");
  63.184 -            w.append("  static net.java.html.geo.Position.Handle createWatch(");
  63.185 -            if (!isStatic) {
  63.186 -                w.append(te.getSimpleName()).append(" instance");
  63.187 -                sep = ", ";
  63.188 -            } else {
  63.189 -                sep = "";
  63.190 -            }
  63.191 -            for (int i = 1; i < params.size(); i++) {
  63.192 -                final VariableElement p = params.get(i);
  63.193 -                w.append(sep).append(p.asType().toString()).append(" ").append(p.getSimpleName());
  63.194 -            }
  63.195 -            w.append(") { return new ").append(className).append("(false, ").append(inst);
  63.196 -            for (int i = 1; i < params.size(); i++) {
  63.197 -                final VariableElement p = params.get(i);
  63.198 -                w.append(", ").append(p.getSimpleName());
  63.199 -            }
  63.200 -            w.append("); }\n");
  63.201 -            w.append("  @Override protected void onError(Exception t) throws Throwable {\n");
  63.202 -            if (ol.onError().isEmpty()) {
  63.203 -                w.append("    t.printStackTrace();");
  63.204 -            } else {
  63.205 -                if (!findOnError(me, te, ol.onError(), isStatic)) {
  63.206 -                    return false;
  63.207 -                }
  63.208 -                if (isStatic) {
  63.209 -                    w.append("    ").append(te.getSimpleName()).append(".");
  63.210 -                } else {
  63.211 -                    w.append("    $i.");
  63.212 -                }
  63.213 -                w.append(ol.onError()).append("(t");
  63.214 -                for (int i = 1; i < params.size(); i++) {
  63.215 -                    final VariableElement p = params.get(i);
  63.216 -                    w.append(", ").append(p.getSimpleName());
  63.217 -                }
  63.218 -                w.append(");\n");
  63.219 -            }
  63.220 -            w.append("  }\n");
  63.221 -            w.append("  @Override protected void onLocation(net.java.html.geo.Position p) throws Throwable {\n");
  63.222 -            if (isStatic) {
  63.223 -                w.append("    ").append(te.getSimpleName()).append(".");
  63.224 -            } else {
  63.225 -                w.append("    $i.");
  63.226 -            }
  63.227 -            w.append(me.getSimpleName()).append("(p");
  63.228 -            for (int i = 1; i < params.size(); i++) {
  63.229 -                final VariableElement p = params.get(i);
  63.230 -                w.append(", ").append(p.getSimpleName());
  63.231 -            }
  63.232 -            w.append(");\n");
  63.233 -            w.append("  }\n");
  63.234 -            w.append("}\n");
  63.235 -            w.close();
  63.236 -        } catch (IOException ex) {
  63.237 -            Logger.getLogger(GeoProcessor.class.getName()).log(Level.SEVERE, null, ex);
  63.238 -            error("Can't write handler class: " + ex.getMessage(), e);
  63.239 -            return false;
  63.240 -        }
  63.241 -        
  63.242 -        return true;
  63.243 -    }
  63.244 -
  63.245 -    private boolean findOnError(ExecutableElement errElem, TypeElement te, String name, boolean onlyStatic) {
  63.246 -        String err = null;
  63.247 -        METHODS: for (Element e : te.getEnclosedElements()) {
  63.248 -            if (e.getKind() != ElementKind.METHOD) {
  63.249 -                continue;
  63.250 -            }
  63.251 -            if (!e.getSimpleName().contentEquals(name)) {
  63.252 -                continue;
  63.253 -            }
  63.254 -            if (onlyStatic && !e.getModifiers().contains(Modifier.STATIC)) {
  63.255 -                errElem = (ExecutableElement) e;
  63.256 -                err = "Would have to be static";
  63.257 -                continue;
  63.258 -            }
  63.259 -            ExecutableElement ee = (ExecutableElement) e;
  63.260 -            TypeMirror excType = processingEnv.getElementUtils().getTypeElement(Exception.class.getName()).asType();
  63.261 -            final List<? extends VariableElement> params = ee.getParameters(); 
  63.262 -            if (params.size() < 1 || 
  63.263 -                !processingEnv.getTypeUtils().isAssignable(excType, ee.getParameters().get(0).asType())
  63.264 -            ) {
  63.265 -                errElem = (ExecutableElement) e;
  63.266 -                err = "Error method first argument needs to be Exception";
  63.267 -                continue;
  63.268 -            }
  63.269 -            final List<? extends Element> origParams = errElem.getParameters();
  63.270 -            if (params.size() != origParams.size()) {
  63.271 -                errElem = (ExecutableElement) e;
  63.272 -                err = "Error method must have the same parameters as @OnLocation one";
  63.273 -                continue;
  63.274 -            }
  63.275 -            for (int i = 1; i < origParams.size(); i++) {
  63.276 -                final TypeMirror t1 = params.get(i).asType();
  63.277 -                final TypeMirror t2 = origParams.get(i).asType();
  63.278 -                if (!processingEnv.getTypeUtils().isSameType(t1, t2)) {
  63.279 -                    errElem = (ExecutableElement) e;
  63.280 -                    err = "Error method must have the same parameters as @OnLocation one";
  63.281 -                    continue METHODS;
  63.282 -                }
  63.283 -            }
  63.284 -            return true;
  63.285 -        }
  63.286 -        if (err == null) {
  63.287 -            err = "Cannot find " + name + "(Exception) method in this class";
  63.288 -        }
  63.289 -        error(err, errElem);
  63.290 -        return false;
  63.291 -    }
  63.292 -}
    64.1 --- a/geo/src/main/java/org/apidesign/html/geo/impl/JsG.java	Mon Dec 16 15:48:09 2013 +0100
    64.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    64.3 @@ -1,107 +0,0 @@
    64.4 -/**
    64.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    64.6 - *
    64.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    64.8 - *
    64.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   64.10 - * Other names may be trademarks of their respective owners.
   64.11 - *
   64.12 - * The contents of this file are subject to the terms of either the GNU
   64.13 - * General Public License Version 2 only ("GPL") or the Common
   64.14 - * Development and Distribution License("CDDL") (collectively, the
   64.15 - * "License"). You may not use this file except in compliance with the
   64.16 - * License. You can obtain a copy of the License at
   64.17 - * http://www.netbeans.org/cddl-gplv2.html
   64.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   64.19 - * specific language governing permissions and limitations under the
   64.20 - * License.  When distributing the software, include this License Header
   64.21 - * Notice in each file and include the License file at
   64.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   64.23 - * particular file as subject to the "Classpath" exception as provided
   64.24 - * by Oracle in the GPL Version 2 section of the License file that
   64.25 - * accompanied this code. If applicable, add the following below the
   64.26 - * License Header, with the fields enclosed by brackets [] replaced by
   64.27 - * your own identifying information:
   64.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   64.29 - *
   64.30 - * Contributor(s):
   64.31 - *
   64.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   64.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   64.34 - *
   64.35 - * If you wish your version of this file to be governed by only the CDDL
   64.36 - * or only the GPL Version 2, indicate your decision by adding
   64.37 - * "[Contributor] elects to include this software in this distribution
   64.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   64.39 - * single choice of license, a recipient has the option to distribute
   64.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   64.41 - * to extend the choice of license to its licensees as provided above.
   64.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   64.43 - * Version 2 license, then the option applies only if the new code is
   64.44 - * made subject to such option by the copyright holder.
   64.45 - */
   64.46 -package org.apidesign.html.geo.impl;
   64.47 -
   64.48 -import net.java.html.js.JavaScriptBody;
   64.49 -
   64.50 -/** Implementation class to deal with browser's <code>navigator.geolocation</code> 
   64.51 - * object.
   64.52 - *
   64.53 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   64.54 - */
   64.55 -public abstract class JsG {
   64.56 -    protected JsG() {
   64.57 -        if (!getClass().getName().equals("net.java.html.geo.Position$Handle$JsH")) {
   64.58 -            throw new IllegalStateException();
   64.59 -        }
   64.60 -    }
   64.61 -    
   64.62 -    public abstract void onLocation(Object position);
   64.63 -    public abstract void onError(Object error);
   64.64 -    
   64.65 -    @JavaScriptBody(args = {}, body = "return !!navigator.geolocation;")
   64.66 -    public static boolean hasGeolocation() {
   64.67 -        return false;
   64.68 -    }
   64.69 -
   64.70 -    @JavaScriptBody(
   64.71 -        args = { "onlyOnce", "enableHighAccuracy", "timeout", "maximumAge" }, 
   64.72 -        javacall = true, 
   64.73 -        body = 
   64.74 -        "var self = this;\n" +
   64.75 -        "var ok = function (position) {\n" +
   64.76 -        "  self.@org.apidesign.html.geo.impl.JsG::onLocation(Ljava/lang/Object;)(position);\n" +
   64.77 -        "};\n" +
   64.78 -        "var fail = function (error) {\n" +
   64.79 -        "  self.@org.apidesign.html.geo.impl.JsG::onError(Ljava/lang/Object;)(error);\n" +
   64.80 -        "};\n" +
   64.81 -        "var options = {};\n" +
   64.82 -        "options.enableHighAccuracy = enableHighAccuracy;\n" +
   64.83 -        "if (timeout >= 0) options.timeout = timeout;\n" +
   64.84 -        "if (maximumAge >= 0) options.maximumAge = maximumAge;\n" +
   64.85 -        "if (onlyOnce) {\n" +
   64.86 -        "  navigator.geolocation.getCurrentPosition(ok, fail);\n" +
   64.87 -        "  return 0;\n" +
   64.88 -        "} else {\n" +
   64.89 -        "  return navigator.geolocation.watchPosition(ok, fail);\n" +
   64.90 -        "}\n"
   64.91 -    )
   64.92 -    protected long start(
   64.93 -        boolean onlyOnce, 
   64.94 -        boolean enableHighAccuracy,
   64.95 -        long timeout,
   64.96 -        long maximumAge
   64.97 -    ) {
   64.98 -        return -1;
   64.99 -    }
  64.100 -    
  64.101 -    @JavaScriptBody(args = { "watch" }, body = "navigator.geolocation.clearWatch(watch);")
  64.102 -    protected void stop(long watch) {
  64.103 -    }
  64.104 -
  64.105 -    @JavaScriptBody(args = { "self", "property" }, body = "return self[property];")
  64.106 -    public static Object get(Object self, String property) {
  64.107 -        return null;
  64.108 -    }
  64.109 -
  64.110 -}
    65.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    65.2 +++ b/geo/src/main/java/org/netbeans/html/geo/impl/GeoProcessor.java	Mon Dec 16 16:59:43 2013 +0100
    65.3 @@ -0,0 +1,289 @@
    65.4 +/**
    65.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    65.6 + *
    65.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    65.8 + *
    65.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   65.10 + * Other names may be trademarks of their respective owners.
   65.11 + *
   65.12 + * The contents of this file are subject to the terms of either the GNU
   65.13 + * General Public License Version 2 only ("GPL") or the Common
   65.14 + * Development and Distribution License("CDDL") (collectively, the
   65.15 + * "License"). You may not use this file except in compliance with the
   65.16 + * License. You can obtain a copy of the License at
   65.17 + * http://www.netbeans.org/cddl-gplv2.html
   65.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   65.19 + * specific language governing permissions and limitations under the
   65.20 + * License.  When distributing the software, include this License Header
   65.21 + * Notice in each file and include the License file at
   65.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   65.23 + * particular file as subject to the "Classpath" exception as provided
   65.24 + * by Oracle in the GPL Version 2 section of the License file that
   65.25 + * accompanied this code. If applicable, add the following below the
   65.26 + * License Header, with the fields enclosed by brackets [] replaced by
   65.27 + * your own identifying information:
   65.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   65.29 + *
   65.30 + * Contributor(s):
   65.31 + *
   65.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   65.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   65.34 + *
   65.35 + * If you wish your version of this file to be governed by only the CDDL
   65.36 + * or only the GPL Version 2, indicate your decision by adding
   65.37 + * "[Contributor] elects to include this software in this distribution
   65.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   65.39 + * single choice of license, a recipient has the option to distribute
   65.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   65.41 + * to extend the choice of license to its licensees as provided above.
   65.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   65.43 + * Version 2 license, then the option applies only if the new code is
   65.44 + * made subject to such option by the copyright holder.
   65.45 + */
   65.46 +package org.netbeans.html.geo.impl;
   65.47 +
   65.48 +import java.io.IOException;
   65.49 +import java.io.Writer;
   65.50 +import java.util.List;
   65.51 +import java.util.Locale;
   65.52 +import java.util.Set;
   65.53 +import java.util.logging.Level;
   65.54 +import java.util.logging.Logger;
   65.55 +import javax.annotation.processing.AbstractProcessor;
   65.56 +import javax.annotation.processing.Processor;
   65.57 +import javax.annotation.processing.RoundEnvironment;
   65.58 +import javax.annotation.processing.SupportedAnnotationTypes;
   65.59 +import javax.annotation.processing.SupportedSourceVersion;
   65.60 +import javax.lang.model.SourceVersion;
   65.61 +import javax.lang.model.element.Element;
   65.62 +import javax.lang.model.element.ElementKind;
   65.63 +import javax.lang.model.element.ExecutableElement;
   65.64 +import javax.lang.model.element.Modifier;
   65.65 +import javax.lang.model.element.PackageElement;
   65.66 +import javax.lang.model.element.TypeElement;
   65.67 +import javax.lang.model.element.VariableElement;
   65.68 +import javax.lang.model.type.TypeMirror;
   65.69 +import javax.tools.Diagnostic;
   65.70 +import javax.tools.JavaFileObject;
   65.71 +import net.java.html.geo.OnLocation;
   65.72 +import net.java.html.geo.Position;
   65.73 +import org.openide.util.lookup.ServiceProvider;
   65.74 +
   65.75 +/** Annotation processor to generate callbacks from {@link GeoHandle} class.
   65.76 + *
   65.77 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   65.78 + */
   65.79 +@ServiceProvider(service=Processor.class)
   65.80 +@SupportedSourceVersion(SourceVersion.RELEASE_6)
   65.81 +@SupportedAnnotationTypes({
   65.82 +    "net.java.html.geo.OnLocation"
   65.83 +})
   65.84 +public final class GeoProcessor extends AbstractProcessor {
   65.85 +    private static final Logger LOG = Logger.getLogger(GeoProcessor.class.getName());
   65.86 +    @Override
   65.87 +    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
   65.88 +        boolean ok = true;
   65.89 +        for (Element e : roundEnv.getElementsAnnotatedWith(OnLocation.class)) {
   65.90 +            if (!processLocation(e)) {
   65.91 +                ok = false;
   65.92 +            }
   65.93 +        }
   65.94 +        return ok;
   65.95 +    }
   65.96 +
   65.97 +    private void error(String msg, Element e) {
   65.98 +        processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e);
   65.99 +    }
  65.100 +    
  65.101 +    private boolean processLocation(Element e) {
  65.102 +        if (e.getKind() != ElementKind.METHOD) {
  65.103 +            return false;
  65.104 +        }
  65.105 +        ExecutableElement me = (ExecutableElement) e;
  65.106 +        OnLocation ol = e.getAnnotation(OnLocation.class);
  65.107 +        if (ol == null) {
  65.108 +            return true;
  65.109 +        }
  65.110 +        if (me.getModifiers().contains(Modifier.PRIVATE)) {
  65.111 +            error("Method annotated by @OnLocation cannot be private", e);
  65.112 +            return false;
  65.113 +        }
  65.114 +        TypeMirror positionClass = processingEnv.getElementUtils().getTypeElement(Position.class.getName()).asType();
  65.115 +        final List<? extends VariableElement> params = me.getParameters();
  65.116 +        if (params.size() < 1 || !params.get(0).asType().equals(positionClass)) {
  65.117 +            error("Method annotated by @OnLocation first argument must be net.java.html.geo.Position!", e);
  65.118 +            return false;
  65.119 +        }
  65.120 +        String className = ol.className();
  65.121 +        if (className.isEmpty()) {
  65.122 +            String n = e.getSimpleName().toString();
  65.123 +            if (n.isEmpty()) {
  65.124 +                error("Empty method name", e);
  65.125 +                return false;
  65.126 +            }
  65.127 +            final String firstLetter = n.substring(0, 1).toUpperCase(Locale.ENGLISH);
  65.128 +            className = firstLetter + n.substring(1) + "Handle";
  65.129 +        }
  65.130 +        TypeElement te = (TypeElement)e.getEnclosingElement();
  65.131 +        PackageElement pe = (PackageElement) te.getEnclosingElement();
  65.132 +        final String pkg = pe.getQualifiedName().toString();
  65.133 +        final String fqn = pkg + "." + className;
  65.134 +        final boolean isStatic = me.getModifiers().contains(Modifier.STATIC);
  65.135 +        String sep;
  65.136 +        try {
  65.137 +            JavaFileObject fo = processingEnv.getFiler().createSourceFile(fqn, e);
  65.138 +            Writer w = fo.openWriter();
  65.139 +            w.append("package ").append(pkg).append(";\n");
  65.140 +            w.append("class ").append(className).append(" extends net.java.html.geo.Position.Handle {\n");
  65.141 +            if (!isStatic) {
  65.142 +                w.append("  private final ").append(te.getSimpleName()).append(" $i;\n");
  65.143 +            }
  65.144 +            for (int i = 1; i < params.size(); i++) {
  65.145 +                final VariableElement p = params.get(i);
  65.146 +                w.append("  private final ").append(p.asType().toString()).append(" ").append(p.getSimpleName()).append(";\n");
  65.147 +            }
  65.148 +            w.append("  private ").append(className).append("(boolean oneTime");
  65.149 +            w.append(", ").append(te.getSimpleName()).append(" i");
  65.150 +            for (int i = 1; i < params.size(); i++) {
  65.151 +                final VariableElement p = params.get(i);
  65.152 +                w.append(", ").append(p.asType().toString()).append(" ").append(p.getSimpleName());
  65.153 +            }
  65.154 +            w.append(") {\n    super(oneTime);\n");
  65.155 +            if (!isStatic) {
  65.156 +                w.append("    this.$i = i;\n");
  65.157 +            }
  65.158 +            for (int i = 1; i < params.size(); i++) {
  65.159 +                final VariableElement p = params.get(i);
  65.160 +                w.append("  this.").append(p.getSimpleName()).append(" = ").append(p.getSimpleName()).append(";\n");
  65.161 +            }
  65.162 +            w.append("}\n");
  65.163 +            w.append("  static net.java.html.geo.Position.Handle createQuery(");
  65.164 +            String inst;
  65.165 +            if (!isStatic) {
  65.166 +                w.append(te.getSimpleName()).append(" instance");
  65.167 +                inst = "instance";
  65.168 +                sep = ", ";
  65.169 +            } else {
  65.170 +                inst = "null";
  65.171 +                sep = "";
  65.172 +            }
  65.173 +            for (int i = 1; i < params.size(); i++) {
  65.174 +                final VariableElement p = params.get(i);
  65.175 +                w.append(sep).append(p.asType().toString()).append(" ").append(p.getSimpleName());
  65.176 +                sep = ", ";
  65.177 +            }
  65.178 +            w.append(") { return new ").append(className).append("(true, ").append(inst);
  65.179 +            for (int i = 1; i < params.size(); i++) {
  65.180 +                final VariableElement p = params.get(i);
  65.181 +                w.append(", ").append(p.getSimpleName());
  65.182 +            }
  65.183 +            w.append("); }\n");
  65.184 +            w.append("  static net.java.html.geo.Position.Handle createWatch(");
  65.185 +            if (!isStatic) {
  65.186 +                w.append(te.getSimpleName()).append(" instance");
  65.187 +                sep = ", ";
  65.188 +            } else {
  65.189 +                sep = "";
  65.190 +            }
  65.191 +            for (int i = 1; i < params.size(); i++) {
  65.192 +                final VariableElement p = params.get(i);
  65.193 +                w.append(sep).append(p.asType().toString()).append(" ").append(p.getSimpleName());
  65.194 +            }
  65.195 +            w.append(") { return new ").append(className).append("(false, ").append(inst);
  65.196 +            for (int i = 1; i < params.size(); i++) {
  65.197 +                final VariableElement p = params.get(i);
  65.198 +                w.append(", ").append(p.getSimpleName());
  65.199 +            }
  65.200 +            w.append("); }\n");
  65.201 +            w.append("  @Override protected void onError(Exception t) throws Throwable {\n");
  65.202 +            if (ol.onError().isEmpty()) {
  65.203 +                w.append("    t.printStackTrace();");
  65.204 +            } else {
  65.205 +                if (!findOnError(me, te, ol.onError(), isStatic)) {
  65.206 +                    return false;
  65.207 +                }
  65.208 +                if (isStatic) {
  65.209 +                    w.append("    ").append(te.getSimpleName()).append(".");
  65.210 +                } else {
  65.211 +                    w.append("    $i.");
  65.212 +                }
  65.213 +                w.append(ol.onError()).append("(t");
  65.214 +                for (int i = 1; i < params.size(); i++) {
  65.215 +                    final VariableElement p = params.get(i);
  65.216 +                    w.append(", ").append(p.getSimpleName());
  65.217 +                }
  65.218 +                w.append(");\n");
  65.219 +            }
  65.220 +            w.append("  }\n");
  65.221 +            w.append("  @Override protected void onLocation(net.java.html.geo.Position p) throws Throwable {\n");
  65.222 +            if (isStatic) {
  65.223 +                w.append("    ").append(te.getSimpleName()).append(".");
  65.224 +            } else {
  65.225 +                w.append("    $i.");
  65.226 +            }
  65.227 +            w.append(me.getSimpleName()).append("(p");
  65.228 +            for (int i = 1; i < params.size(); i++) {
  65.229 +                final VariableElement p = params.get(i);
  65.230 +                w.append(", ").append(p.getSimpleName());
  65.231 +            }
  65.232 +            w.append(");\n");
  65.233 +            w.append("  }\n");
  65.234 +            w.append("}\n");
  65.235 +            w.close();
  65.236 +        } catch (IOException ex) {
  65.237 +            Logger.getLogger(GeoProcessor.class.getName()).log(Level.SEVERE, null, ex);
  65.238 +            error("Can't write handler class: " + ex.getMessage(), e);
  65.239 +            return false;
  65.240 +        }
  65.241 +        
  65.242 +        return true;
  65.243 +    }
  65.244 +
  65.245 +    private boolean findOnError(ExecutableElement errElem, TypeElement te, String name, boolean onlyStatic) {
  65.246 +        String err = null;
  65.247 +        METHODS: for (Element e : te.getEnclosedElements()) {
  65.248 +            if (e.getKind() != ElementKind.METHOD) {
  65.249 +                continue;
  65.250 +            }
  65.251 +            if (!e.getSimpleName().contentEquals(name)) {
  65.252 +                continue;
  65.253 +            }
  65.254 +            if (onlyStatic && !e.getModifiers().contains(Modifier.STATIC)) {
  65.255 +                errElem = (ExecutableElement) e;
  65.256 +                err = "Would have to be static";
  65.257 +                continue;
  65.258 +            }
  65.259 +            ExecutableElement ee = (ExecutableElement) e;
  65.260 +            TypeMirror excType = processingEnv.getElementUtils().getTypeElement(Exception.class.getName()).asType();
  65.261 +            final List<? extends VariableElement> params = ee.getParameters(); 
  65.262 +            if (params.size() < 1 || 
  65.263 +                !processingEnv.getTypeUtils().isAssignable(excType, ee.getParameters().get(0).asType())
  65.264 +            ) {
  65.265 +                errElem = (ExecutableElement) e;
  65.266 +                err = "Error method first argument needs to be Exception";
  65.267 +                continue;
  65.268 +            }
  65.269 +            final List<? extends Element> origParams = errElem.getParameters();
  65.270 +            if (params.size() != origParams.size()) {
  65.271 +                errElem = (ExecutableElement) e;
  65.272 +                err = "Error method must have the same parameters as @OnLocation one";
  65.273 +                continue;
  65.274 +            }
  65.275 +            for (int i = 1; i < origParams.size(); i++) {
  65.276 +                final TypeMirror t1 = params.get(i).asType();
  65.277 +                final TypeMirror t2 = origParams.get(i).asType();
  65.278 +                if (!processingEnv.getTypeUtils().isSameType(t1, t2)) {
  65.279 +                    errElem = (ExecutableElement) e;
  65.280 +                    err = "Error method must have the same parameters as @OnLocation one";
  65.281 +                    continue METHODS;
  65.282 +                }
  65.283 +            }
  65.284 +            return true;
  65.285 +        }
  65.286 +        if (err == null) {
  65.287 +            err = "Cannot find " + name + "(Exception) method in this class";
  65.288 +        }
  65.289 +        error(err, errElem);
  65.290 +        return false;
  65.291 +    }
  65.292 +}
    66.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    66.2 +++ b/geo/src/main/java/org/netbeans/html/geo/impl/JsG.java	Mon Dec 16 16:59:43 2013 +0100
    66.3 @@ -0,0 +1,107 @@
    66.4 +/**
    66.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    66.6 + *
    66.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    66.8 + *
    66.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   66.10 + * Other names may be trademarks of their respective owners.
   66.11 + *
   66.12 + * The contents of this file are subject to the terms of either the GNU
   66.13 + * General Public License Version 2 only ("GPL") or the Common
   66.14 + * Development and Distribution License("CDDL") (collectively, the
   66.15 + * "License"). You may not use this file except in compliance with the
   66.16 + * License. You can obtain a copy of the License at
   66.17 + * http://www.netbeans.org/cddl-gplv2.html
   66.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   66.19 + * specific language governing permissions and limitations under the
   66.20 + * License.  When distributing the software, include this License Header
   66.21 + * Notice in each file and include the License file at
   66.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   66.23 + * particular file as subject to the "Classpath" exception as provided
   66.24 + * by Oracle in the GPL Version 2 section of the License file that
   66.25 + * accompanied this code. If applicable, add the following below the
   66.26 + * License Header, with the fields enclosed by brackets [] replaced by
   66.27 + * your own identifying information:
   66.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   66.29 + *
   66.30 + * Contributor(s):
   66.31 + *
   66.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   66.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   66.34 + *
   66.35 + * If you wish your version of this file to be governed by only the CDDL
   66.36 + * or only the GPL Version 2, indicate your decision by adding
   66.37 + * "[Contributor] elects to include this software in this distribution
   66.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   66.39 + * single choice of license, a recipient has the option to distribute
   66.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   66.41 + * to extend the choice of license to its licensees as provided above.
   66.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   66.43 + * Version 2 license, then the option applies only if the new code is
   66.44 + * made subject to such option by the copyright holder.
   66.45 + */
   66.46 +package org.netbeans.html.geo.impl;
   66.47 +
   66.48 +import net.java.html.js.JavaScriptBody;
   66.49 +
   66.50 +/** Implementation class to deal with browser's <code>navigator.geolocation</code> 
   66.51 + * object.
   66.52 + *
   66.53 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   66.54 + */
   66.55 +public abstract class JsG {
   66.56 +    protected JsG() {
   66.57 +        if (!getClass().getName().equals("net.java.html.geo.Position$Handle$JsH")) {
   66.58 +            throw new IllegalStateException();
   66.59 +        }
   66.60 +    }
   66.61 +    
   66.62 +    public abstract void onLocation(Object position);
   66.63 +    public abstract void onError(Object error);
   66.64 +    
   66.65 +    @JavaScriptBody(args = {}, body = "return !!navigator.geolocation;")
   66.66 +    public static boolean hasGeolocation() {
   66.67 +        return false;
   66.68 +    }
   66.69 +
   66.70 +    @JavaScriptBody(
   66.71 +        args = { "onlyOnce", "enableHighAccuracy", "timeout", "maximumAge" }, 
   66.72 +        javacall = true, 
   66.73 +        body = 
   66.74 +        "var self = this;\n" +
   66.75 +        "var ok = function (position) {\n" +
   66.76 +        "  self.@org.netbeans.html.geo.impl.JsG::onLocation(Ljava/lang/Object;)(position);\n" +
   66.77 +        "};\n" +
   66.78 +        "var fail = function (error) {\n" +
   66.79 +        "  self.@org.netbeans.html.geo.impl.JsG::onError(Ljava/lang/Object;)(error);\n" +
   66.80 +        "};\n" +
   66.81 +        "var options = {};\n" +
   66.82 +        "options.enableHighAccuracy = enableHighAccuracy;\n" +
   66.83 +        "if (timeout >= 0) options.timeout = timeout;\n" +
   66.84 +        "if (maximumAge >= 0) options.maximumAge = maximumAge;\n" +
   66.85 +        "if (onlyOnce) {\n" +
   66.86 +        "  navigator.geolocation.getCurrentPosition(ok, fail);\n" +
   66.87 +        "  return 0;\n" +
   66.88 +        "} else {\n" +
   66.89 +        "  return navigator.geolocation.watchPosition(ok, fail);\n" +
   66.90 +        "}\n"
   66.91 +    )
   66.92 +    protected long start(
   66.93 +        boolean onlyOnce, 
   66.94 +        boolean enableHighAccuracy,
   66.95 +        long timeout,
   66.96 +        long maximumAge
   66.97 +    ) {
   66.98 +        return -1;
   66.99 +    }
  66.100 +    
  66.101 +    @JavaScriptBody(args = { "watch" }, body = "navigator.geolocation.clearWatch(watch);")
  66.102 +    protected void stop(long watch) {
  66.103 +    }
  66.104 +
  66.105 +    @JavaScriptBody(args = { "self", "property" }, body = "return self[property];")
  66.106 +    public static Object get(Object self, String property) {
  66.107 +        return null;
  66.108 +    }
  66.109 +
  66.110 +}
    67.1 --- a/geo/src/test/java/org/apidesign/html/geo/impl/Compile.java	Mon Dec 16 15:48:09 2013 +0100
    67.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    67.3 @@ -1,286 +0,0 @@
    67.4 -/**
    67.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    67.6 - *
    67.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    67.8 - *
    67.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   67.10 - * Other names may be trademarks of their respective owners.
   67.11 - *
   67.12 - * The contents of this file are subject to the terms of either the GNU
   67.13 - * General Public License Version 2 only ("GPL") or the Common
   67.14 - * Development and Distribution License("CDDL") (collectively, the
   67.15 - * "License"). You may not use this file except in compliance with the
   67.16 - * License. You can obtain a copy of the License at
   67.17 - * http://www.netbeans.org/cddl-gplv2.html
   67.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   67.19 - * specific language governing permissions and limitations under the
   67.20 - * License.  When distributing the software, include this License Header
   67.21 - * Notice in each file and include the License file at
   67.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   67.23 - * particular file as subject to the "Classpath" exception as provided
   67.24 - * by Oracle in the GPL Version 2 section of the License file that
   67.25 - * accompanied this code. If applicable, add the following below the
   67.26 - * License Header, with the fields enclosed by brackets [] replaced by
   67.27 - * your own identifying information:
   67.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   67.29 - *
   67.30 - * Contributor(s):
   67.31 - *
   67.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   67.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   67.34 - *
   67.35 - * If you wish your version of this file to be governed by only the CDDL
   67.36 - * or only the GPL Version 2, indicate your decision by adding
   67.37 - * "[Contributor] elects to include this software in this distribution
   67.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   67.39 - * single choice of license, a recipient has the option to distribute
   67.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   67.41 - * to extend the choice of license to its licensees as provided above.
   67.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   67.43 - * Version 2 license, then the option applies only if the new code is
   67.44 - * made subject to such option by the copyright holder.
   67.45 - */
   67.46 -package org.apidesign.html.geo.impl;
   67.47 -
   67.48 -import java.io.ByteArrayInputStream;
   67.49 -import java.io.ByteArrayOutputStream;
   67.50 -import java.io.IOException;
   67.51 -import java.io.InputStream;
   67.52 -import java.io.OutputStream;
   67.53 -import java.net.URI;
   67.54 -import java.net.URISyntaxException;
   67.55 -import java.util.ArrayList;
   67.56 -import java.util.Arrays;
   67.57 -import java.util.HashMap;
   67.58 -import java.util.List;
   67.59 -import java.util.Locale;
   67.60 -import java.util.Map;
   67.61 -import java.util.regex.Matcher;
   67.62 -import java.util.regex.Pattern;
   67.63 -import javax.tools.Diagnostic;
   67.64 -import javax.tools.DiagnosticListener;
   67.65 -import javax.tools.FileObject;
   67.66 -import javax.tools.ForwardingJavaFileManager;
   67.67 -import javax.tools.JavaFileManager;
   67.68 -import javax.tools.JavaFileObject;
   67.69 -import javax.tools.JavaFileObject.Kind;
   67.70 -import javax.tools.SimpleJavaFileObject;
   67.71 -import javax.tools.StandardJavaFileManager;
   67.72 -import javax.tools.StandardLocation;
   67.73 -import javax.tools.ToolProvider;
   67.74 -import static org.testng.Assert.*;
   67.75 -
   67.76 -/**
   67.77 - *
   67.78 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   67.79 - */
   67.80 -final class Compile implements DiagnosticListener<JavaFileObject> {
   67.81 -    private final List<Diagnostic<? extends JavaFileObject>> errors = 
   67.82 -            new ArrayList<Diagnostic<? extends JavaFileObject>>();
   67.83 -    private final Map<String, byte[]> classes;
   67.84 -    private final String pkg;
   67.85 -    private final String cls;
   67.86 -    private final String html;
   67.87 -    private final String sourceLevel;
   67.88 -
   67.89 -    private Compile(String html, String code, String sl) throws IOException {
   67.90 -        this.pkg = findPkg(code);
   67.91 -        this.cls = findCls(code);
   67.92 -        this.html = html;
   67.93 -        this.sourceLevel = sl;
   67.94 -        classes = compile(html, code);
   67.95 -    }
   67.96 -
   67.97 -    /** Performs compilation of given HTML page and associated Java code
   67.98 -     */
   67.99 -    public static Compile create(String html, String code) throws IOException {
  67.100 -        return create(html, code, "1.7");
  67.101 -    }
  67.102 -    static Compile create(String html, String code, String sourceLevel) throws IOException {
  67.103 -        return new Compile(html, code, sourceLevel);
  67.104 -    }
  67.105 -    
  67.106 -    /** Checks for given class among compiled resources */
  67.107 -    public byte[] get(String res) {
  67.108 -        return classes.get(res);
  67.109 -    }
  67.110 -    
  67.111 -    /** Obtains errors created during compilation.
  67.112 -     */
  67.113 -    public List<Diagnostic<? extends JavaFileObject>> getErrors() {
  67.114 -        List<Diagnostic<? extends JavaFileObject>> err;
  67.115 -        err = new ArrayList<Diagnostic<? extends JavaFileObject>>();
  67.116 -        for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
  67.117 -            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
  67.118 -                err.add(diagnostic);
  67.119 -            }
  67.120 -        }
  67.121 -        return err;
  67.122 -    }
  67.123 -    
  67.124 -    private Map<String, byte[]> compile(final String html, final String code) throws IOException {
  67.125 -        StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
  67.126 -
  67.127 -        final Map<String, ByteArrayOutputStream> class2BAOS;
  67.128 -        class2BAOS = new HashMap<String, ByteArrayOutputStream>();
  67.129 -
  67.130 -        JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
  67.131 -            @Override
  67.132 -            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
  67.133 -                return code;
  67.134 -            }
  67.135 -        };
  67.136 -        final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
  67.137 -            @Override
  67.138 -            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
  67.139 -                return html;
  67.140 -            }
  67.141 -
  67.142 -            @Override
  67.143 -            public InputStream openInputStream() throws IOException {
  67.144 -                return new ByteArrayInputStream(html.getBytes());
  67.145 -            }
  67.146 -        };
  67.147 -        
  67.148 -        final URI scratch;
  67.149 -        try {
  67.150 -            scratch = new URI("mem://mem3");
  67.151 -        } catch (URISyntaxException ex) {
  67.152 -            throw new IOException(ex);
  67.153 -        }
  67.154 -        
  67.155 -        JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
  67.156 -            @Override
  67.157 -            public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
  67.158 -                if (kind  == Kind.CLASS) {
  67.159 -                    final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
  67.160 -
  67.161 -                    class2BAOS.put(className.replace('.', '/') + ".class", buffer);
  67.162 -                    return new SimpleJavaFileObject(sibling.toUri(), kind) {
  67.163 -                        @Override
  67.164 -                        public OutputStream openOutputStream() throws IOException {
  67.165 -                            return buffer;
  67.166 -                        }
  67.167 -                    };
  67.168 -                }
  67.169 -                
  67.170 -                if (kind == Kind.SOURCE) {
  67.171 -                    final String n = className.replace('.', '/') + ".java";
  67.172 -                    final URI un;
  67.173 -                    try {
  67.174 -                        un = new URI("mem://" + n);
  67.175 -                    } catch (URISyntaxException ex) {
  67.176 -                        throw new IOException(ex);
  67.177 -                    }
  67.178 -                    return new VirtFO(un/*sibling.toUri()*/, kind, n);
  67.179 -                }
  67.180 -                
  67.181 -                throw new IllegalStateException();
  67.182 -            }
  67.183 -
  67.184 -            @Override
  67.185 -            public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
  67.186 -                if (location == StandardLocation.SOURCE_PATH) {
  67.187 -                    if (packageName.equals(pkg)) {
  67.188 -                        return htmlFile;
  67.189 -                    }
  67.190 -                }
  67.191 -                
  67.192 -                return null;
  67.193 -            }
  67.194 -
  67.195 -            @Override
  67.196 -            public boolean isSameFile(FileObject a, FileObject b) {
  67.197 -                if (a instanceof VirtFO && b instanceof VirtFO) {
  67.198 -                    return ((VirtFO)a).getName().equals(((VirtFO)b).getName());
  67.199 -                }
  67.200 -                
  67.201 -                return super.isSameFile(a, b);
  67.202 -            }
  67.203 -
  67.204 -            class VirtFO extends SimpleJavaFileObject {
  67.205 -
  67.206 -                private final String n;
  67.207 -
  67.208 -                public VirtFO(URI uri, Kind kind, String n) {
  67.209 -                    super(uri, kind);
  67.210 -                    this.n = n;
  67.211 -                }
  67.212 -                private final ByteArrayOutputStream data = new ByteArrayOutputStream();
  67.213 -
  67.214 -                @Override
  67.215 -                public OutputStream openOutputStream() throws IOException {
  67.216 -                    return data;
  67.217 -                }
  67.218 -
  67.219 -                @Override
  67.220 -                public String getName() {
  67.221 -                    return n;
  67.222 -                }
  67.223 -
  67.224 -                @Override
  67.225 -                public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
  67.226 -                    data.close();
  67.227 -                    return new String(data.toByteArray());
  67.228 -                }
  67.229 -            }
  67.230 -        };
  67.231 -
  67.232 -        ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", sourceLevel, "-target", "1.7"), null, Arrays.asList(file)).call();
  67.233 -
  67.234 -        Map<String, byte[]> result = new HashMap<String, byte[]>();
  67.235 -
  67.236 -        for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
  67.237 -            result.put(e.getKey(), e.getValue().toByteArray());
  67.238 -        }
  67.239 -
  67.240 -        return result;
  67.241 -    }
  67.242 -
  67.243 -
  67.244 -    @Override
  67.245 -    public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
  67.246 -        errors.add(diagnostic);
  67.247 -    }
  67.248 -    private static String findPkg(String java) throws IOException {
  67.249 -        Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
  67.250 -        Matcher m = p.matcher(java);
  67.251 -        if (!m.find()) {
  67.252 -            throw new IOException("Can't find package declaration in the java file");
  67.253 -        }
  67.254 -        String pkg = m.group(1);
  67.255 -        return pkg;
  67.256 -    }
  67.257 -    private static String findCls(String java) throws IOException {
  67.258 -        Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
  67.259 -        Matcher m = p.matcher(java);
  67.260 -        if (!m.find()) {
  67.261 -            throw new IOException("Can't find package declaration in the java file");
  67.262 -        }
  67.263 -        String cls = m.group(1);
  67.264 -        return cls;
  67.265 -    }
  67.266 -
  67.267 -    String getHtml() {
  67.268 -        String fqn = "'" + pkg + '.' + cls + "'";
  67.269 -        return html.replace("'${fqn}'", fqn);
  67.270 -    }
  67.271 -
  67.272 -    void assertErrors() {
  67.273 -        assertFalse(getErrors().isEmpty(), "There are supposed to be some errors");
  67.274 -    }
  67.275 -
  67.276 -    void assertError(String expMsg) {
  67.277 -        StringBuilder sb = new StringBuilder();
  67.278 -        sb.append("Can't find ").append(expMsg).append(" among:");
  67.279 -        for (Diagnostic<? extends JavaFileObject> e : errors) {
  67.280 -            String msg = e.getMessage(Locale.US);
  67.281 -            if (msg.contains(expMsg)) {
  67.282 -                return;
  67.283 -            }
  67.284 -            sb.append("\n");
  67.285 -            sb.append(msg);
  67.286 -        }
  67.287 -        fail(sb.toString());
  67.288 -    }
  67.289 -}
    68.1 --- a/geo/src/test/java/org/apidesign/html/geo/impl/GeoProcessorTest.java	Mon Dec 16 15:48:09 2013 +0100
    68.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    68.3 @@ -1,114 +0,0 @@
    68.4 -/**
    68.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    68.6 - *
    68.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    68.8 - *
    68.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   68.10 - * Other names may be trademarks of their respective owners.
   68.11 - *
   68.12 - * The contents of this file are subject to the terms of either the GNU
   68.13 - * General Public License Version 2 only ("GPL") or the Common
   68.14 - * Development and Distribution License("CDDL") (collectively, the
   68.15 - * "License"). You may not use this file except in compliance with the
   68.16 - * License. You can obtain a copy of the License at
   68.17 - * http://www.netbeans.org/cddl-gplv2.html
   68.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   68.19 - * specific language governing permissions and limitations under the
   68.20 - * License.  When distributing the software, include this License Header
   68.21 - * Notice in each file and include the License file at
   68.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   68.23 - * particular file as subject to the "Classpath" exception as provided
   68.24 - * by Oracle in the GPL Version 2 section of the License file that
   68.25 - * accompanied this code. If applicable, add the following below the
   68.26 - * License Header, with the fields enclosed by brackets [] replaced by
   68.27 - * your own identifying information:
   68.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   68.29 - *
   68.30 - * Contributor(s):
   68.31 - *
   68.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   68.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   68.34 - *
   68.35 - * If you wish your version of this file to be governed by only the CDDL
   68.36 - * or only the GPL Version 2, indicate your decision by adding
   68.37 - * "[Contributor] elects to include this software in this distribution
   68.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   68.39 - * single choice of license, a recipient has the option to distribute
   68.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   68.41 - * to extend the choice of license to its licensees as provided above.
   68.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   68.43 - * Version 2 license, then the option applies only if the new code is
   68.44 - * made subject to such option by the copyright holder.
   68.45 - */
   68.46 -package org.apidesign.html.geo.impl;
   68.47 -
   68.48 -import java.io.IOException;
   68.49 -import org.testng.annotations.Test;
   68.50 -
   68.51 -/** Test whether the annotation processor detects errors correctly.
   68.52 - *
   68.53 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   68.54 - */
   68.55 -public class GeoProcessorTest {
   68.56 -    
   68.57 -    public GeoProcessorTest() {
   68.58 -    }
   68.59 -
   68.60 -    @Test public void onLocationMethodHasToTakePositionParameter() throws IOException {
   68.61 -        Compile res = Compile.create("", "package x;\n"
   68.62 -            + "class UseOnLocation {\n"
   68.63 -            + "  @net.java.html.geo.OnLocation\n"
   68.64 -            + "  public static void cantCallMe() {}\n"
   68.65 -            + "}\n"
   68.66 -        );
   68.67 -        res.assertErrors();
   68.68 -        res.assertError("first argument must be net.java.html.geo.Position");
   68.69 -    }
   68.70 -    
   68.71 -    @Test public void onLocationMethodCannotBePrivate() throws IOException {
   68.72 -        Compile res = Compile.create("", "package x;\n"
   68.73 -            + "class UseOnLocation {\n"
   68.74 -            + "  @net.java.html.geo.OnLocation\n"
   68.75 -            + "  private static void cantCallMe(net.java.html.geo.Position p) {}\n"
   68.76 -            + "}\n"
   68.77 -        );
   68.78 -        res.assertErrors();
   68.79 -        res.assertError("cannot be private");
   68.80 -    }
   68.81 -    
   68.82 -    @Test public void onErrorHasToExist() throws IOException {
   68.83 -        Compile res = Compile.create("", "package x;\n"
   68.84 -            + "class UseOnLocation {\n"
   68.85 -            + "  @net.java.html.geo.OnLocation(onError=\"doesNotExist\")\n"
   68.86 -            + "  static void cantCallMe(net.java.html.geo.Position p) {}\n"
   68.87 -            + "}\n"
   68.88 -        );
   68.89 -        res.assertErrors();
   68.90 -        res.assertError("not find doesNotExist");
   68.91 -    }
   68.92 -
   68.93 -    @Test public void onErrorWouldHaveToBeStatic() throws IOException {
   68.94 -        Compile res = Compile.create("", "package x;\n"
   68.95 -            + "class UseOnLocation {\n"
   68.96 -            + "  @net.java.html.geo.OnLocation(onError=\"notStatic\")\n"
   68.97 -            + "  static void cantCallMe(net.java.html.geo.Position p) {}\n"
   68.98 -            + "  void notStatic(Exception e) {}\n"
   68.99 -            + "}\n"
  68.100 -        );
  68.101 -        res.assertErrors();
  68.102 -        res.assertError("have to be static");
  68.103 -    }
  68.104 -
  68.105 -    @Test public void onErrorMustAcceptExceptionArgument() throws IOException {
  68.106 -        Compile res = Compile.create("", "package x;\n"
  68.107 -            + "class UseOnLocation {\n"
  68.108 -            + "  @net.java.html.geo.OnLocation(onError=\"notStatic\")\n"
  68.109 -            + "  static void cantCallMe(net.java.html.geo.Position p) {}\n"
  68.110 -            + "  static void notStatic(java.io.IOException e) {}\n"
  68.111 -            + "}\n"
  68.112 -        );
  68.113 -        res.assertErrors();
  68.114 -        res.assertError("Error method first argument needs to be Exception");
  68.115 -    }
  68.116 -    
  68.117 -}
    69.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    69.2 +++ b/geo/src/test/java/org/netbeans/html/geo/impl/Compile.java	Mon Dec 16 16:59:43 2013 +0100
    69.3 @@ -0,0 +1,286 @@
    69.4 +/**
    69.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    69.6 + *
    69.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    69.8 + *
    69.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   69.10 + * Other names may be trademarks of their respective owners.
   69.11 + *
   69.12 + * The contents of this file are subject to the terms of either the GNU
   69.13 + * General Public License Version 2 only ("GPL") or the Common
   69.14 + * Development and Distribution License("CDDL") (collectively, the
   69.15 + * "License"). You may not use this file except in compliance with the
   69.16 + * License. You can obtain a copy of the License at
   69.17 + * http://www.netbeans.org/cddl-gplv2.html
   69.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   69.19 + * specific language governing permissions and limitations under the
   69.20 + * License.  When distributing the software, include this License Header
   69.21 + * Notice in each file and include the License file at
   69.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   69.23 + * particular file as subject to the "Classpath" exception as provided
   69.24 + * by Oracle in the GPL Version 2 section of the License file that
   69.25 + * accompanied this code. If applicable, add the following below the
   69.26 + * License Header, with the fields enclosed by brackets [] replaced by
   69.27 + * your own identifying information:
   69.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   69.29 + *
   69.30 + * Contributor(s):
   69.31 + *
   69.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   69.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   69.34 + *
   69.35 + * If you wish your version of this file to be governed by only the CDDL
   69.36 + * or only the GPL Version 2, indicate your decision by adding
   69.37 + * "[Contributor] elects to include this software in this distribution
   69.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   69.39 + * single choice of license, a recipient has the option to distribute
   69.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   69.41 + * to extend the choice of license to its licensees as provided above.
   69.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   69.43 + * Version 2 license, then the option applies only if the new code is
   69.44 + * made subject to such option by the copyright holder.
   69.45 + */
   69.46 +package org.netbeans.html.geo.impl;
   69.47 +
   69.48 +import java.io.ByteArrayInputStream;
   69.49 +import java.io.ByteArrayOutputStream;
   69.50 +import java.io.IOException;
   69.51 +import java.io.InputStream;
   69.52 +import java.io.OutputStream;
   69.53 +import java.net.URI;
   69.54 +import java.net.URISyntaxException;
   69.55 +import java.util.ArrayList;
   69.56 +import java.util.Arrays;
   69.57 +import java.util.HashMap;
   69.58 +import java.util.List;
   69.59 +import java.util.Locale;
   69.60 +import java.util.Map;
   69.61 +import java.util.regex.Matcher;
   69.62 +import java.util.regex.Pattern;
   69.63 +import javax.tools.Diagnostic;
   69.64 +import javax.tools.DiagnosticListener;
   69.65 +import javax.tools.FileObject;
   69.66 +import javax.tools.ForwardingJavaFileManager;
   69.67 +import javax.tools.JavaFileManager;
   69.68 +import javax.tools.JavaFileObject;
   69.69 +import javax.tools.JavaFileObject.Kind;
   69.70 +import javax.tools.SimpleJavaFileObject;
   69.71 +import javax.tools.StandardJavaFileManager;
   69.72 +import javax.tools.StandardLocation;
   69.73 +import javax.tools.ToolProvider;
   69.74 +import static org.testng.Assert.*;
   69.75 +
   69.76 +/**
   69.77 + *
   69.78 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   69.79 + */
   69.80 +final class Compile implements DiagnosticListener<JavaFileObject> {
   69.81 +    private final List<Diagnostic<? extends JavaFileObject>> errors = 
   69.82 +            new ArrayList<Diagnostic<? extends JavaFileObject>>();
   69.83 +    private final Map<String, byte[]> classes;
   69.84 +    private final String pkg;
   69.85 +    private final String cls;
   69.86 +    private final String html;
   69.87 +    private final String sourceLevel;
   69.88 +
   69.89 +    private Compile(String html, String code, String sl) throws IOException {
   69.90 +        this.pkg = findPkg(code);
   69.91 +        this.cls = findCls(code);
   69.92 +        this.html = html;
   69.93 +        this.sourceLevel = sl;
   69.94 +        classes = compile(html, code);
   69.95 +    }
   69.96 +
   69.97 +    /** Performs compilation of given HTML page and associated Java code
   69.98 +     */
   69.99 +    public static Compile create(String html, String code) throws IOException {
  69.100 +        return create(html, code, "1.7");
  69.101 +    }
  69.102 +    static Compile create(String html, String code, String sourceLevel) throws IOException {
  69.103 +        return new Compile(html, code, sourceLevel);
  69.104 +    }
  69.105 +    
  69.106 +    /** Checks for given class among compiled resources */
  69.107 +    public byte[] get(String res) {
  69.108 +        return classes.get(res);
  69.109 +    }
  69.110 +    
  69.111 +    /** Obtains errors created during compilation.
  69.112 +     */
  69.113 +    public List<Diagnostic<? extends JavaFileObject>> getErrors() {
  69.114 +        List<Diagnostic<? extends JavaFileObject>> err;
  69.115 +        err = new ArrayList<Diagnostic<? extends JavaFileObject>>();
  69.116 +        for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
  69.117 +            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
  69.118 +                err.add(diagnostic);
  69.119 +            }
  69.120 +        }
  69.121 +        return err;
  69.122 +    }
  69.123 +    
  69.124 +    private Map<String, byte[]> compile(final String html, final String code) throws IOException {
  69.125 +        StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
  69.126 +
  69.127 +        final Map<String, ByteArrayOutputStream> class2BAOS;
  69.128 +        class2BAOS = new HashMap<String, ByteArrayOutputStream>();
  69.129 +
  69.130 +        JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
  69.131 +            @Override
  69.132 +            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
  69.133 +                return code;
  69.134 +            }
  69.135 +        };
  69.136 +        final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
  69.137 +            @Override
  69.138 +            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
  69.139 +                return html;
  69.140 +            }
  69.141 +
  69.142 +            @Override
  69.143 +            public InputStream openInputStream() throws IOException {
  69.144 +                return new ByteArrayInputStream(html.getBytes());
  69.145 +            }
  69.146 +        };
  69.147 +        
  69.148 +        final URI scratch;
  69.149 +        try {
  69.150 +            scratch = new URI("mem://mem3");
  69.151 +        } catch (URISyntaxException ex) {
  69.152 +            throw new IOException(ex);
  69.153 +        }
  69.154 +        
  69.155 +        JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
  69.156 +            @Override
  69.157 +            public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
  69.158 +                if (kind  == Kind.CLASS) {
  69.159 +                    final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
  69.160 +
  69.161 +                    class2BAOS.put(className.replace('.', '/') + ".class", buffer);
  69.162 +                    return new SimpleJavaFileObject(sibling.toUri(), kind) {
  69.163 +                        @Override
  69.164 +                        public OutputStream openOutputStream() throws IOException {
  69.165 +                            return buffer;
  69.166 +                        }
  69.167 +                    };
  69.168 +                }
  69.169 +                
  69.170 +                if (kind == Kind.SOURCE) {
  69.171 +                    final String n = className.replace('.', '/') + ".java";
  69.172 +                    final URI un;
  69.173 +                    try {
  69.174 +                        un = new URI("mem://" + n);
  69.175 +                    } catch (URISyntaxException ex) {
  69.176 +                        throw new IOException(ex);
  69.177 +                    }
  69.178 +                    return new VirtFO(un/*sibling.toUri()*/, kind, n);
  69.179 +                }
  69.180 +                
  69.181 +                throw new IllegalStateException();
  69.182 +            }
  69.183 +
  69.184 +            @Override
  69.185 +            public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
  69.186 +                if (location == StandardLocation.SOURCE_PATH) {
  69.187 +                    if (packageName.equals(pkg)) {
  69.188 +                        return htmlFile;
  69.189 +                    }
  69.190 +                }
  69.191 +                
  69.192 +                return null;
  69.193 +            }
  69.194 +
  69.195 +            @Override
  69.196 +            public boolean isSameFile(FileObject a, FileObject b) {
  69.197 +                if (a instanceof VirtFO && b instanceof VirtFO) {
  69.198 +                    return ((VirtFO)a).getName().equals(((VirtFO)b).getName());
  69.199 +                }
  69.200 +                
  69.201 +                return super.isSameFile(a, b);
  69.202 +            }
  69.203 +
  69.204 +            class VirtFO extends SimpleJavaFileObject {
  69.205 +
  69.206 +                private final String n;
  69.207 +
  69.208 +                public VirtFO(URI uri, Kind kind, String n) {
  69.209 +                    super(uri, kind);
  69.210 +                    this.n = n;
  69.211 +                }
  69.212 +                private final ByteArrayOutputStream data = new ByteArrayOutputStream();
  69.213 +
  69.214 +                @Override
  69.215 +                public OutputStream openOutputStream() throws IOException {
  69.216 +                    return data;
  69.217 +                }
  69.218 +
  69.219 +                @Override
  69.220 +                public String getName() {
  69.221 +                    return n;
  69.222 +                }
  69.223 +
  69.224 +                @Override
  69.225 +                public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
  69.226 +                    data.close();
  69.227 +                    return new String(data.toByteArray());
  69.228 +                }
  69.229 +            }
  69.230 +        };
  69.231 +
  69.232 +        ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", sourceLevel, "-target", "1.7"), null, Arrays.asList(file)).call();
  69.233 +
  69.234 +        Map<String, byte[]> result = new HashMap<String, byte[]>();
  69.235 +
  69.236 +        for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
  69.237 +            result.put(e.getKey(), e.getValue().toByteArray());
  69.238 +        }
  69.239 +
  69.240 +        return result;
  69.241 +    }
  69.242 +
  69.243 +
  69.244 +    @Override
  69.245 +    public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
  69.246 +        errors.add(diagnostic);
  69.247 +    }
  69.248 +    private static String findPkg(String java) throws IOException {
  69.249 +        Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
  69.250 +        Matcher m = p.matcher(java);
  69.251 +        if (!m.find()) {
  69.252 +            throw new IOException("Can't find package declaration in the java file");
  69.253 +        }
  69.254 +        String pkg = m.group(1);
  69.255 +        return pkg;
  69.256 +    }
  69.257 +    private static String findCls(String java) throws IOException {
  69.258 +        Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
  69.259 +        Matcher m = p.matcher(java);
  69.260 +        if (!m.find()) {
  69.261 +            throw new IOException("Can't find package declaration in the java file");
  69.262 +        }
  69.263 +        String cls = m.group(1);
  69.264 +        return cls;
  69.265 +    }
  69.266 +
  69.267 +    String getHtml() {
  69.268 +        String fqn = "'" + pkg + '.' + cls + "'";
  69.269 +        return html.replace("'${fqn}'", fqn);
  69.270 +    }
  69.271 +
  69.272 +    void assertErrors() {
  69.273 +        assertFalse(getErrors().isEmpty(), "There are supposed to be some errors");
  69.274 +    }
  69.275 +
  69.276 +    void assertError(String expMsg) {
  69.277 +        StringBuilder sb = new StringBuilder();
  69.278 +        sb.append("Can't find ").append(expMsg).append(" among:");
  69.279 +        for (Diagnostic<? extends JavaFileObject> e : errors) {
  69.280 +            String msg = e.getMessage(Locale.US);
  69.281 +            if (msg.contains(expMsg)) {
  69.282 +                return;
  69.283 +            }
  69.284 +            sb.append("\n");
  69.285 +            sb.append(msg);
  69.286 +        }
  69.287 +        fail(sb.toString());
  69.288 +    }
  69.289 +}
    70.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    70.2 +++ b/geo/src/test/java/org/netbeans/html/geo/impl/GeoProcessorTest.java	Mon Dec 16 16:59:43 2013 +0100
    70.3 @@ -0,0 +1,114 @@
    70.4 +/**
    70.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    70.6 + *
    70.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    70.8 + *
    70.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   70.10 + * Other names may be trademarks of their respective owners.
   70.11 + *
   70.12 + * The contents of this file are subject to the terms of either the GNU
   70.13 + * General Public License Version 2 only ("GPL") or the Common
   70.14 + * Development and Distribution License("CDDL") (collectively, the
   70.15 + * "License"). You may not use this file except in compliance with the
   70.16 + * License. You can obtain a copy of the License at
   70.17 + * http://www.netbeans.org/cddl-gplv2.html
   70.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   70.19 + * specific language governing permissions and limitations under the
   70.20 + * License.  When distributing the software, include this License Header
   70.21 + * Notice in each file and include the License file at
   70.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   70.23 + * particular file as subject to the "Classpath" exception as provided
   70.24 + * by Oracle in the GPL Version 2 section of the License file that
   70.25 + * accompanied this code. If applicable, add the following below the
   70.26 + * License Header, with the fields enclosed by brackets [] replaced by
   70.27 + * your own identifying information:
   70.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   70.29 + *
   70.30 + * Contributor(s):
   70.31 + *
   70.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   70.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   70.34 + *
   70.35 + * If you wish your version of this file to be governed by only the CDDL
   70.36 + * or only the GPL Version 2, indicate your decision by adding
   70.37 + * "[Contributor] elects to include this software in this distribution
   70.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   70.39 + * single choice of license, a recipient has the option to distribute
   70.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   70.41 + * to extend the choice of license to its licensees as provided above.
   70.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   70.43 + * Version 2 license, then the option applies only if the new code is
   70.44 + * made subject to such option by the copyright holder.
   70.45 + */
   70.46 +package org.netbeans.html.geo.impl;
   70.47 +
   70.48 +import java.io.IOException;
   70.49 +import org.testng.annotations.Test;
   70.50 +
   70.51 +/** Test whether the annotation processor detects errors correctly.
   70.52 + *
   70.53 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   70.54 + */
   70.55 +public class GeoProcessorTest {
   70.56 +    
   70.57 +    public GeoProcessorTest() {
   70.58 +    }
   70.59 +
   70.60 +    @Test public void onLocationMethodHasToTakePositionParameter() throws IOException {
   70.61 +        Compile res = Compile.create("", "package x;\n"
   70.62 +            + "class UseOnLocation {\n"
   70.63 +            + "  @net.java.html.geo.OnLocation\n"
   70.64 +            + "  public static void cantCallMe() {}\n"
   70.65 +            + "}\n"
   70.66 +        );
   70.67 +        res.assertErrors();
   70.68 +        res.assertError("first argument must be net.java.html.geo.Position");
   70.69 +    }
   70.70 +    
   70.71 +    @Test public void onLocationMethodCannotBePrivate() throws IOException {
   70.72 +        Compile res = Compile.create("", "package x;\n"
   70.73 +            + "class UseOnLocation {\n"
   70.74 +            + "  @net.java.html.geo.OnLocation\n"
   70.75 +            + "  private static void cantCallMe(net.java.html.geo.Position p) {}\n"
   70.76 +            + "}\n"
   70.77 +        );
   70.78 +        res.assertErrors();
   70.79 +        res.assertError("cannot be private");
   70.80 +    }
   70.81 +    
   70.82 +    @Test public void onErrorHasToExist() throws IOException {
   70.83 +        Compile res = Compile.create("", "package x;\n"
   70.84 +            + "class UseOnLocation {\n"
   70.85 +            + "  @net.java.html.geo.OnLocation(onError=\"doesNotExist\")\n"
   70.86 +            + "  static void cantCallMe(net.java.html.geo.Position p) {}\n"
   70.87 +            + "}\n"
   70.88 +        );
   70.89 +        res.assertErrors();
   70.90 +        res.assertError("not find doesNotExist");
   70.91 +    }
   70.92 +
   70.93 +    @Test public void onErrorWouldHaveToBeStatic() throws IOException {
   70.94 +        Compile res = Compile.create("", "package x;\n"
   70.95 +            + "class UseOnLocation {\n"
   70.96 +            + "  @net.java.html.geo.OnLocation(onError=\"notStatic\")\n"
   70.97 +            + "  static void cantCallMe(net.java.html.geo.Position p) {}\n"
   70.98 +            + "  void notStatic(Exception e) {}\n"
   70.99 +            + "}\n"
  70.100 +        );
  70.101 +        res.assertErrors();
  70.102 +        res.assertError("have to be static");
  70.103 +    }
  70.104 +
  70.105 +    @Test public void onErrorMustAcceptExceptionArgument() throws IOException {
  70.106 +        Compile res = Compile.create("", "package x;\n"
  70.107 +            + "class UseOnLocation {\n"
  70.108 +            + "  @net.java.html.geo.OnLocation(onError=\"notStatic\")\n"
  70.109 +            + "  static void cantCallMe(net.java.html.geo.Position p) {}\n"
  70.110 +            + "  static void notStatic(java.io.IOException e) {}\n"
  70.111 +            + "}\n"
  70.112 +        );
  70.113 +        res.assertErrors();
  70.114 +        res.assertError("Error method first argument needs to be Exception");
  70.115 +    }
  70.116 +    
  70.117 +}
    71.1 --- a/json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java	Mon Dec 16 15:48:09 2013 +0100
    71.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java	Mon Dec 16 16:59:43 2013 +0100
    71.3 @@ -49,7 +49,7 @@
    71.4  import java.util.Map;
    71.5  import net.java.html.BrwsrCtx;
    71.6  import net.java.html.json.Models;
    71.7 -import org.apidesign.html.json.impl.JSON;
    71.8 +import org.netbeans.html.json.impl.JSON;
    71.9  import org.apidesign.html.json.tck.KOTest;
   71.10  
   71.11  /**
    72.1 --- a/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java	Mon Dec 16 15:48:09 2013 +0100
    72.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java	Mon Dec 16 16:59:43 2013 +0100
    72.3 @@ -49,7 +49,7 @@
    72.4  import net.java.html.json.Models;
    72.5  import net.java.html.json.OnReceive;
    72.6  import net.java.html.json.Property;
    72.7 -import org.apidesign.html.json.impl.JSON;
    72.8 +import org.netbeans.html.json.impl.JSON;
    72.9  import org.apidesign.html.json.tck.KOTest;
   72.10  
   72.11  /** Need to verify that models produce reasonable JSON objects.
    73.1 --- a/json/src/main/java/net/java/html/json/Models.java	Mon Dec 16 15:48:09 2013 +0100
    73.2 +++ b/json/src/main/java/net/java/html/json/Models.java	Mon Dec 16 16:59:43 2013 +0100
    73.3 @@ -45,7 +45,7 @@
    73.4  import net.java.html.BrwsrCtx;
    73.5  import java.io.IOException;
    73.6  import java.io.InputStream;
    73.7 -import org.apidesign.html.json.impl.JSON;
    73.8 +import org.netbeans.html.json.impl.JSON;
    73.9  
   73.10  /** Information about and 
   73.11   * operations for classes generated by the {@link Model @Model}
    74.1 --- a/json/src/main/java/org/apidesign/html/json/impl/Bindings.java	Mon Dec 16 15:48:09 2013 +0100
    74.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    74.3 @@ -1,113 +0,0 @@
    74.4 -/**
    74.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    74.6 - *
    74.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    74.8 - *
    74.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   74.10 - * Other names may be trademarks of their respective owners.
   74.11 - *
   74.12 - * The contents of this file are subject to the terms of either the GNU
   74.13 - * General Public License Version 2 only ("GPL") or the Common
   74.14 - * Development and Distribution License("CDDL") (collectively, the
   74.15 - * "License"). You may not use this file except in compliance with the
   74.16 - * License. You can obtain a copy of the License at
   74.17 - * http://www.netbeans.org/cddl-gplv2.html
   74.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   74.19 - * specific language governing permissions and limitations under the
   74.20 - * License.  When distributing the software, include this License Header
   74.21 - * Notice in each file and include the License file at
   74.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   74.23 - * particular file as subject to the "Classpath" exception as provided
   74.24 - * by Oracle in the GPL Version 2 section of the License file that
   74.25 - * accompanied this code. If applicable, add the following below the
   74.26 - * License Header, with the fields enclosed by brackets [] replaced by
   74.27 - * your own identifying information:
   74.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   74.29 - *
   74.30 - * Contributor(s):
   74.31 - *
   74.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   74.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   74.34 - *
   74.35 - * If you wish your version of this file to be governed by only the CDDL
   74.36 - * or only the GPL Version 2, indicate your decision by adding
   74.37 - * "[Contributor] elects to include this software in this distribution
   74.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   74.39 - * single choice of license, a recipient has the option to distribute
   74.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   74.41 - * to extend the choice of license to its licensees as provided above.
   74.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   74.43 - * Version 2 license, then the option applies only if the new code is
   74.44 - * made subject to such option by the copyright holder.
   74.45 - */
   74.46 -package org.apidesign.html.json.impl;
   74.47 -
   74.48 -import org.apidesign.html.json.spi.PropertyBinding;
   74.49 -import net.java.html.BrwsrCtx;
   74.50 -import org.apidesign.html.json.impl.PropertyBindingAccessor.FBData;
   74.51 -import org.apidesign.html.json.impl.PropertyBindingAccessor.PBData;
   74.52 -import org.apidesign.html.json.spi.FunctionBinding;
   74.53 -import org.apidesign.html.json.spi.Technology;
   74.54 -
   74.55 -/**
   74.56 - *
   74.57 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   74.58 - */
   74.59 -public final class Bindings<Data> {
   74.60 -    private Data data;
   74.61 -    private final Technology<Data> bp;
   74.62 -
   74.63 -    private Bindings(Technology<Data> bp) {
   74.64 -        this.bp = bp;
   74.65 -    }
   74.66 -    
   74.67 -    public <M> PropertyBinding registerProperty(String propName, M model, SetAndGet<M> access, boolean readOnly) {
   74.68 -        return PropertyBindingAccessor.create(new PBData<M>(this, propName, model, access, readOnly));
   74.69 -    }
   74.70 -
   74.71 -    public <M> FunctionBinding registerFunction(String name, M model, Callback<M> access) {
   74.72 -        return PropertyBindingAccessor.createFunction(new FBData<M>(name, model, access));
   74.73 -    }
   74.74 -    
   74.75 -    public static Bindings<?> apply(BrwsrCtx c, Object model) {
   74.76 -        Technology<?> bp = JSON.findTechnology(c);
   74.77 -        return apply(bp);
   74.78 -    }
   74.79 -    
   74.80 -    private static <Data> Bindings<Data> apply(Technology<Data> bp) {
   74.81 -        return new Bindings<Data>(bp);
   74.82 -    }
   74.83 -    
   74.84 -    public final void finish(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
   74.85 -        assert data == null;
   74.86 -        if (bp instanceof Technology.BatchInit) {
   74.87 -            Technology.BatchInit<Data> bi = (Technology.BatchInit<Data>)bp;
   74.88 -            data = bi.wrapModel(model, propArr, funcArr);
   74.89 -        } else {
   74.90 -            data = bp.wrapModel(model);
   74.91 -            for (PropertyBinding b : propArr) {
   74.92 -                bp.bind(b, model, data);
   74.93 -            }
   74.94 -            for (FunctionBinding b : funcArr) {
   74.95 -                bp.expose(b, model, data);
   74.96 -            }
   74.97 -        }
   74.98 -    }
   74.99 -    
  74.100 -    
  74.101 -    public Data koData() {
  74.102 -        return data;
  74.103 -    }
  74.104 -
  74.105 -    public void valueHasMutated(String firstName) {
  74.106 -        bp.valueHasMutated(data, firstName);
  74.107 -    }
  74.108 -    
  74.109 -    public void applyBindings() {
  74.110 -        bp.applyBindings(data);
  74.111 -    }
  74.112 -
  74.113 -    Object wrapArray(Object[] arr) {
  74.114 -        return bp.wrapArray(arr);
  74.115 -    }
  74.116 -}
    75.1 --- a/json/src/main/java/org/apidesign/html/json/impl/Callback.java	Mon Dec 16 15:48:09 2013 +0100
    75.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    75.3 @@ -1,51 +0,0 @@
    75.4 -/**
    75.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    75.6 - *
    75.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    75.8 - *
    75.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   75.10 - * Other names may be trademarks of their respective owners.
   75.11 - *
   75.12 - * The contents of this file are subject to the terms of either the GNU
   75.13 - * General Public License Version 2 only ("GPL") or the Common
   75.14 - * Development and Distribution License("CDDL") (collectively, the
   75.15 - * "License"). You may not use this file except in compliance with the
   75.16 - * License. You can obtain a copy of the License at
   75.17 - * http://www.netbeans.org/cddl-gplv2.html
   75.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   75.19 - * specific language governing permissions and limitations under the
   75.20 - * License.  When distributing the software, include this License Header
   75.21 - * Notice in each file and include the License file at
   75.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   75.23 - * particular file as subject to the "Classpath" exception as provided
   75.24 - * by Oracle in the GPL Version 2 section of the License file that
   75.25 - * accompanied this code. If applicable, add the following below the
   75.26 - * License Header, with the fields enclosed by brackets [] replaced by
   75.27 - * your own identifying information:
   75.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   75.29 - *
   75.30 - * Contributor(s):
   75.31 - *
   75.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   75.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   75.34 - *
   75.35 - * If you wish your version of this file to be governed by only the CDDL
   75.36 - * or only the GPL Version 2, indicate your decision by adding
   75.37 - * "[Contributor] elects to include this software in this distribution
   75.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   75.39 - * single choice of license, a recipient has the option to distribute
   75.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   75.41 - * to extend the choice of license to its licensees as provided above.
   75.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   75.43 - * Version 2 license, then the option applies only if the new code is
   75.44 - * made subject to such option by the copyright holder.
   75.45 - */
   75.46 -package org.apidesign.html.json.impl;
   75.47 -
   75.48 -/**
   75.49 - *
   75.50 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   75.51 - */
   75.52 -public interface Callback<Data> {
   75.53 -    public void call(Data model, Object data, Object ev);
   75.54 -}
    76.1 --- a/json/src/main/java/org/apidesign/html/json/impl/FromJSON.java	Mon Dec 16 15:48:09 2013 +0100
    76.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    76.3 @@ -1,55 +0,0 @@
    76.4 -/**
    76.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    76.6 - *
    76.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    76.8 - *
    76.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   76.10 - * Other names may be trademarks of their respective owners.
   76.11 - *
   76.12 - * The contents of this file are subject to the terms of either the GNU
   76.13 - * General Public License Version 2 only ("GPL") or the Common
   76.14 - * Development and Distribution License("CDDL") (collectively, the
   76.15 - * "License"). You may not use this file except in compliance with the
   76.16 - * License. You can obtain a copy of the License at
   76.17 - * http://www.netbeans.org/cddl-gplv2.html
   76.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   76.19 - * specific language governing permissions and limitations under the
   76.20 - * License.  When distributing the software, include this License Header
   76.21 - * Notice in each file and include the License file at
   76.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   76.23 - * particular file as subject to the "Classpath" exception as provided
   76.24 - * by Oracle in the GPL Version 2 section of the License file that
   76.25 - * accompanied this code. If applicable, add the following below the
   76.26 - * License Header, with the fields enclosed by brackets [] replaced by
   76.27 - * your own identifying information:
   76.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   76.29 - *
   76.30 - * Contributor(s):
   76.31 - *
   76.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   76.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   76.34 - *
   76.35 - * If you wish your version of this file to be governed by only the CDDL
   76.36 - * or only the GPL Version 2, indicate your decision by adding
   76.37 - * "[Contributor] elects to include this software in this distribution
   76.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   76.39 - * single choice of license, a recipient has the option to distribute
   76.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   76.41 - * to extend the choice of license to its licensees as provided above.
   76.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   76.43 - * Version 2 license, then the option applies only if the new code is
   76.44 - * made subject to such option by the copyright holder.
   76.45 - */
   76.46 -package org.apidesign.html.json.impl;
   76.47 -
   76.48 -import net.java.html.BrwsrCtx;
   76.49 -
   76.50 -/**
   76.51 - *
   76.52 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   76.53 - */
   76.54 -public interface FromJSON<Data> {
   76.55 -    public Class<Data> factoryFor();
   76.56 -    public Data read(BrwsrCtx c, Object d);
   76.57 -    public Data cloneTo(Object d, BrwsrCtx c);
   76.58 -}
    77.1 --- a/json/src/main/java/org/apidesign/html/json/impl/JSON.java	Mon Dec 16 15:48:09 2013 +0100
    77.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    77.3 @@ -1,474 +0,0 @@
    77.4 -/**
    77.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    77.6 - *
    77.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    77.8 - *
    77.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   77.10 - * Other names may be trademarks of their respective owners.
   77.11 - *
   77.12 - * The contents of this file are subject to the terms of either the GNU
   77.13 - * General Public License Version 2 only ("GPL") or the Common
   77.14 - * Development and Distribution License("CDDL") (collectively, the
   77.15 - * "License"). You may not use this file except in compliance with the
   77.16 - * License. You can obtain a copy of the License at
   77.17 - * http://www.netbeans.org/cddl-gplv2.html
   77.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   77.19 - * specific language governing permissions and limitations under the
   77.20 - * License.  When distributing the software, include this License Header
   77.21 - * Notice in each file and include the License file at
   77.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   77.23 - * particular file as subject to the "Classpath" exception as provided
   77.24 - * by Oracle in the GPL Version 2 section of the License file that
   77.25 - * accompanied this code. If applicable, add the following below the
   77.26 - * License Header, with the fields enclosed by brackets [] replaced by
   77.27 - * your own identifying information:
   77.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   77.29 - *
   77.30 - * Contributor(s):
   77.31 - *
   77.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   77.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   77.34 - *
   77.35 - * If you wish your version of this file to be governed by only the CDDL
   77.36 - * or only the GPL Version 2, indicate your decision by adding
   77.37 - * "[Contributor] elects to include this software in this distribution
   77.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   77.39 - * single choice of license, a recipient has the option to distribute
   77.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   77.41 - * to extend the choice of license to its licensees as provided above.
   77.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   77.43 - * Version 2 license, then the option applies only if the new code is
   77.44 - * made subject to such option by the copyright holder.
   77.45 - */
   77.46 -package org.apidesign.html.json.impl;
   77.47 -
   77.48 -import java.io.IOException;
   77.49 -import java.io.InputStream;
   77.50 -import java.util.HashMap;
   77.51 -import java.util.Map;
   77.52 -import net.java.html.BrwsrCtx;
   77.53 -import org.apidesign.html.context.spi.Contexts;
   77.54 -import org.apidesign.html.json.spi.FunctionBinding;
   77.55 -import org.apidesign.html.json.spi.JSONCall;
   77.56 -import org.apidesign.html.json.spi.PropertyBinding;
   77.57 -import org.apidesign.html.json.spi.Technology;
   77.58 -import org.apidesign.html.json.spi.Transfer;
   77.59 -import org.apidesign.html.json.spi.WSTransfer;
   77.60 -
   77.61 -/**
   77.62 - *
   77.63 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   77.64 - */
   77.65 -public final class JSON {
   77.66 -    private JSON() {
   77.67 -    }
   77.68 -
   77.69 -    static Technology<?> findTechnology(BrwsrCtx c) {
   77.70 -        Technology<?> t = Contexts.find(c, Technology.class);
   77.71 -        return t == null ? EmptyTech.EMPTY : t;
   77.72 -    }
   77.73 -
   77.74 -    static Transfer findTransfer(BrwsrCtx c) {
   77.75 -        Transfer t = Contexts.find(c, Transfer.class);
   77.76 -        return t == null ? EmptyTech.EMPTY : t;
   77.77 -    }
   77.78 -
   77.79 -    static WSTransfer<?> findWSTransfer(BrwsrCtx c) {
   77.80 -        WSTransfer<?> t = Contexts.find(c, WSTransfer.class);
   77.81 -        return t == null ? EmptyTech.EMPTY : t;
   77.82 -    }
   77.83 -    
   77.84 -    public static void runInBrowser(BrwsrCtx c, Runnable runnable) {
   77.85 -        findTechnology(c).runSafe(runnable);
   77.86 -    }
   77.87 -    
   77.88 -    public static void extract(BrwsrCtx c, Object value, String[] props, Object[] values) {
   77.89 -        Transfer t = findTransfer(c);
   77.90 -        t.extract(value, props, values);
   77.91 -    }
   77.92 -    
   77.93 -    private static Object getProperty(BrwsrCtx c, Object obj, String prop) {
   77.94 -        if (prop == null) return obj;
   77.95 -        
   77.96 -        String[] arr = { prop };
   77.97 -        Object[] val = { null };
   77.98 -        extract(c, obj, arr, val);
   77.99 -        return val[0];
  77.100 -    }
  77.101 -
  77.102 -    public static Object toJSON(Object value) {
  77.103 -        if (value == null) {
  77.104 -            return "null";
  77.105 -        }
  77.106 -        if (value instanceof Enum) {
  77.107 -            value = value.toString();
  77.108 -        }
  77.109 -        if (value instanceof String) {
  77.110 -            String s = (String)value;
  77.111 -            int len = s.length();
  77.112 -            StringBuilder sb = new StringBuilder(len + 10);
  77.113 -            sb.append('"');
  77.114 -            for (int i = 0; i < len; i++) {
  77.115 -                char ch = s.charAt(i);
  77.116 -                switch (ch) {
  77.117 -                    case '\"': sb.append("\\\""); break;
  77.118 -                    case '\n': sb.append("\\n"); break;
  77.119 -                    case '\r': sb.append("\\r"); break;
  77.120 -                    case '\t': sb.append("\\t"); break;
  77.121 -                    case '\\': sb.append("\\\\"); break;
  77.122 -                    default: sb.append(ch);
  77.123 -                }
  77.124 -            }
  77.125 -            sb.append('"');
  77.126 -            return sb.toString();
  77.127 -        }
  77.128 -        return value.toString();
  77.129 -    }
  77.130 -
  77.131 -    public static String toString(BrwsrCtx c, Object obj, String prop) {
  77.132 -        obj = getProperty(c, obj, prop);
  77.133 -        return obj instanceof String ? (String)obj : null;
  77.134 -    }
  77.135 -    public static Number toNumber(BrwsrCtx c, Object obj, String prop) {
  77.136 -        obj = getProperty(c, obj, prop);
  77.137 -        if (!(obj instanceof Number)) {
  77.138 -            obj = Double.NaN;
  77.139 -        }
  77.140 -        return (Number)obj;
  77.141 -    }
  77.142 -    public static <M> M toModel(BrwsrCtx c, Class<M> aClass, Object data, Object object) {
  77.143 -        Technology<?> t = findTechnology(c);
  77.144 -        Object o = t.toModel(aClass, data);
  77.145 -        return aClass.cast(o);
  77.146 -    }
  77.147 -    
  77.148 -    public static boolean isSame(int a, int b) {
  77.149 -        return a == b;
  77.150 -    }
  77.151 -    
  77.152 -    public static boolean isSame(double a, double b) {
  77.153 -        return a == b;
  77.154 -    }
  77.155 -    
  77.156 -    public static boolean isSame(Object a, Object b) {
  77.157 -        if (a == b) {
  77.158 -            return true;
  77.159 -        }
  77.160 -        if (a == null || b == null) {
  77.161 -            return false;
  77.162 -        }
  77.163 -        return a.equals(b);
  77.164 -    }
  77.165 -    
  77.166 -    public static int hashPlus(Object o, int h) {
  77.167 -        return o == null ? h : h ^ o.hashCode();
  77.168 -    }
  77.169 -
  77.170 -    public static <T> T extractValue(Class<T> type, Object val) {
  77.171 -        if (Number.class.isAssignableFrom(type)) {
  77.172 -            val = numberValue(val);
  77.173 -        }
  77.174 -        if (Boolean.class == type) {
  77.175 -            val = boolValue(val);
  77.176 -        }
  77.177 -        if (String.class == type) {
  77.178 -            val = stringValue(val);
  77.179 -        }
  77.180 -        if (Character.class == type) {
  77.181 -            val = charValue(val);
  77.182 -        }
  77.183 -        if (Integer.class == type) {
  77.184 -            val = val instanceof Number ? ((Number)val).intValue() : 0;
  77.185 -        }
  77.186 -        if (Long.class == type) {
  77.187 -            val = val instanceof Number  ? ((Number)val).longValue() : 0;
  77.188 -        }
  77.189 -        if (Short.class == type) {
  77.190 -            val = val instanceof Number ? ((Number)val).shortValue() : 0;
  77.191 -        }
  77.192 -        if (Byte.class == type) {
  77.193 -            val = val instanceof Number ? ((Number)val).byteValue() : 0;
  77.194 -        }        
  77.195 -        if (Double.class == type) {
  77.196 -            val = val instanceof Number ? ((Number)val).doubleValue() : Double.NaN;
  77.197 -        }
  77.198 -        if (Float.class == type) {
  77.199 -            val = val instanceof Number ? ((Number)val).floatValue() : Float.NaN;
  77.200 -        }
  77.201 -        return type.cast(val);
  77.202 -    }
  77.203 -    
  77.204 -    protected static boolean isNumeric(Object val) {
  77.205 -        return ((val instanceof Integer) || (val instanceof Long) || (val instanceof Short) || (val instanceof Byte));
  77.206 -    }
  77.207 -    
  77.208 -    public static String stringValue(Object val) {
  77.209 -        if (val instanceof Boolean) {
  77.210 -            return ((Boolean)val ? "true" : "false");
  77.211 -        }
  77.212 -        if (isNumeric(val)) {
  77.213 -            return Long.toString(((Number)val).longValue());
  77.214 -        }
  77.215 -        if (val instanceof Float) {
  77.216 -            return Float.toString((Float)val);
  77.217 -        }
  77.218 -        if (val instanceof Double) {
  77.219 -            return Double.toString((Double)val);
  77.220 -        }
  77.221 -        return (String)val;
  77.222 -    }
  77.223 -
  77.224 -    public static Number numberValue(Object val) {
  77.225 -        if (val instanceof String) {
  77.226 -            try {
  77.227 -                return Double.valueOf((String)val);
  77.228 -            } catch (NumberFormatException ex) {
  77.229 -                return Double.NaN;
  77.230 -            }
  77.231 -        }
  77.232 -        if (val instanceof Boolean) {
  77.233 -            return (Boolean)val ? 1 : 0;
  77.234 -        }
  77.235 -        return (Number)val;
  77.236 -    }
  77.237 -
  77.238 -    public static Character charValue(Object val) {
  77.239 -        if (val instanceof Number) {
  77.240 -            return Character.toChars(numberValue(val).intValue())[0];
  77.241 -        }
  77.242 -        if (val instanceof Boolean) {
  77.243 -            return (Boolean)val ? (char)1 : (char)0;
  77.244 -        }
  77.245 -        if (val instanceof String) {
  77.246 -            String s = (String)val;
  77.247 -            return s.isEmpty() ? (char)0 : s.charAt(0);
  77.248 -        }
  77.249 -        return (Character)val;
  77.250 -    }
  77.251 -    
  77.252 -    public static Boolean boolValue(Object val) {
  77.253 -        if (val instanceof String) {
  77.254 -            return Boolean.parseBoolean((String)val);
  77.255 -        }
  77.256 -        if (val instanceof Number) {
  77.257 -            return numberValue(val).doubleValue() != 0.0;
  77.258 -        }
  77.259 -    
  77.260 -        return Boolean.TRUE.equals(val);
  77.261 -    }
  77.262 -    
  77.263 -    public static void loadJSON(
  77.264 -        BrwsrCtx c, RcvrJSON callback,
  77.265 -        String urlBefore, String urlAfter, String method,
  77.266 -        Object data
  77.267 -    ) {
  77.268 -        JSONCall call = PropertyBindingAccessor.createCall(c, callback, urlBefore, urlAfter, method, data);
  77.269 -        Transfer t = findTransfer(c);
  77.270 -        t.loadJSON(call);
  77.271 -    }
  77.272 -    public static WS openWS(
  77.273 -        BrwsrCtx c, RcvrJSON r, String url, Object data
  77.274 -    ) {
  77.275 -        WS ws = WSImpl.create(findWSTransfer(c), r);
  77.276 -        ws.send(c, url, data);
  77.277 -        return ws;
  77.278 -    }
  77.279 -    
  77.280 -    public static abstract class WS {
  77.281 -        private WS() {
  77.282 -        }
  77.283 -        
  77.284 -        public abstract void send(BrwsrCtx ctx, String url, Object model);
  77.285 -    }
  77.286 -    
  77.287 -    private static final class WSImpl<Socket> extends WS {
  77.288 -
  77.289 -        private final WSTransfer<Socket> trans;
  77.290 -        private final RcvrJSON rcvr;
  77.291 -        private Socket socket;
  77.292 -        private String prevURL;
  77.293 -
  77.294 -        private WSImpl(WSTransfer<Socket> trans, RcvrJSON rcvr) {
  77.295 -            this.trans = trans;
  77.296 -            this.rcvr = rcvr;
  77.297 -        }
  77.298 -        
  77.299 -        static <Socket> WS create(WSTransfer<Socket> t, RcvrJSON r) {
  77.300 -            return new WSImpl<Socket>(t, r);
  77.301 -        }
  77.302 -
  77.303 -        @Override
  77.304 -        public void send(BrwsrCtx ctx, String url, Object data) {
  77.305 -            Socket s = socket;
  77.306 -            if (s == null) {
  77.307 -                if (data != null) {
  77.308 -                    throw new IllegalStateException("WebSocket is not opened yet. Call with null data, was: " + data);
  77.309 -                }
  77.310 -                JSONCall call = PropertyBindingAccessor.createCall(ctx, rcvr, url, null, "WebSocket", null);
  77.311 -                socket = trans.open(url, call);
  77.312 -                prevURL = url;
  77.313 -                return;
  77.314 -            }
  77.315 -            if (data == null) {
  77.316 -                trans.close(s);
  77.317 -                socket = null;
  77.318 -                return;
  77.319 -            }
  77.320 -            if (!prevURL.equals(url)) {
  77.321 -                throw new IllegalStateException(
  77.322 -                    "Can't call to different URL " + url + " was: " + prevURL + "!"
  77.323 -                    + " Close the socket by calling it will null data first!"
  77.324 -                );
  77.325 -            }
  77.326 -            JSONCall call = PropertyBindingAccessor.createCall(ctx, rcvr, prevURL, null, "WebSocket", data);
  77.327 -            trans.send(s, call);
  77.328 -        }
  77.329 -        
  77.330 -    }
  77.331 -    
  77.332 -    private static final Map<Class,FromJSON<?>> froms;
  77.333 -    static {
  77.334 -        Map<Class,FromJSON<?>> m = new HashMap<Class,FromJSON<?>>();
  77.335 -        froms = m;
  77.336 -    }
  77.337 -    public static void register(FromJSON<?> from) {
  77.338 -        froms.put(from.factoryFor(), from);
  77.339 -    }
  77.340 -    
  77.341 -    public static boolean isModel(Class<?> clazz) {
  77.342 -        return findFrom(clazz) != null; 
  77.343 -    }
  77.344 -    
  77.345 -    private static FromJSON<?> findFrom(Class<?> clazz) {
  77.346 -        for (int i = 0; i < 2; i++) {
  77.347 -            FromJSON<?> from = froms.get(clazz);
  77.348 -            if (from == null) {
  77.349 -                initClass(clazz);
  77.350 -            } else {
  77.351 -                return from;
  77.352 -            }
  77.353 -        }
  77.354 -        return null;
  77.355 -    }
  77.356 -    
  77.357 -    public static <Model> Model bindTo(Model model, BrwsrCtx c) {
  77.358 -        FromJSON<?> from = findFrom(model.getClass());
  77.359 -        if (from == null) {
  77.360 -            throw new IllegalArgumentException();
  77.361 -        }
  77.362 -        return (Model) from.cloneTo(model, c);
  77.363 -    }
  77.364 -    
  77.365 -    public static <T> T readStream(BrwsrCtx c, Class<T> modelClazz, InputStream data) 
  77.366 -    throws IOException {
  77.367 -        Transfer tr = findTransfer(c);
  77.368 -        return read(c, modelClazz, tr.toJSON((InputStream)data));
  77.369 -    }
  77.370 -    public static <T> T read(BrwsrCtx c, Class<T> modelClazz, Object data) {
  77.371 -        if (data == null) {
  77.372 -            return null;
  77.373 -        }
  77.374 -        if (modelClazz == String.class) {
  77.375 -            return modelClazz.cast(data.toString());
  77.376 -        }
  77.377 -        for (int i = 0; i < 2; i++) {
  77.378 -            FromJSON<?> from = froms.get(modelClazz);
  77.379 -            if (from == null) {
  77.380 -                initClass(modelClazz);
  77.381 -            } else {
  77.382 -                return modelClazz.cast(from.read(c, data));
  77.383 -            }
  77.384 -        }
  77.385 -        throw new NullPointerException();
  77.386 -    }
  77.387 -    static void initClass(Class<?> modelClazz) {
  77.388 -        try {
  77.389 -            // try to resolve the class
  77.390 -            ClassLoader l;
  77.391 -            try {
  77.392 -                l = modelClazz.getClassLoader();
  77.393 -            } catch (SecurityException ex) {
  77.394 -                l = null;
  77.395 -            }
  77.396 -            if (l != null) {
  77.397 -                Class.forName(modelClazz.getName(), true, l);
  77.398 -            }
  77.399 -            modelClazz.newInstance();
  77.400 -        } catch (Exception ex) {
  77.401 -            // ignore and try again
  77.402 -        }
  77.403 -    }
  77.404 -    
  77.405 -    private static final class EmptyTech
  77.406 -    implements Technology<Object>, Transfer, WSTransfer<Void> {
  77.407 -        private static final EmptyTech EMPTY = new EmptyTech();
  77.408 -
  77.409 -        @Override
  77.410 -        public Object wrapModel(Object model) {
  77.411 -            return model;
  77.412 -        }
  77.413 -
  77.414 -        @Override
  77.415 -        public void valueHasMutated(Object data, String propertyName) {
  77.416 -        }
  77.417 -
  77.418 -        @Override
  77.419 -        public void bind(PropertyBinding b, Object model, Object data) {
  77.420 -        }
  77.421 -
  77.422 -        @Override
  77.423 -        public void expose(FunctionBinding fb, Object model, Object d) {
  77.424 -        }
  77.425 -
  77.426 -        @Override
  77.427 -        public void applyBindings(Object data) {
  77.428 -        }
  77.429 -
  77.430 -        @Override
  77.431 -        public Object wrapArray(Object[] arr) {
  77.432 -            return arr;
  77.433 -        }
  77.434 -
  77.435 -        @Override
  77.436 -        public void extract(Object obj, String[] props, Object[] values) {
  77.437 -            for (int i = 0; i < values.length; i++) {
  77.438 -                values[i] = null;
  77.439 -            }
  77.440 -        }
  77.441 -
  77.442 -        @Override
  77.443 -        public void loadJSON(JSONCall call) {
  77.444 -            call.notifyError(new UnsupportedOperationException());
  77.445 -        }
  77.446 -
  77.447 -        @Override
  77.448 -        public <M> M toModel(Class<M> modelClass, Object data) {
  77.449 -            return modelClass.cast(data);
  77.450 -        }
  77.451 -
  77.452 -        @Override
  77.453 -        public Object toJSON(InputStream is) throws IOException {
  77.454 -            throw new IOException("Not supported");
  77.455 -        }
  77.456 -
  77.457 -        @Override
  77.458 -        public synchronized void runSafe(Runnable r) {
  77.459 -            r.run();
  77.460 -        }
  77.461 -
  77.462 -        @Override
  77.463 -        public Void open(String url, JSONCall onReply) {
  77.464 -            onReply.notifyError(new UnsupportedOperationException("WebSockets not supported!"));
  77.465 -            return null;
  77.466 -        }
  77.467 -
  77.468 -        @Override
  77.469 -        public void send(Void socket, JSONCall data) {
  77.470 -        }
  77.471 -
  77.472 -        @Override
  77.473 -        public void close(Void socket) {
  77.474 -        }
  77.475 -    }
  77.476 -    
  77.477 -}
    78.1 --- a/json/src/main/java/org/apidesign/html/json/impl/JSONList.java	Mon Dec 16 15:48:09 2013 +0100
    78.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    78.3 @@ -1,236 +0,0 @@
    78.4 -/**
    78.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    78.6 - *
    78.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    78.8 - *
    78.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   78.10 - * Other names may be trademarks of their respective owners.
   78.11 - *
   78.12 - * The contents of this file are subject to the terms of either the GNU
   78.13 - * General Public License Version 2 only ("GPL") or the Common
   78.14 - * Development and Distribution License("CDDL") (collectively, the
   78.15 - * "License"). You may not use this file except in compliance with the
   78.16 - * License. You can obtain a copy of the License at
   78.17 - * http://www.netbeans.org/cddl-gplv2.html
   78.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   78.19 - * specific language governing permissions and limitations under the
   78.20 - * License.  When distributing the software, include this License Header
   78.21 - * Notice in each file and include the License file at
   78.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   78.23 - * particular file as subject to the "Classpath" exception as provided
   78.24 - * by Oracle in the GPL Version 2 section of the License file that
   78.25 - * accompanied this code. If applicable, add the following below the
   78.26 - * License Header, with the fields enclosed by brackets [] replaced by
   78.27 - * your own identifying information:
   78.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   78.29 - *
   78.30 - * Contributor(s):
   78.31 - *
   78.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   78.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   78.34 - *
   78.35 - * If you wish your version of this file to be governed by only the CDDL
   78.36 - * or only the GPL Version 2, indicate your decision by adding
   78.37 - * "[Contributor] elects to include this software in this distribution
   78.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   78.39 - * single choice of license, a recipient has the option to distribute
   78.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   78.41 - * to extend the choice of license to its licensees as provided above.
   78.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   78.43 - * Version 2 license, then the option applies only if the new code is
   78.44 - * made subject to such option by the copyright holder.
   78.45 - */
   78.46 -package org.apidesign.html.json.impl;
   78.47 -
   78.48 -import java.lang.reflect.Array;
   78.49 -import java.util.ArrayList;
   78.50 -import java.util.Arrays;
   78.51 -import java.util.Collection;
   78.52 -import java.util.Iterator;
   78.53 -import java.util.List;
   78.54 -import net.java.html.BrwsrCtx;
   78.55 -
   78.56 -/**
   78.57 - *
   78.58 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   78.59 - */
   78.60 -public final class JSONList<T> extends ArrayList<T> {
   78.61 -    private final String name;
   78.62 -    private final String[] deps;
   78.63 -    private Bindings[] model;
   78.64 -    private Runnable onchange;
   78.65 -
   78.66 -    public JSONList(Bindings[] model, String name, String... deps) {
   78.67 -        assert model.length == 1;
   78.68 -        this.model = model;
   78.69 -        this.name = name;
   78.70 -        this.deps = deps;
   78.71 -    }
   78.72 -    
   78.73 -    public void init(T... values) {
   78.74 -        if (values == null || values.length == 0) {
   78.75 -            return;
   78.76 -        }
   78.77 -        if (this.model[0] != null || !isEmpty()) {
   78.78 -            throw new IllegalStateException();
   78.79 -        }
   78.80 -        super.addAll(Arrays.asList(values));
   78.81 -    }
   78.82 -    
   78.83 -    public void init(Object values) {
   78.84 -        int len;
   78.85 -        if (values == null || (len = Array.getLength(values)) == 0) {
   78.86 -            return;
   78.87 -        }
   78.88 -        if (this.model[0] != null || !isEmpty()) {
   78.89 -            throw new IllegalStateException();
   78.90 -        }
   78.91 -        for (int i = 0; i < len; i++) {
   78.92 -            Object data = Array.get(values, i);
   78.93 -            super.add((T)data);
   78.94 -        }
   78.95 -    }
   78.96 -    
   78.97 -    public JSONList<T> onChange(Runnable r) {
   78.98 -        if (this.onchange != null) {
   78.99 -            throw new IllegalStateException();
  78.100 -        }
  78.101 -        this.onchange = r;
  78.102 -        return this;
  78.103 -    }
  78.104 -
  78.105 -    @Override
  78.106 -    public boolean add(T e) {
  78.107 -        boolean ret = super.add(e);
  78.108 -        notifyChange();
  78.109 -        return ret;
  78.110 -    }
  78.111 -
  78.112 -    @Override
  78.113 -    public boolean addAll(Collection<? extends T> c) {
  78.114 -        boolean ret = super.addAll(c);
  78.115 -        notifyChange();
  78.116 -        return ret;
  78.117 -    }
  78.118 -
  78.119 -    @Override
  78.120 -    public boolean addAll(int index, Collection<? extends T> c) {
  78.121 -        boolean ret = super.addAll(index, c);
  78.122 -        notifyChange();
  78.123 -        return ret;
  78.124 -    }
  78.125 -
  78.126 -    @Override
  78.127 -    public boolean remove(Object o) {
  78.128 -        boolean ret = super.remove(o);
  78.129 -        notifyChange();
  78.130 -        return ret;
  78.131 -    }
  78.132 -
  78.133 -    @Override
  78.134 -    public void clear() {
  78.135 -        super.clear();
  78.136 -        notifyChange();
  78.137 -    }
  78.138 -
  78.139 -    @Override
  78.140 -    public boolean removeAll(Collection<?> c) {
  78.141 -        boolean ret = super.removeAll(c);
  78.142 -        notifyChange();
  78.143 -        return ret;
  78.144 -    }
  78.145 -
  78.146 -    @Override
  78.147 -    public boolean retainAll(Collection<?> c) {
  78.148 -        boolean ret = super.retainAll(c);
  78.149 -        notifyChange();
  78.150 -        return ret;
  78.151 -    }
  78.152 -
  78.153 -    @Override
  78.154 -    public T set(int index, T element) {
  78.155 -        T ret = super.set(index, element);
  78.156 -        notifyChange();
  78.157 -        return ret;
  78.158 -    }
  78.159 -
  78.160 -    @Override
  78.161 -    public void add(int index, T element) {
  78.162 -        super.add(index, element);
  78.163 -        notifyChange();
  78.164 -    }
  78.165 -
  78.166 -    @Override
  78.167 -    public T remove(int index) {
  78.168 -        T ret = super.remove(index);
  78.169 -        notifyChange();
  78.170 -        return ret;
  78.171 -    }
  78.172 -
  78.173 -    @Override
  78.174 -    public String toString() {
  78.175 -        Iterator<T> it = iterator();
  78.176 -        if (!it.hasNext()) {
  78.177 -            return "[]";
  78.178 -        }
  78.179 -        String sep = "";
  78.180 -        StringBuilder sb = new StringBuilder();
  78.181 -        sb.append('[');
  78.182 -        while (it.hasNext()) {
  78.183 -            T t = it.next();
  78.184 -            sb.append(sep);
  78.185 -            sb.append(JSON.toJSON(t));
  78.186 -            sep = ",";
  78.187 -        }
  78.188 -        sb.append(']');
  78.189 -        return sb.toString();
  78.190 -    }
  78.191 -
  78.192 -    private void notifyChange() {
  78.193 -        Bindings m = model[0];
  78.194 -        if (m != null) {
  78.195 -            m.valueHasMutated(name);
  78.196 -            for (String dependant : deps) {
  78.197 -                m.valueHasMutated(dependant);
  78.198 -            }
  78.199 -            Runnable r = onchange;
  78.200 -            if (r != null) {
  78.201 -                r.run();
  78.202 -            }
  78.203 -        }
  78.204 -    }
  78.205 -    
  78.206 -    public void cloneAll(BrwsrCtx c, Collection<T> other) {
  78.207 -        Boolean isModel = null;
  78.208 -        for (T t : other) {
  78.209 -            if (isModel == null) {
  78.210 -                isModel = JSON.isModel(t.getClass());
  78.211 -            }
  78.212 -            if (isModel) {
  78.213 -                add(JSON.bindTo(t, c));
  78.214 -            } else {
  78.215 -                add(t);
  78.216 -            }
  78.217 -        }
  78.218 -    }
  78.219 -
  78.220 -    @Override
  78.221 -    public JSONList clone() {
  78.222 -        throw new UnsupportedOperationException();
  78.223 -    }
  78.224 -
  78.225 -    static final Object koData(Collection<?> c, Bindings m) {
  78.226 -        Object[] arr = c.toArray(new Object[c.size()]);
  78.227 -        for (int i = 0; i < arr.length; i++) {
  78.228 -            Object r = WrapperObject.find(arr[i], m);
  78.229 -            if (r != null) {
  78.230 -                arr[i] = r;
  78.231 -            }
  78.232 -        }
  78.233 -        return m.wrapArray(arr);
  78.234 -    }
  78.235 -
  78.236 -    final Object koData() {
  78.237 -        return koData(this, model[0]);
  78.238 -    }
  78.239 -}
    79.1 --- a/json/src/main/java/org/apidesign/html/json/impl/ModelProcessor.java	Mon Dec 16 15:48:09 2013 +0100
    79.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    79.3 @@ -1,1767 +0,0 @@
    79.4 -/**
    79.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    79.6 - *
    79.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    79.8 - *
    79.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   79.10 - * Other names may be trademarks of their respective owners.
   79.11 - *
   79.12 - * The contents of this file are subject to the terms of either the GNU
   79.13 - * General Public License Version 2 only ("GPL") or the Common
   79.14 - * Development and Distribution License("CDDL") (collectively, the
   79.15 - * "License"). You may not use this file except in compliance with the
   79.16 - * License. You can obtain a copy of the License at
   79.17 - * http://www.netbeans.org/cddl-gplv2.html
   79.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   79.19 - * specific language governing permissions and limitations under the
   79.20 - * License.  When distributing the software, include this License Header
   79.21 - * Notice in each file and include the License file at
   79.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   79.23 - * particular file as subject to the "Classpath" exception as provided
   79.24 - * by Oracle in the GPL Version 2 section of the License file that
   79.25 - * accompanied this code. If applicable, add the following below the
   79.26 - * License Header, with the fields enclosed by brackets [] replaced by
   79.27 - * your own identifying information:
   79.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   79.29 - *
   79.30 - * Contributor(s):
   79.31 - *
   79.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   79.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   79.34 - *
   79.35 - * If you wish your version of this file to be governed by only the CDDL
   79.36 - * or only the GPL Version 2, indicate your decision by adding
   79.37 - * "[Contributor] elects to include this software in this distribution
   79.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   79.39 - * single choice of license, a recipient has the option to distribute
   79.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   79.41 - * to extend the choice of license to its licensees as provided above.
   79.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   79.43 - * Version 2 license, then the option applies only if the new code is
   79.44 - * made subject to such option by the copyright holder.
   79.45 - */
   79.46 -package org.apidesign.html.json.impl;
   79.47 -
   79.48 -import java.io.IOException;
   79.49 -import java.io.OutputStreamWriter;
   79.50 -import java.io.StringWriter;
   79.51 -import java.io.Writer;
   79.52 -import java.lang.annotation.AnnotationTypeMismatchException;
   79.53 -import java.lang.annotation.IncompleteAnnotationException;
   79.54 -import java.lang.reflect.Method;
   79.55 -import java.util.ArrayList;
   79.56 -import java.util.Arrays;
   79.57 -import java.util.Collection;
   79.58 -import java.util.Collections;
   79.59 -import java.util.HashMap;
   79.60 -import java.util.HashSet;
   79.61 -import java.util.LinkedHashSet;
   79.62 -import java.util.List;
   79.63 -import java.util.Map;
   79.64 -import java.util.ResourceBundle;
   79.65 -import java.util.Set;
   79.66 -import java.util.WeakHashMap;
   79.67 -import java.util.logging.Level;
   79.68 -import java.util.logging.Logger;
   79.69 -import javax.annotation.processing.AbstractProcessor;
   79.70 -import javax.annotation.processing.Completion;
   79.71 -import javax.annotation.processing.Completions;
   79.72 -import javax.annotation.processing.ProcessingEnvironment;
   79.73 -import javax.annotation.processing.Processor;
   79.74 -import javax.annotation.processing.RoundEnvironment;
   79.75 -import javax.annotation.processing.SupportedAnnotationTypes;
   79.76 -import javax.annotation.processing.SupportedSourceVersion;
   79.77 -import javax.lang.model.SourceVersion;
   79.78 -import javax.lang.model.element.AnnotationMirror;
   79.79 -import javax.lang.model.element.AnnotationValue;
   79.80 -import javax.lang.model.element.Element;
   79.81 -import javax.lang.model.element.ElementKind;
   79.82 -import javax.lang.model.element.ExecutableElement;
   79.83 -import javax.lang.model.element.Modifier;
   79.84 -import javax.lang.model.element.PackageElement;
   79.85 -import javax.lang.model.element.TypeElement;
   79.86 -import javax.lang.model.element.VariableElement;
   79.87 -import javax.lang.model.type.ArrayType;
   79.88 -import javax.lang.model.type.DeclaredType;
   79.89 -import javax.lang.model.type.MirroredTypeException;
   79.90 -import javax.lang.model.type.TypeKind;
   79.91 -import javax.lang.model.type.TypeMirror;
   79.92 -import javax.lang.model.util.Elements;
   79.93 -import javax.lang.model.util.Types;
   79.94 -import javax.tools.Diagnostic;
   79.95 -import javax.tools.FileObject;
   79.96 -import net.java.html.json.ComputedProperty;
   79.97 -import net.java.html.json.Model;
   79.98 -import net.java.html.json.Function;
   79.99 -import net.java.html.json.ModelOperation;
  79.100 -import net.java.html.json.OnPropertyChange;
  79.101 -import net.java.html.json.OnReceive;
  79.102 -import net.java.html.json.Property;
  79.103 -import org.openide.util.lookup.ServiceProvider;
  79.104 -
  79.105 -/** Annotation processor to process {@link Model @Model} annotations and
  79.106 - * generate appropriate model classes.
  79.107 - *
  79.108 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  79.109 - */
  79.110 -@ServiceProvider(service=Processor.class)
  79.111 -@SupportedSourceVersion(SourceVersion.RELEASE_6)
  79.112 -@SupportedAnnotationTypes({
  79.113 -    "net.java.html.json.Model",
  79.114 -    "net.java.html.json.ModelOperation",
  79.115 -    "net.java.html.json.Function",
  79.116 -    "net.java.html.json.OnReceive",
  79.117 -    "net.java.html.json.OnPropertyChange",
  79.118 -    "net.java.html.json.ComputedProperty",
  79.119 -    "net.java.html.json.Property"
  79.120 -})
  79.121 -public final class ModelProcessor extends AbstractProcessor {
  79.122 -    private static final Logger LOG = Logger.getLogger(ModelProcessor.class.getName());
  79.123 -    private final Map<Element,String> models = new WeakHashMap<Element,String>();
  79.124 -    private final Map<Element,Prprt[]> verify = new WeakHashMap<Element,Prprt[]>();
  79.125 -    @Override
  79.126 -    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
  79.127 -        boolean ok = true;
  79.128 -        for (Element e : roundEnv.getElementsAnnotatedWith(Model.class)) {
  79.129 -            if (!processModel(e)) {
  79.130 -                ok = false;
  79.131 -            }
  79.132 -        }
  79.133 -        if (roundEnv.processingOver()) {
  79.134 -            models.clear();
  79.135 -            for (Map.Entry<Element, Prprt[]> entry : verify.entrySet()) {
  79.136 -                TypeElement te = (TypeElement)entry.getKey();
  79.137 -                String fqn = processingEnv.getElementUtils().getBinaryName(te).toString();
  79.138 -                Element finalElem = processingEnv.getElementUtils().getTypeElement(fqn);
  79.139 -                if (finalElem == null) {
  79.140 -                    continue;
  79.141 -                }
  79.142 -                Prprt[] props;
  79.143 -                Model m = finalElem.getAnnotation(Model.class);
  79.144 -                if (m == null) {
  79.145 -                    continue;
  79.146 -                }
  79.147 -                props = Prprt.wrap(processingEnv, finalElem, m.properties());
  79.148 -                for (Prprt p : props) {
  79.149 -                    boolean[] isModel = { false };
  79.150 -                    boolean[] isEnum = { false };
  79.151 -                    boolean[] isPrimitive = { false };
  79.152 -                    String t = checkType(p, isModel, isEnum, isPrimitive);
  79.153 -                    if (isEnum[0]) {
  79.154 -                        continue;
  79.155 -                    }
  79.156 -                    if (isPrimitive[0]) {
  79.157 -                        continue;
  79.158 -                    }
  79.159 -                    if (isModel[0]) {
  79.160 -                        continue;
  79.161 -                    }
  79.162 -                    if ("java.lang.String".equals(t)) {
  79.163 -                        continue;
  79.164 -                    }
  79.165 -                    error("The type " + t + " should be defined by @Model annotation", entry.getKey());
  79.166 -                }
  79.167 -            }
  79.168 -            verify.clear();
  79.169 -        }
  79.170 -        return ok;
  79.171 -    }
  79.172 -
  79.173 -    private void error(String msg, Element e) {
  79.174 -        processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e);
  79.175 -    }
  79.176 -    
  79.177 -    private boolean processModel(Element e) {
  79.178 -        boolean ok = true;
  79.179 -        Model m = e.getAnnotation(Model.class);
  79.180 -        if (m == null) {
  79.181 -            return true;
  79.182 -        }
  79.183 -        String pkg = findPkgName(e);
  79.184 -        Writer w;
  79.185 -        String className = m.className();
  79.186 -        models.put(e, className);
  79.187 -        try {
  79.188 -            StringWriter body = new StringWriter();
  79.189 -            List<String> propsGetSet = new ArrayList<String>();
  79.190 -            List<String> functions = new ArrayList<String>();
  79.191 -            Map<String, Collection<String>> propsDeps = new HashMap<String, Collection<String>>();
  79.192 -            Map<String, Collection<String>> functionDeps = new HashMap<String, Collection<String>>();
  79.193 -            Prprt[] props = createProps(e, m.properties());
  79.194 -            
  79.195 -            if (!generateComputedProperties(body, props, e.getEnclosedElements(), propsGetSet, propsDeps)) {
  79.196 -                ok = false;
  79.197 -            }
  79.198 -            if (!generateOnChange(e, propsDeps, props, className, functionDeps)) {
  79.199 -                ok = false;
  79.200 -            }
  79.201 -            if (!generateProperties(e, body, props, propsGetSet, propsDeps, functionDeps)) {
  79.202 -                ok = false;
  79.203 -            }
  79.204 -            if (!generateFunctions(e, body, className, e.getEnclosedElements(), functions)) {
  79.205 -                ok = false;
  79.206 -            }
  79.207 -            if (!generateReceive(e, body, className, e.getEnclosedElements(), functions)) {
  79.208 -                ok = false;
  79.209 -            }
  79.210 -            if (!generateOperation(e, body, className, e.getEnclosedElements())) {
  79.211 -                ok = false;
  79.212 -            }
  79.213 -            FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e);
  79.214 -            w = new OutputStreamWriter(java.openOutputStream());
  79.215 -            try {
  79.216 -                w.append("package " + pkg + ";\n");
  79.217 -                w.append("import net.java.html.json.*;\n");
  79.218 -                w.append("public final class ").append(className).append(" implements Cloneable {\n");
  79.219 -                w.append("  private boolean locked;\n");
  79.220 -                w.append("  private net.java.html.BrwsrCtx context;\n");
  79.221 -                w.append("  private org.apidesign.html.json.impl.Bindings[] ko = { null };\n");
  79.222 -                w.append(body.toString());
  79.223 -                w.append("  private static Class<" + inPckName(e) + "> modelFor() { return null; }\n");
  79.224 -                w.append("  private ").append(className).append("(net.java.html.BrwsrCtx context) {\n");
  79.225 -                w.append("    this.context = context;\n");
  79.226 -                w.append("  };\n");
  79.227 -                w.append("  public ").append(className).append("() {\n");
  79.228 -                w.append("    this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n");
  79.229 -                for (Prprt p : props) {
  79.230 -                    if (p.array()) {
  79.231 -                        continue;
  79.232 -                    }
  79.233 -                    boolean[] isModel = {false};
  79.234 -                    boolean[] isEnum = {false};
  79.235 -                    boolean isPrimitive[] = {false};
  79.236 -                    String tn = checkType(p, isModel, isEnum, isPrimitive);
  79.237 -                    if (isModel[0]) {
  79.238 -                        w.write("    prop_" + p.name() + " = new " + tn + "();\n");
  79.239 -                    }
  79.240 -                }
  79.241 -                w.append("  };\n");
  79.242 -                if (props.length > 0) {
  79.243 -                    w.append("  public ").append(className).append("(");
  79.244 -                    Prprt firstArray = null;
  79.245 -                    String sep = "";
  79.246 -                    for (Prprt p : props) {
  79.247 -                        if (p.array()) {
  79.248 -                            if (firstArray == null) {
  79.249 -                                firstArray = p;
  79.250 -                            }
  79.251 -                            continue;
  79.252 -                        }
  79.253 -                        String tn = typeName(e, p);
  79.254 -                        w.write(sep);
  79.255 -                        w.write(tn);
  79.256 -                        w.write(" " + p.name());
  79.257 -                        sep = ", ";
  79.258 -                    }
  79.259 -                    if (firstArray != null) {
  79.260 -                        String tn;
  79.261 -                        boolean[] isModel = {false};
  79.262 -                        boolean[] isEnum = {false};
  79.263 -                        boolean isPrimitive[] = {false};
  79.264 -                        tn = checkType(firstArray, isModel, isEnum, isPrimitive);
  79.265 -                        w.write(sep);
  79.266 -                        w.write(tn);
  79.267 -                        w.write("... " + firstArray.name());
  79.268 -                    }
  79.269 -                    w.append(") {\n");
  79.270 -                    w.append("    this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n");
  79.271 -                    for (Prprt p : props) {
  79.272 -                        if (p.array()) {
  79.273 -                            continue;
  79.274 -                        }
  79.275 -                        w.write("    this.prop_" + p.name() + " = " + p.name() + ";\n");
  79.276 -                    }
  79.277 -                    if (firstArray != null) {
  79.278 -                        w.write("    this.prop_" + firstArray.name() + ".init(" + firstArray.name() + ");\n");
  79.279 -                    }
  79.280 -                    w.append("  };\n");
  79.281 -                }
  79.282 -                w.append("  private org.apidesign.html.json.impl.Bindings intKnckt() {\n");
  79.283 -                w.append("    if (ko[0] != null) return ko[0];\n");
  79.284 -                w.append("    ko[0] = org.apidesign.html.json.impl.Bindings.apply(context, this);\n");
  79.285 -                {
  79.286 -                    w.append("    org.apidesign.html.json.spi.PropertyBinding[] propArr = {\n");
  79.287 -                    for (int i = 0; i < propsGetSet.size(); i += 5) {
  79.288 -                        w.append("      ko[0].registerProperty(\"").append(propsGetSet.get(i)).append("\", this, new P(");
  79.289 -                        w.append((i / 5) + "), " + (propsGetSet.get(i + 2) == null) + "),\n");
  79.290 -                    }
  79.291 -                    w.append("    };\n");
  79.292 -                }
  79.293 -                {
  79.294 -                    w.append("    org.apidesign.html.json.spi.FunctionBinding[] funcArr = {\n");
  79.295 -                    for (int i = 0; i < functions.size(); i += 2) {
  79.296 -                        w.append("      ko[0].registerFunction(\"").append(functions.get(i)).append("\", this, new P(");
  79.297 -                        w.append((i / 2) + ")),\n");
  79.298 -                    }
  79.299 -                    w.append("    };\n");
  79.300 -                }
  79.301 -                w.append("    ko[0].finish(this, propArr, funcArr);\n");
  79.302 -                w.append("    return ko[0];\n");
  79.303 -                w.append("  };\n");
  79.304 -                w.append("  private static final class P implements org.apidesign.html.json.impl.SetAndGet<" + className + ">,\n");
  79.305 -                w.append("  org.apidesign.html.json.impl.Callback<" + className + ">,\n");
  79.306 -                w.append("  org.apidesign.html.json.impl.FromJSON<" + className + "> {\n");
  79.307 -                w.append("    private final int type;\n");
  79.308 -                w.append("    P(int t) { type = t; };\n");
  79.309 -                w.append("    public void setValue(" + className + " data, Object value) {\n");
  79.310 -                w.append("      switch (type) {\n");
  79.311 -                for (int i = 0; i < propsGetSet.size(); i += 5) {
  79.312 -                    final String set = propsGetSet.get(i + 2);
  79.313 -                    String tn = propsGetSet.get(i + 4);
  79.314 -                    String btn = findBoxedType(tn);
  79.315 -                    if (btn != null) {
  79.316 -                        tn = btn;
  79.317 -                    }
  79.318 -                    if (set != null) {
  79.319 -                        w.append("        case " + (i / 5) + ": data." + strip(set) + "(org.apidesign.html.json.impl.JSON.extractValue(" + tn + ".class, value)); return;\n");
  79.320 -                    }
  79.321 -                }
  79.322 -                w.append("      }\n");
  79.323 -                w.append("    }\n");
  79.324 -                w.append("    public Object getValue(" + className + " data) {\n");
  79.325 -                w.append("      switch (type) {\n");
  79.326 -                for (int i = 0; i < propsGetSet.size(); i += 5) {
  79.327 -                    final String get = propsGetSet.get(i + 1);
  79.328 -                    if (get != null) {
  79.329 -                        w.append("        case " + (i / 5) + ": return data." + strip(get) + "();\n");
  79.330 -                    }
  79.331 -                }
  79.332 -                w.append("      }\n");
  79.333 -                w.append("      throw new UnsupportedOperationException();\n");
  79.334 -                w.append("    }\n");
  79.335 -                w.append("    public void call(" + className + " model, Object data, Object ev) {\n");
  79.336 -                w.append("      switch (type) {\n");
  79.337 -                for (int i = 0; i < functions.size(); i += 2) {
  79.338 -                    final String name = functions.get(i);
  79.339 -                    w.append("        case " + (i / 2) + ": model." + name + "(data, ev); return;\n");
  79.340 -                }
  79.341 -                w.append("      }\n");
  79.342 -                w.append("      throw new UnsupportedOperationException();\n");
  79.343 -                w.append("    }\n");
  79.344 -                w.append("    public Class<" + className + "> factoryFor() { return " + className + ".class; }\n");
  79.345 -                w.append("    public " + className + " read(net.java.html.BrwsrCtx c, Object json) { return new " + className + "(c, json); }\n");
  79.346 -                w.append("    public " + className + " cloneTo(Object o, net.java.html.BrwsrCtx c) { return ((" + className + ")o).clone(c); }\n");
  79.347 -                w.append("  }\n");
  79.348 -                w.append("  static { org.apidesign.html.json.impl.JSON.register(new P(0)); }\n");
  79.349 -                w.append("  private ").append(className).append("(net.java.html.BrwsrCtx c, Object json) {\n");
  79.350 -                w.append("    this.context = c;\n");
  79.351 -                int values = 0;
  79.352 -                for (int i = 0; i < propsGetSet.size(); i += 5) {
  79.353 -                    Prprt p = findPrprt(props, propsGetSet.get(i));
  79.354 -                    if (p == null) {
  79.355 -                        continue;
  79.356 -                    }
  79.357 -                    values++;
  79.358 -                }
  79.359 -                w.append("    Object[] ret = new Object[" + values + "];\n");
  79.360 -                w.append("    org.apidesign.html.json.impl.JSON.extract(context, json, new String[] {\n");
  79.361 -                for (int i = 0; i < propsGetSet.size(); i += 5) {
  79.362 -                    Prprt p = findPrprt(props, propsGetSet.get(i));
  79.363 -                    if (p == null) {
  79.364 -                        continue;
  79.365 -                    }
  79.366 -                    w.append("      \"").append(propsGetSet.get(i)).append("\",\n");
  79.367 -                }
  79.368 -                w.append("    }, ret);\n");
  79.369 -                for (int i = 0, cnt = 0, prop = 0; i < propsGetSet.size(); i += 5) {
  79.370 -                    final String pn = propsGetSet.get(i);
  79.371 -                    Prprt p = findPrprt(props, pn);
  79.372 -                    if (p == null) {
  79.373 -                        continue;
  79.374 -                    }
  79.375 -                    boolean[] isModel = { false };
  79.376 -                    boolean[] isEnum = { false };
  79.377 -                    boolean isPrimitive[] = { false };
  79.378 -                    String type = checkType(props[prop++], isModel, isEnum, isPrimitive);
  79.379 -                    if (p.array()) {
  79.380 -                        w.append("    if (ret[" + cnt + "] instanceof Object[]) {\n");
  79.381 -                        w.append("      for (Object e : ((Object[])ret[" + cnt + "])) {\n");
  79.382 -                        if (isModel[0]) {
  79.383 -                            w.append("        this.prop_").append(pn).append(".add(org.apidesign.html.json.impl.JSON.read");
  79.384 -                            w.append("(c, " + type + ".class, e));\n");
  79.385 -                        } else if (isEnum[0]) {
  79.386 -                            w.append("        this.prop_").append(pn);
  79.387 -                            w.append(".add(e == null ? null : ");
  79.388 -                            w.append(type).append(".valueOf(org.apidesign.html.json.impl.JSON.stringValue(e)));\n");
  79.389 -                        } else {
  79.390 -                            if (isPrimitive(type)) {
  79.391 -                                w.append("        this.prop_").append(pn).append(".add(org.apidesign.html.json.impl.JSON.numberValue(e).");
  79.392 -                                w.append(type).append("Value());\n");
  79.393 -                            } else {
  79.394 -                                w.append("        this.prop_").append(pn).append(".add((");
  79.395 -                                w.append(type).append(")e);\n");
  79.396 -                            }
  79.397 -                        }
  79.398 -                        w.append("      }\n");
  79.399 -                        w.append("    }\n");
  79.400 -                    } else {
  79.401 -                        if (isEnum[0]) {
  79.402 -                            w.append("    try {\n");
  79.403 -                            w.append("    this.prop_").append(pn);
  79.404 -                            w.append(" = ret[" + cnt + "] == null ? null : ");
  79.405 -                            w.append(type).append(".valueOf(org.apidesign.html.json.impl.JSON.stringValue(ret[" + cnt + "]));\n");
  79.406 -                            w.append("    } catch (IllegalArgumentException ex) {\n");
  79.407 -                            w.append("      ex.printStackTrace();\n");
  79.408 -                            w.append("    }\n");
  79.409 -                        } else if (isPrimitive(type)) {
  79.410 -                            w.append("    this.prop_").append(pn);
  79.411 -                            w.append(" = ret[" + cnt + "] == null ? ");
  79.412 -                            if ("char".equals(type)) {
  79.413 -                                w.append("0 : (org.apidesign.html.json.impl.JSON.charValue(");
  79.414 -                            } else if ("boolean".equals(type)) {
  79.415 -                                w.append("false : (org.apidesign.html.json.impl.JSON.boolValue(");
  79.416 -                            } else {
  79.417 -                                w.append("0 : (org.apidesign.html.json.impl.JSON.numberValue(");
  79.418 -                            }
  79.419 -                            w.append("ret[" + cnt + "])).");
  79.420 -                            w.append(type).append("Value();\n");
  79.421 -                        } else if (isModel[0]) {
  79.422 -                            w.append("    this.prop_").append(pn).append(" = org.apidesign.html.json.impl.JSON.read");
  79.423 -                            w.append("(c, " + type + ".class, ");
  79.424 -                            w.append("ret[" + cnt + "]);\n");
  79.425 -                        }else {
  79.426 -                            w.append("    this.prop_").append(pn);
  79.427 -                            w.append(" = (").append(type).append(')');
  79.428 -                            w.append("ret[" + cnt + "];\n");
  79.429 -                        }
  79.430 -                    }
  79.431 -                    cnt++;
  79.432 -                }
  79.433 -                w.append("  };\n");
  79.434 -                writeToString(props, w);
  79.435 -                writeClone(className, props, w);
  79.436 -                w.write("  /** Activates this model instance in the current {@link \n"
  79.437 -                    + "net.java.html.json.Models#bind(java.lang.Object, net.java.html.BrwsrCtx) browser context}. \n"
  79.438 -                    + "In case of using Knockout technology, this means to \n"
  79.439 -                    + "bind JSON like data in this model instance with Knockout tags in \n"
  79.440 -                    + "the surrounding HTML page.\n"
  79.441 -                    + "*/\n"
  79.442 -                );
  79.443 -                w.write("  public " + className + " applyBindings() {\n");
  79.444 -                w.write("    intKnckt().applyBindings();\n");
  79.445 -                w.write("    return this;\n");
  79.446 -                w.write("  }\n");
  79.447 -                w.write("  public boolean equals(Object o) {\n");
  79.448 -                w.write("    if (o == this) return true;\n");
  79.449 -                w.write("    if (o instanceof org.apidesign.html.json.impl.WrapperObject) {\n");
  79.450 -                w.write("      ((org.apidesign.html.json.impl.WrapperObject)o).setRealObject(intKnckt().koData());\n");
  79.451 -                w.write("      return false;\n");
  79.452 -                w.write("    }\n");
  79.453 -                w.write("    if (!(o instanceof " + className + ")) return false;\n");
  79.454 -                w.write("    " + className + " p = (" + className + ")o;\n");
  79.455 -                for (Prprt p : props) {
  79.456 -                    w.write("    if (!org.apidesign.html.json.impl.JSON.isSame(prop_" + p.name() + ", p.prop_" + p.name() + ")) return false;\n");
  79.457 -                }
  79.458 -                w.write("    return true;\n");
  79.459 -                w.write("  }\n");
  79.460 -                w.write("  public int hashCode() {\n");
  79.461 -                w.write("    int h = " + className + ".class.getName().hashCode();\n");
  79.462 -                for (Prprt p : props) {
  79.463 -                    w.write("    h = org.apidesign.html.json.impl.JSON.hashPlus(prop_" + p.name() + ", h);\n");
  79.464 -                }
  79.465 -                w.write("    return h;\n");
  79.466 -                w.write("  }\n");
  79.467 -                w.write("}\n");
  79.468 -            } finally {
  79.469 -                w.close();
  79.470 -            }
  79.471 -        } catch (IOException ex) {
  79.472 -            error("Can't create " + className + ".java", e);
  79.473 -            return false;
  79.474 -        }
  79.475 -        return ok;
  79.476 -    }
  79.477 -    
  79.478 -    private boolean generateProperties(
  79.479 -        Element where,
  79.480 -        Writer w, Prprt[] properties,
  79.481 -        Collection<String> props, 
  79.482 -        Map<String,Collection<String>> deps,
  79.483 -        Map<String,Collection<String>> functionDeps
  79.484 -    ) throws IOException {
  79.485 -        boolean ok = true;
  79.486 -        for (Prprt p : properties) {
  79.487 -            final String tn;
  79.488 -            tn = typeName(where, p);
  79.489 -            String[] gs = toGetSet(p.name(), tn, p.array());
  79.490 -            String castTo;
  79.491 -            
  79.492 -            if (p.array()) {
  79.493 -                w.write("  private org.apidesign.html.json.impl.JSONList<" + tn + "> prop_" + p.name() + " = new org.apidesign.html.json.impl.JSONList<" + tn + ">(ko, \""
  79.494 -                    + p.name() + "\"");
  79.495 -                Collection<String> dependants = deps.get(p.name());
  79.496 -                if (dependants != null) {
  79.497 -                    for (String depProp : dependants) {
  79.498 -                        w.write(", ");
  79.499 -                        w.write('\"');
  79.500 -                        w.write(depProp);
  79.501 -                        w.write('\"');
  79.502 -                    }
  79.503 -                }
  79.504 -                w.write(")");
  79.505 -                
  79.506 -                dependants = functionDeps.get(p.name());
  79.507 -                if (dependants != null) {
  79.508 -                    w.write(".onChange(new Runnable() { public void run() {\n");
  79.509 -                    for (String call : dependants) {
  79.510 -                        w.append("  ").append(call);
  79.511 -                    }
  79.512 -                    w.write("  }})");
  79.513 -                }
  79.514 -                w.write(";\n");
  79.515 -            
  79.516 -                castTo = "java.util.List";
  79.517 -                w.write("  public java.util.List<" + tn + "> " + gs[0] + "() {\n");
  79.518 -                w.write("    if (locked) throw new IllegalStateException();\n");
  79.519 -                w.write("    return prop_" + p.name() + ";\n");
  79.520 -                w.write("  }\n");
  79.521 -            } else {
  79.522 -                castTo = tn;
  79.523 -                w.write("  private " + tn + " prop_" + p.name() + ";\n");
  79.524 -                w.write("  public " + tn + " " + gs[0] + "() {\n");
  79.525 -                w.write("    if (locked) throw new IllegalStateException();\n");
  79.526 -                w.write("    return prop_" + p.name() + ";\n");
  79.527 -                w.write("  }\n");
  79.528 -                w.write("  public void " + gs[1] + "(" + tn + " v) {\n");
  79.529 -                w.write("    if (locked) throw new IllegalStateException();\n");
  79.530 -                w.write("    if (org.apidesign.html.json.impl.JSON.isSame(prop_" + p.name() + ", v)) return;\n");
  79.531 -                w.write("    prop_" + p.name() + " = v;\n");
  79.532 -                w.write("    org.apidesign.html.json.impl.Bindings b = ko[0];\n");
  79.533 -                w.write("    if (b != null) {\n");
  79.534 -                w.write("      b.valueHasMutated(\"" + p.name() + "\");\n");
  79.535 -                Collection<String> dependants = deps.get(p.name());
  79.536 -                if (dependants != null) {
  79.537 -                    for (String depProp : dependants) {
  79.538 -                        w.write("      b.valueHasMutated(\"" + depProp + "\");\n");
  79.539 -                    }
  79.540 -                }
  79.541 -                w.write("    }\n");
  79.542 -                dependants = functionDeps.get(p.name());
  79.543 -                if (dependants != null) {
  79.544 -                    for (String call : dependants) {
  79.545 -                        w.append("  ").append(call);
  79.546 -                    }
  79.547 -                }
  79.548 -                w.write("  }\n");
  79.549 -            }
  79.550 -            
  79.551 -            props.add(p.name());
  79.552 -            props.add(gs[2]);
  79.553 -            props.add(gs[3]);
  79.554 -            props.add(gs[0]);
  79.555 -            props.add(castTo);
  79.556 -        }
  79.557 -        return ok;
  79.558 -    }
  79.559 -
  79.560 -    private boolean generateComputedProperties(
  79.561 -        Writer w, Prprt[] fixedProps,
  79.562 -        Collection<? extends Element> arr, Collection<String> props,
  79.563 -        Map<String,Collection<String>> deps
  79.564 -    ) throws IOException {
  79.565 -        boolean ok = true;
  79.566 -        for (Element e : arr) {
  79.567 -            if (e.getKind() != ElementKind.METHOD) {
  79.568 -                continue;
  79.569 -            }
  79.570 -            if (e.getAnnotation(ComputedProperty.class) == null) {
  79.571 -                continue;
  79.572 -            }
  79.573 -            if (!e.getModifiers().contains(Modifier.STATIC)) {
  79.574 -                error("Method " + e.getSimpleName() + " has to be static when annotated by @ComputedProperty", e);
  79.575 -                ok = false;
  79.576 -                continue;
  79.577 -            }
  79.578 -            ExecutableElement ee = (ExecutableElement)e;
  79.579 -            final TypeMirror rt = ee.getReturnType();
  79.580 -            final Types tu = processingEnv.getTypeUtils();
  79.581 -            TypeMirror ert = tu.erasure(rt);
  79.582 -            String tn = fqn(ert, ee);
  79.583 -            boolean array = false;
  79.584 -            final TypeMirror toCheck;
  79.585 -            if (tn.equals("java.util.List")) {
  79.586 -                array = true;
  79.587 -                toCheck = ((DeclaredType)rt).getTypeArguments().get(0);
  79.588 -            } else {
  79.589 -                toCheck = rt;
  79.590 -            }
  79.591 -            
  79.592 -            final String sn = ee.getSimpleName().toString();
  79.593 -            
  79.594 -            if (toCheck.getKind().isPrimitive()) {
  79.595 -                // OK
  79.596 -            } else {
  79.597 -                TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
  79.598 -                TypeMirror enumType = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType();
  79.599 -
  79.600 -                if (tu.isSubtype(toCheck, stringType)) {
  79.601 -                    // OK
  79.602 -                } else if (tu.isSubtype(tu.erasure(toCheck), tu.erasure(enumType))) {
  79.603 -                    // OK
  79.604 -                } else if (isModel(toCheck)) {
  79.605 -                    // OK
  79.606 -                } else {
  79.607 -                    ok = false;
  79.608 -                    error(sn + " cannot return " + toCheck, e);
  79.609 -                }
  79.610 -            }
  79.611 -            
  79.612 -            String[] gs = toGetSet(sn, tn, array);
  79.613 -            
  79.614 -            w.write("  public " + tn + " " + gs[0] + "() {\n");
  79.615 -            w.write("    if (locked) throw new IllegalStateException();\n");
  79.616 -            int arg = 0;
  79.617 -            for (VariableElement pe : ee.getParameters()) {
  79.618 -                final String dn = pe.getSimpleName().toString();
  79.619 -                
  79.620 -                if (!verifyPropName(pe, dn, fixedProps)) {
  79.621 -                    ok = false;
  79.622 -                }
  79.623 -                
  79.624 -                final String dt = fqn(pe.asType(), ee);
  79.625 -                String[] call = toGetSet(dn, dt, false);
  79.626 -                w.write("    " + dt + " arg" + (++arg) + " = ");
  79.627 -                w.write(call[0] + "();\n");
  79.628 -                
  79.629 -                Collection<String> depends = deps.get(dn);
  79.630 -                if (depends == null) {
  79.631 -                    depends = new LinkedHashSet<String>();
  79.632 -                    deps.put(dn, depends);
  79.633 -                }
  79.634 -                depends.add(sn);
  79.635 -            }
  79.636 -            w.write("    try {\n");
  79.637 -            w.write("      locked = true;\n");
  79.638 -            w.write("      return " + fqn(ee.getEnclosingElement().asType(), ee) + '.' + e.getSimpleName() + "(");
  79.639 -            String sep = "";
  79.640 -            for (int i = 1; i <= arg; i++) {
  79.641 -                w.write(sep);
  79.642 -                w.write("arg" + i);
  79.643 -                sep = ", ";
  79.644 -            }
  79.645 -            w.write(");\n");
  79.646 -            w.write("    } finally {\n");
  79.647 -            w.write("      locked = false;\n");
  79.648 -            w.write("    }\n");
  79.649 -            w.write("  }\n");
  79.650 -
  79.651 -            props.add(e.getSimpleName().toString());
  79.652 -            props.add(gs[2]);
  79.653 -            props.add(null);
  79.654 -            props.add(gs[0]);
  79.655 -            props.add(tn);
  79.656 -        }
  79.657 -        
  79.658 -        return ok;
  79.659 -    }
  79.660 -
  79.661 -    private static String[] toGetSet(String name, String type, boolean array) {
  79.662 -        String n = Character.toUpperCase(name.charAt(0)) + name.substring(1);
  79.663 -        String bck2brwsrType = "L" + type.replace('.', '_') + "_2";
  79.664 -        if ("int".equals(type)) {
  79.665 -            bck2brwsrType = "I";
  79.666 -        }
  79.667 -        if ("double".equals(type)) {
  79.668 -            bck2brwsrType = "D";
  79.669 -        }
  79.670 -        String pref = "get";
  79.671 -        if ("boolean".equals(type)) {
  79.672 -            pref = "is";
  79.673 -            bck2brwsrType = "Z";
  79.674 -        }
  79.675 -        final String nu = n.replace('.', '_');
  79.676 -        if (array) {
  79.677 -            return new String[] { 
  79.678 -                "get" + n,
  79.679 -                null,
  79.680 -                "get" + nu + "__Ljava_util_List_2",
  79.681 -                null
  79.682 -            };
  79.683 -        }
  79.684 -        return new String[]{
  79.685 -            pref + n, 
  79.686 -            "set" + n, 
  79.687 -            pref + nu + "__" + bck2brwsrType,
  79.688 -            "set" + nu + "__V" + bck2brwsrType
  79.689 -        };
  79.690 -    }
  79.691 -
  79.692 -    private String typeName(Element where, Prprt p) {
  79.693 -        String ret;
  79.694 -        boolean[] isModel = { false };
  79.695 -        boolean[] isEnum = { false };
  79.696 -        boolean isPrimitive[] = { false };
  79.697 -        ret = checkType(p, isModel, isEnum, isPrimitive);
  79.698 -        if (p.array()) {
  79.699 -            String bt = findBoxedType(ret);
  79.700 -            if (bt != null) {
  79.701 -                return bt;
  79.702 -            }
  79.703 -        }
  79.704 -        return ret;
  79.705 -    }
  79.706 -    
  79.707 -    private static String findBoxedType(String ret) {
  79.708 -        if (ret.equals("boolean")) {
  79.709 -            return Boolean.class.getName();
  79.710 -        }
  79.711 -        if (ret.equals("byte")) {
  79.712 -            return Byte.class.getName();
  79.713 -        }
  79.714 -        if (ret.equals("short")) {
  79.715 -            return Short.class.getName();
  79.716 -        }
  79.717 -        if (ret.equals("char")) {
  79.718 -            return Character.class.getName();
  79.719 -        }
  79.720 -        if (ret.equals("int")) {
  79.721 -            return Integer.class.getName();
  79.722 -        }
  79.723 -        if (ret.equals("long")) {
  79.724 -            return Long.class.getName();
  79.725 -        }
  79.726 -        if (ret.equals("float")) {
  79.727 -            return Float.class.getName();
  79.728 -        }
  79.729 -        if (ret.equals("double")) {
  79.730 -            return Double.class.getName();
  79.731 -        }
  79.732 -        return null;
  79.733 -    }
  79.734 -
  79.735 -    private boolean verifyPropName(Element e, String propName, Prprt[] existingProps) {
  79.736 -        StringBuilder sb = new StringBuilder();
  79.737 -        String sep = "";
  79.738 -        for (Prprt Prprt : existingProps) {
  79.739 -            if (Prprt.name().equals(propName)) {
  79.740 -                return true;
  79.741 -            }
  79.742 -            sb.append(sep);
  79.743 -            sb.append('"');
  79.744 -            sb.append(Prprt.name());
  79.745 -            sb.append('"');
  79.746 -            sep = ", ";
  79.747 -        }
  79.748 -        error(
  79.749 -            propName + " is not one of known properties: " + sb
  79.750 -            , e
  79.751 -        );
  79.752 -        return false;
  79.753 -    }
  79.754 -
  79.755 -    private static String findPkgName(Element e) {
  79.756 -        for (;;) {
  79.757 -            if (e.getKind() == ElementKind.PACKAGE) {
  79.758 -                return ((PackageElement)e).getQualifiedName().toString();
  79.759 -            }
  79.760 -            e = e.getEnclosingElement();
  79.761 -        }
  79.762 -    }
  79.763 -
  79.764 -    private boolean generateFunctions(
  79.765 -        Element clazz, StringWriter body, String className, 
  79.766 -        List<? extends Element> enclosedElements, List<String> functions
  79.767 -    ) {
  79.768 -        for (Element m : enclosedElements) {
  79.769 -            if (m.getKind() != ElementKind.METHOD) {
  79.770 -                continue;
  79.771 -            }
  79.772 -            ExecutableElement e = (ExecutableElement)m;
  79.773 -            Function onF = e.getAnnotation(Function.class);
  79.774 -            if (onF == null) {
  79.775 -                continue;
  79.776 -            }
  79.777 -            if (!e.getModifiers().contains(Modifier.STATIC)) {
  79.778 -                error("@OnFunction method needs to be static", e);
  79.779 -                return false;
  79.780 -            }
  79.781 -            if (e.getModifiers().contains(Modifier.PRIVATE)) {
  79.782 -                error("@OnFunction method cannot be private", e);
  79.783 -                return false;
  79.784 -            }
  79.785 -            if (e.getReturnType().getKind() != TypeKind.VOID) {
  79.786 -                error("@OnFunction method should return void", e);
  79.787 -                return false;
  79.788 -            }
  79.789 -            String n = e.getSimpleName().toString();
  79.790 -            body.append("  private void ").append(n).append("(Object data, Object ev) {\n");
  79.791 -            body.append("    ").append(((TypeElement)clazz).getQualifiedName()).append(".").append(n).append("(");
  79.792 -            body.append(wrapParams(e, null, className, "ev", "data"));
  79.793 -            body.append(");\n");
  79.794 -            body.append("  }\n");
  79.795 -            
  79.796 -            functions.add(n);
  79.797 -            functions.add(n + "__VLjava_lang_Object_2Ljava_lang_Object_2");
  79.798 -        }
  79.799 -        return true;
  79.800 -    }
  79.801 -
  79.802 -    private boolean generateOnChange(Element clazz, Map<String,Collection<String>> propDeps,
  79.803 -        Prprt[] properties, String className, 
  79.804 -        Map<String, Collection<String>> functionDeps
  79.805 -    ) {
  79.806 -        for (Element m : clazz.getEnclosedElements()) {
  79.807 -            if (m.getKind() != ElementKind.METHOD) {
  79.808 -                continue;
  79.809 -            }
  79.810 -            ExecutableElement e = (ExecutableElement) m;
  79.811 -            OnPropertyChange onPC = e.getAnnotation(OnPropertyChange.class);
  79.812 -            if (onPC == null) {
  79.813 -                continue;
  79.814 -            }
  79.815 -            for (String pn : onPC.value()) {
  79.816 -                if (findPrprt(properties, pn) == null && findDerivedFrom(propDeps, pn).isEmpty()) {
  79.817 -                    error("No Prprt named '" + pn + "' in the model", clazz);
  79.818 -                    return false;
  79.819 -                }
  79.820 -            }
  79.821 -            if (!e.getModifiers().contains(Modifier.STATIC)) {
  79.822 -                error("@OnPrprtChange method needs to be static", e);
  79.823 -                return false;
  79.824 -            }
  79.825 -            if (e.getModifiers().contains(Modifier.PRIVATE)) {
  79.826 -                error("@OnPrprtChange method cannot be private", e);
  79.827 -                return false;
  79.828 -            }
  79.829 -            if (e.getReturnType().getKind() != TypeKind.VOID) {
  79.830 -                error("@OnPrprtChange method should return void", e);
  79.831 -                return false;
  79.832 -            }
  79.833 -            String n = e.getSimpleName().toString();
  79.834 -            
  79.835 -            
  79.836 -            for (String pn : onPC.value()) {
  79.837 -                StringBuilder call = new StringBuilder();
  79.838 -                call.append("  ").append(clazz.getSimpleName()).append(".").append(n).append("(");
  79.839 -                call.append(wrapPropName(e, className, "name", pn));
  79.840 -                call.append(");\n");
  79.841 -                
  79.842 -                Collection<String> change = functionDeps.get(pn);
  79.843 -                if (change == null) {
  79.844 -                    change = new ArrayList<String>();
  79.845 -                    functionDeps.put(pn, change);
  79.846 -                }
  79.847 -                change.add(call.toString());
  79.848 -                for (String dpn : findDerivedFrom(propDeps, pn)) {
  79.849 -                    change = functionDeps.get(dpn);
  79.850 -                    if (change == null) {
  79.851 -                        change = new ArrayList<String>();
  79.852 -                        functionDeps.put(dpn, change);
  79.853 -                    }
  79.854 -                    change.add(call.toString());
  79.855 -                }
  79.856 -            }
  79.857 -        }
  79.858 -        return true;
  79.859 -    }
  79.860 -
  79.861 -    private boolean generateOperation(Element clazz, 
  79.862 -        StringWriter body, String className, 
  79.863 -        List<? extends Element> enclosedElements
  79.864 -    ) {
  79.865 -        for (Element m : enclosedElements) {
  79.866 -            if (m.getKind() != ElementKind.METHOD) {
  79.867 -                continue;
  79.868 -            }
  79.869 -            ExecutableElement e = (ExecutableElement)m;
  79.870 -            ModelOperation mO = e.getAnnotation(ModelOperation.class);
  79.871 -            if (mO == null) {
  79.872 -                continue;
  79.873 -            }
  79.874 -            if (!e.getModifiers().contains(Modifier.STATIC)) {
  79.875 -                error("@ModelOperation method needs to be static", e);
  79.876 -                return false;
  79.877 -            }
  79.878 -            if (e.getModifiers().contains(Modifier.PRIVATE)) {
  79.879 -                error("@ModelOperation method cannot be private", e);
  79.880 -                return false;
  79.881 -            }
  79.882 -            if (e.getReturnType().getKind() != TypeKind.VOID) {
  79.883 -                error("@ModelOperation method should return void", e);
  79.884 -                return false;
  79.885 -            }
  79.886 -            List<String> args = new ArrayList<String>();
  79.887 -            {
  79.888 -                body.append("  public void ").append(m.getSimpleName()).append("(");
  79.889 -                String sep = "";
  79.890 -                boolean checkFirst = true;
  79.891 -                for (VariableElement ve : e.getParameters()) {
  79.892 -                    final TypeMirror type = ve.asType();
  79.893 -                    CharSequence simpleName;
  79.894 -                    if (type.getKind() == TypeKind.DECLARED) {
  79.895 -                        simpleName = ((DeclaredType)type).asElement().getSimpleName();
  79.896 -                    } else {
  79.897 -                        simpleName = type.toString();
  79.898 -                    }
  79.899 -                    if (simpleName.toString().equals(className)) {
  79.900 -                        checkFirst = false;
  79.901 -                    } else {
  79.902 -                        if (checkFirst) {
  79.903 -                            error("First parameter of @ModelOperation method must be " + className, m);
  79.904 -                            return false;
  79.905 -                        }
  79.906 -                        args.add(ve.getSimpleName().toString());
  79.907 -                        body.append(sep).append("final ");
  79.908 -                        body.append(ve.asType().toString()).append(" ");
  79.909 -                        body.append(ve.toString());
  79.910 -                        sep = ", ";
  79.911 -                    }
  79.912 -                }
  79.913 -                body.append(") {\n");
  79.914 -                body.append("    org.apidesign.html.json.impl.JSON.runInBrowser(this.context, new Runnable() { public void run() {\n");
  79.915 -                body.append("      ").append(clazz.getSimpleName()).append(".").append(m.getSimpleName()).append("(");
  79.916 -                body.append(className).append(".this");
  79.917 -                for (String s : args) {
  79.918 -                    body.append(", ").append(s);
  79.919 -                }
  79.920 -                body.append(");\n");
  79.921 -                body.append("    }});\n");
  79.922 -                body.append("  }\n");
  79.923 -            }
  79.924 -            
  79.925 -        }
  79.926 -        return true;
  79.927 -    }
  79.928 -    
  79.929 -    
  79.930 -    private boolean generateReceive(
  79.931 -        Element clazz, StringWriter body, String className, 
  79.932 -        List<? extends Element> enclosedElements, List<String> functions
  79.933 -    ) {
  79.934 -        for (Element m : enclosedElements) {
  79.935 -            if (m.getKind() != ElementKind.METHOD) {
  79.936 -                continue;
  79.937 -            }
  79.938 -            ExecutableElement e = (ExecutableElement)m;
  79.939 -            OnReceive onR = e.getAnnotation(OnReceive.class);
  79.940 -            if (onR == null) {
  79.941 -                continue;
  79.942 -            }
  79.943 -            if (!e.getModifiers().contains(Modifier.STATIC)) {
  79.944 -                error("@OnReceive method needs to be static", e);
  79.945 -                return false;
  79.946 -            }
  79.947 -            if (e.getModifiers().contains(Modifier.PRIVATE)) {
  79.948 -                error("@OnReceive method cannot be private", e);
  79.949 -                return false;
  79.950 -            }
  79.951 -            if (e.getReturnType().getKind() != TypeKind.VOID) {
  79.952 -                error("@OnReceive method should return void", e);
  79.953 -                return false;
  79.954 -            }
  79.955 -            if (!onR.jsonp().isEmpty() && !"GET".equals(onR.method())) {
  79.956 -                error("JSONP works only with GET transport method", e);
  79.957 -            }
  79.958 -            String dataMirror = findDataSpecified(e, onR);
  79.959 -            if ("PUT".equals(onR.method()) && dataMirror == null) {
  79.960 -                error("PUT method needs to specify a data() class", e);
  79.961 -                return false;
  79.962 -            }
  79.963 -            if ("POST".equals(onR.method()) && dataMirror == null) {
  79.964 -                error("POST method needs to specify a data() class", e);
  79.965 -                return false;
  79.966 -            }
  79.967 -            String modelClass = null;
  79.968 -            boolean expectsList = false;
  79.969 -            List<String> args = new ArrayList<String>();
  79.970 -            {
  79.971 -                for (VariableElement ve : e.getParameters()) {
  79.972 -                    TypeMirror modelType = null;
  79.973 -                    final TypeMirror type = ve.asType();
  79.974 -                    CharSequence simpleName;
  79.975 -                    if (type.getKind() == TypeKind.DECLARED) {
  79.976 -                        simpleName = ((DeclaredType)type).asElement().getSimpleName();
  79.977 -                    } else {
  79.978 -                        simpleName = type.toString();
  79.979 -                    }
  79.980 -                    if (simpleName.toString().equals(className)) {
  79.981 -                        args.add(className + ".this");
  79.982 -                    } else if (isModel(ve.asType())) {
  79.983 -                        modelType = ve.asType();
  79.984 -                    } else if (ve.asType().getKind() == TypeKind.ARRAY) {
  79.985 -                        modelType = ((ArrayType)ve.asType()).getComponentType();
  79.986 -                        expectsList = true;
  79.987 -                    } else if (ve.asType().toString().equals("java.lang.String")) {
  79.988 -                        modelType = ve.asType();
  79.989 -                    }
  79.990 -                    if (modelType != null) {
  79.991 -                        if (modelClass != null) {
  79.992 -                            error("There can be only one model class among arguments", e);
  79.993 -                        } else {
  79.994 -                            modelClass = modelType.toString();
  79.995 -                            if (expectsList) {
  79.996 -                                args.add("arr");
  79.997 -                            } else {
  79.998 -                                args.add("arr[0]");
  79.999 -                            }
 79.1000 -                        }
 79.1001 -                    }
 79.1002 -                }
 79.1003 -            }
 79.1004 -            if (modelClass == null) {
 79.1005 -                error("The method needs to have one @Model class as parameter", e);
 79.1006 -            }
 79.1007 -            String n = e.getSimpleName().toString();
 79.1008 -            if ("WebSocket".equals(onR.method())) {
 79.1009 -                body.append("  /** Performs WebSocket communication. Call with <code>null</code> data parameter\n");
 79.1010 -                body.append("  * to open the connection (even if not required). Call with non-null data to\n");
 79.1011 -                body.append("  * send messages to server. Call again with <code>null</code> data to close the socket.\n");
 79.1012 -                body.append("  */\n");
 79.1013 -            }
 79.1014 -            body.append("  public void ").append(n).append("(");
 79.1015 -            StringBuilder urlBefore = new StringBuilder();
 79.1016 -            StringBuilder urlAfter = new StringBuilder();
 79.1017 -            String jsonpVarName = null;
 79.1018 -            {
 79.1019 -                String sep = "";
 79.1020 -                boolean skipJSONP = onR.jsonp().isEmpty();
 79.1021 -                for (String p : findParamNames(e, onR.url(), onR.jsonp(), urlBefore, urlAfter)) {
 79.1022 -                    if (!skipJSONP && p.equals(onR.jsonp())) {
 79.1023 -                        skipJSONP = true;
 79.1024 -                        jsonpVarName = p;
 79.1025 -                        continue;
 79.1026 -                    }
 79.1027 -                    body.append(sep);
 79.1028 -                    body.append("String ").append(p);
 79.1029 -                    sep = ", ";
 79.1030 -                }
 79.1031 -                if (!skipJSONP) {
 79.1032 -                    error(
 79.1033 -                        "Name of jsonp attribute ('" + onR.jsonp() + 
 79.1034 -                        "') is not used in url attribute '" + onR.url() + "'", e
 79.1035 -                    );
 79.1036 -                }
 79.1037 -                if (dataMirror != null) {
 79.1038 -                    body.append(sep).append(dataMirror.toString()).append(" data");
 79.1039 -                }
 79.1040 -            }
 79.1041 -            body.append(") {\n");
 79.1042 -            boolean webSocket = onR.method().equals("WebSocket");
 79.1043 -            if (webSocket) {
 79.1044 -                if (generateWSReceiveBody(body, onR, e, clazz, className, expectsList, modelClass, n, args, urlBefore, jsonpVarName, urlAfter, dataMirror)) {
 79.1045 -                    return false;
 79.1046 -                }
 79.1047 -                body.append("  }\n");
 79.1048 -                body.append("  private org.apidesign.html.json.impl.JSON.WS ws_" + e.getSimpleName() + ";\n");
 79.1049 -            } else {
 79.1050 -                if (generateJSONReceiveBody(body, onR, e, clazz, className, expectsList, modelClass, n, args, urlBefore, jsonpVarName, urlAfter, dataMirror)) {
 79.1051 -                    return false;
 79.1052 -                }
 79.1053 -                body.append("  }\n");
 79.1054 -            }
 79.1055 -        }
 79.1056 -        return true;
 79.1057 -    }
 79.1058 -
 79.1059 -    private boolean generateJSONReceiveBody(StringWriter body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List<String> args, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror) {
 79.1060 -        body.append(
 79.1061 -            "    class ProcessResult extends org.apidesign.html.json.impl.RcvrJSON {\n" +
 79.1062 -            "      @Override\n" +
 79.1063 -            "      public void onError(org.apidesign.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" +
 79.1064 -            "        Exception value = ev.getException();\n"
 79.1065 -            );
 79.1066 -        if (onR.onError().isEmpty()) {
 79.1067 -            body.append(
 79.1068 -                "        value.printStackTrace();\n"
 79.1069 -                );
 79.1070 -        } else {
 79.1071 -            if (!findOnError(e, ((TypeElement)clazz), onR.onError(), className)) {
 79.1072 -                return true;
 79.1073 -            }
 79.1074 -            body.append("        ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("(");
 79.1075 -            body.append(className).append(".this, value);\n");
 79.1076 -        }
 79.1077 -        body.append(
 79.1078 -            "      }\n" +
 79.1079 -            "      @Override\n" +
 79.1080 -            "      public void onMessage(org.apidesign.html.json.impl.RcvrJSON.MsgEvnt ev) {\n"
 79.1081 -            );
 79.1082 -        if (expectsList) {
 79.1083 -            body.append(
 79.1084 -                "        " + modelClass + "[] arr = new " + modelClass + "[ev.dataSize()];\n"
 79.1085 -                );
 79.1086 -        } else {
 79.1087 -            body.append(
 79.1088 -                "        " + modelClass + "[] arr = { null };\n"
 79.1089 -                );
 79.1090 -        }
 79.1091 -        body.append(
 79.1092 -            "        ev.dataRead(context, " + modelClass + ".class, arr);\n"
 79.1093 -            );
 79.1094 -        {
 79.1095 -            body.append("        ").append(clazz.getSimpleName()).append(".").append(n).append("(");
 79.1096 -            String sep = "";
 79.1097 -            for (String arg : args) {
 79.1098 -                body.append(sep);
 79.1099 -                body.append(arg);
 79.1100 -                sep = ", ";
 79.1101 -            }
 79.1102 -            body.append(");\n");
 79.1103 -        }
 79.1104 -        body.append(
 79.1105 -            "      }\n" +
 79.1106 -            "    }\n"
 79.1107 -            );
 79.1108 -        body.append("    ProcessResult pr = new ProcessResult();\n");
 79.1109 -        body.append("    org.apidesign.html.json.impl.JSON.loadJSON(context, pr,\n        ");
 79.1110 -        body.append(urlBefore).append(", ");
 79.1111 -        if (jsonpVarName != null) {
 79.1112 -            body.append(urlAfter);
 79.1113 -        } else {
 79.1114 -            body.append("null");
 79.1115 -        }
 79.1116 -        if (!"GET".equals(onR.method()) || dataMirror != null) {
 79.1117 -            body.append(", \"").append(onR.method()).append('"');
 79.1118 -            if (dataMirror != null) {
 79.1119 -                body.append(", data");
 79.1120 -            } else {
 79.1121 -                body.append(", null");
 79.1122 -            }
 79.1123 -        } else {
 79.1124 -            body.append(", null, null");
 79.1125 -        }
 79.1126 -        body.append(");\n");
 79.1127 -        return false;
 79.1128 -    }
 79.1129 -    
 79.1130 -    private boolean generateWSReceiveBody(StringWriter body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List<String> args, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror) {
 79.1131 -        body.append(
 79.1132 -            "    class ProcessResult extends org.apidesign.html.json.impl.RcvrJSON {\n" +
 79.1133 -            "      @Override\n" +
 79.1134 -            "      public void onOpen(org.apidesign.html.json.impl.RcvrJSON.MsgEvnt ev) {\n"
 79.1135 -        );
 79.1136 -        body.append("        ").append(clazz.getSimpleName()).append(".").append(n).append("(");
 79.1137 -        {
 79.1138 -            String sep = "";
 79.1139 -            for (String arg : args) {
 79.1140 -                body.append(sep);
 79.1141 -                if (arg.startsWith("arr")) {
 79.1142 -                    body.append("null");
 79.1143 -                } else {
 79.1144 -                    body.append(arg);
 79.1145 -                }
 79.1146 -                sep = ", ";
 79.1147 -            }
 79.1148 -        }
 79.1149 -        body.append(");\n");
 79.1150 -        body.append(
 79.1151 -            "      }\n" +
 79.1152 -            "      @Override\n" +
 79.1153 -            "      public void onError(org.apidesign.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" +
 79.1154 -            "        Exception value = ev.getException();\n"
 79.1155 -            );
 79.1156 -        if (onR.onError().isEmpty()) {
 79.1157 -            body.append(
 79.1158 -                "        value.printStackTrace();\n"
 79.1159 -                );
 79.1160 -        } else {
 79.1161 -            if (!findOnError(e, ((TypeElement)clazz), onR.onError(), className)) {
 79.1162 -                return true;
 79.1163 -            }
 79.1164 -            body.append("        ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("(");
 79.1165 -            body.append(className).append(".this, value);\n");
 79.1166 -        }
 79.1167 -        body.append(
 79.1168 -            "      }\n" +
 79.1169 -            "      @Override\n" +
 79.1170 -            "      public void onMessage(org.apidesign.html.json.impl.RcvrJSON.MsgEvnt ev) {\n"
 79.1171 -        );
 79.1172 -        if (expectsList) {
 79.1173 -            body.append(
 79.1174 -                "        " + modelClass + "[] arr = new " + modelClass + "[ev.dataSize()];\n"
 79.1175 -                );
 79.1176 -        } else {
 79.1177 -            body.append(
 79.1178 -                "        " + modelClass + "[] arr = { null };\n"
 79.1179 -                );
 79.1180 -        }
 79.1181 -        body.append(
 79.1182 -            "        ev.dataRead(context, " + modelClass + ".class, arr);\n"
 79.1183 -            );
 79.1184 -        {
 79.1185 -            body.append("        ").append(clazz.getSimpleName()).append(".").append(n).append("(");
 79.1186 -            String sep = "";
 79.1187 -            for (String arg : args) {
 79.1188 -                body.append(sep);
 79.1189 -                body.append(arg);
 79.1190 -                sep = ", ";
 79.1191 -            }
 79.1192 -            body.append(");\n");
 79.1193 -        }
 79.1194 -        body.append(
 79.1195 -            "      }\n"
 79.1196 -        );
 79.1197 -        if (!onR.onError().isEmpty()) {
 79.1198 -            body.append(
 79.1199 -                "      @Override\n"
 79.1200 -              + "      public void onClose(org.apidesign.html.json.impl.RcvrJSON.MsgEvnt ev) {\n"
 79.1201 -            );
 79.1202 -            body.append("        ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("(");
 79.1203 -            body.append(className).append(".this, null);\n");
 79.1204 -            body.append(
 79.1205 -                "      }\n"
 79.1206 -            );
 79.1207 -        }
 79.1208 -        body.append("    }\n");
 79.1209 -        body.append("    if (this.ws_").append(e.getSimpleName()).append(" == null) {\n");
 79.1210 -        body.append("      ProcessResult pr = new ProcessResult();\n");
 79.1211 -        body.append("      this.ws_").append(e.getSimpleName());
 79.1212 -        body.append("= org.apidesign.html.json.impl.JSON.openWS(context, pr,\n        ");
 79.1213 -        body.append(urlBefore).append(", data);\n");
 79.1214 -        body.append("    } else {\n");
 79.1215 -        body.append("      this.ws_").append(e.getSimpleName()).append(".send(context, ").append(urlBefore).append(", data);\n");
 79.1216 -        body.append("    }\n");
 79.1217 -        return false;
 79.1218 -    }
 79.1219 -
 79.1220 -    private CharSequence wrapParams(
 79.1221 -        ExecutableElement ee, String id, String className, String evName, String dataName
 79.1222 -    ) {
 79.1223 -        TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
 79.1224 -        StringBuilder params = new StringBuilder();
 79.1225 -        boolean first = true;
 79.1226 -        for (VariableElement ve : ee.getParameters()) {
 79.1227 -            if (!first) {
 79.1228 -                params.append(", ");
 79.1229 -            }
 79.1230 -            first = false;
 79.1231 -            String toCall = null;
 79.1232 -            String toFinish = null;
 79.1233 -            if (ve.asType() == stringType) {
 79.1234 -                if (ve.getSimpleName().contentEquals("id")) {
 79.1235 -                    params.append('"').append(id).append('"');
 79.1236 -                    continue;
 79.1237 -                }
 79.1238 -                toCall = "org.apidesign.html.json.impl.JSON.toString(context, ";
 79.1239 -            }
 79.1240 -            if (ve.asType().getKind() == TypeKind.DOUBLE) {
 79.1241 -                toCall = "org.apidesign.html.json.impl.JSON.toNumber(context, ";
 79.1242 -                toFinish = ".doubleValue()";
 79.1243 -            }
 79.1244 -            if (ve.asType().getKind() == TypeKind.INT) {
 79.1245 -                toCall = "org.apidesign.html.json.impl.JSON.toNumber(context, ";
 79.1246 -                toFinish = ".intValue()";
 79.1247 -            }
 79.1248 -            if (dataName != null && ve.getSimpleName().contentEquals(dataName) && isModel(ve.asType())) {
 79.1249 -                toCall = "org.apidesign.html.json.impl.JSON.toModel(context, " + ve.asType() + ".class, ";
 79.1250 -            }
 79.1251 -
 79.1252 -            if (toCall != null) {
 79.1253 -                params.append(toCall);
 79.1254 -                if (dataName != null && ve.getSimpleName().contentEquals(dataName)) {
 79.1255 -                    params.append(dataName);
 79.1256 -                    params.append(", null");
 79.1257 -                } else {
 79.1258 -                    if (evName == null) {
 79.1259 -                        final StringBuilder sb = new StringBuilder();
 79.1260 -                        sb.append("Unexpected string parameter name.");
 79.1261 -                        if (dataName != null) {
 79.1262 -                            sb.append(" Try \"").append(dataName).append("\"");
 79.1263 -                        }
 79.1264 -                        error(sb.toString(), ee);
 79.1265 -                    }
 79.1266 -                    params.append(evName);
 79.1267 -                    params.append(", \"");
 79.1268 -                    params.append(ve.getSimpleName().toString());
 79.1269 -                    params.append("\"");
 79.1270 -                }
 79.1271 -                params.append(")");
 79.1272 -                if (toFinish != null) {
 79.1273 -                    params.append(toFinish);
 79.1274 -                }
 79.1275 -                continue;
 79.1276 -            }
 79.1277 -            String rn = fqn(ve.asType(), ee);
 79.1278 -            int last = rn.lastIndexOf('.');
 79.1279 -            if (last >= 0) {
 79.1280 -                rn = rn.substring(last + 1);
 79.1281 -            }
 79.1282 -            if (rn.equals(className)) {
 79.1283 -                params.append(className).append(".this");
 79.1284 -                continue;
 79.1285 -            }
 79.1286 -            error(
 79.1287 -                "The annotated method can only accept " + className + " argument or argument named 'data'",
 79.1288 -                ee
 79.1289 -            );
 79.1290 -        }
 79.1291 -        return params;
 79.1292 -    }
 79.1293 -    
 79.1294 -    
 79.1295 -    private CharSequence wrapPropName(
 79.1296 -        ExecutableElement ee, String className, String propName, String propValue
 79.1297 -    ) {
 79.1298 -        TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
 79.1299 -        StringBuilder params = new StringBuilder();
 79.1300 -        boolean first = true;
 79.1301 -        for (VariableElement ve : ee.getParameters()) {
 79.1302 -            if (!first) {
 79.1303 -                params.append(", ");
 79.1304 -            }
 79.1305 -            first = false;
 79.1306 -            if (ve.asType() == stringType) {
 79.1307 -                if (propName != null && ve.getSimpleName().contentEquals(propName)) {
 79.1308 -                    params.append('"').append(propValue).append('"');
 79.1309 -                } else {
 79.1310 -                    error("Unexpected string parameter name. Try \"" + propName + "\".", ee);
 79.1311 -                }
 79.1312 -                continue;
 79.1313 -            }
 79.1314 -            String rn = fqn(ve.asType(), ee);
 79.1315 -            int last = rn.lastIndexOf('.');
 79.1316 -            if (last >= 0) {
 79.1317 -                rn = rn.substring(last + 1);
 79.1318 -            }
 79.1319 -            if (rn.equals(className)) {
 79.1320 -                params.append(className).append(".this");
 79.1321 -                continue;
 79.1322 -            }
 79.1323 -            error(
 79.1324 -                "@OnPrprtChange method can only accept String or " + className + " arguments",
 79.1325 -                ee);
 79.1326 -        }
 79.1327 -        return params;
 79.1328 -    }
 79.1329 -    
 79.1330 -    private boolean isModel(TypeMirror tm) {
 79.1331 -        if (tm.getKind() == TypeKind.ERROR) {
 79.1332 -            return true;
 79.1333 -        }
 79.1334 -        final Element e = processingEnv.getTypeUtils().asElement(tm);
 79.1335 -        if (e == null) {
 79.1336 -            return false;
 79.1337 -        }
 79.1338 -        for (Element ch : e.getEnclosedElements()) {
 79.1339 -            if (ch.getKind() == ElementKind.METHOD) {
 79.1340 -                ExecutableElement ee = (ExecutableElement)ch;
 79.1341 -                if (ee.getParameters().isEmpty() && ee.getSimpleName().contentEquals("modelFor")) {
 79.1342 -                    return true;
 79.1343 -                }
 79.1344 -            }
 79.1345 -        }
 79.1346 -        return models.values().contains(e.getSimpleName().toString());
 79.1347 -    }
 79.1348 -    
 79.1349 -    private void writeToString(Prprt[] props, Writer w) throws IOException {
 79.1350 -        w.write("  public String toString() {\n");
 79.1351 -        w.write("    StringBuilder sb = new StringBuilder();\n");
 79.1352 -        w.write("    sb.append('{');\n");
 79.1353 -        String sep = "";
 79.1354 -        for (Prprt p : props) {
 79.1355 -            w.write(sep);
 79.1356 -            w.append("    sb.append('\"').append(\"" + p.name() + "\")");
 79.1357 -                w.append(".append('\"').append(\":\");\n");
 79.1358 -            w.append("    sb.append(org.apidesign.html.json.impl.JSON.toJSON(prop_");
 79.1359 -            w.append(p.name()).append("));\n");
 79.1360 -            sep =    "    sb.append(',');\n";
 79.1361 -        }
 79.1362 -        w.write("    sb.append('}');\n");
 79.1363 -        w.write("    return sb.toString();\n");
 79.1364 -        w.write("  }\n");
 79.1365 -    }
 79.1366 -    private void writeClone(String className, Prprt[] props, Writer w) throws IOException {
 79.1367 -        w.write("  public " + className + " clone() {\n");
 79.1368 -        w.write("    return clone(context);\n");
 79.1369 -        w.write("  }\n");
 79.1370 -        w.write("  private " + className + " clone(net.java.html.BrwsrCtx ctx) {\n");
 79.1371 -        w.write("    " + className + " ret = new " + className + "(ctx);\n");
 79.1372 -        for (Prprt p : props) {
 79.1373 -            if (!p.array()) {
 79.1374 -                boolean isModel[] = { false };
 79.1375 -                boolean isEnum[] = { false };
 79.1376 -                boolean isPrimitive[] = { false };
 79.1377 -                checkType(p, isModel, isEnum, isPrimitive);
 79.1378 -                if (!isModel[0]) {
 79.1379 -                    w.write("    ret.prop_" + p.name() + " = prop_" + p.name() + ";\n");
 79.1380 -                    continue;
 79.1381 -                }
 79.1382 -                w.write("    ret.prop_" + p.name() + " =  prop_" + p.name() + "  == null ? null : prop_" + p.name() + ".clone();\n");
 79.1383 -            } else {
 79.1384 -                w.write("    ret.prop_" + p.name() + ".cloneAll(ctx, prop_" + p.name() + ");\n");
 79.1385 -            }
 79.1386 -        }
 79.1387 -        
 79.1388 -        w.write("    return ret;\n");
 79.1389 -        w.write("  }\n");
 79.1390 -    }
 79.1391 -
 79.1392 -    private String inPckName(Element e) {
 79.1393 -        StringBuilder sb = new StringBuilder();
 79.1394 -        while (e.getKind() != ElementKind.PACKAGE) {
 79.1395 -            if (sb.length() == 0) {
 79.1396 -                sb.append(e.getSimpleName());
 79.1397 -            } else {
 79.1398 -                sb.insert(0, '.');
 79.1399 -                sb.insert(0, e.getSimpleName());
 79.1400 -            }
 79.1401 -            e = e.getEnclosingElement();
 79.1402 -        }
 79.1403 -        return sb.toString();
 79.1404 -    }
 79.1405 -
 79.1406 -    private String fqn(TypeMirror pt, Element relative) {
 79.1407 -        if (pt.getKind() == TypeKind.ERROR) {
 79.1408 -            final Elements eu = processingEnv.getElementUtils();
 79.1409 -            PackageElement pckg = eu.getPackageOf(relative);
 79.1410 -            return pckg.getQualifiedName() + "." + pt.toString();
 79.1411 -        }
 79.1412 -        return pt.toString();
 79.1413 -    }
 79.1414 -
 79.1415 -    private String checkType(Prprt p, boolean[] isModel, boolean[] isEnum, boolean[] isPrimitive) {
 79.1416 -        TypeMirror tm;
 79.1417 -        try {
 79.1418 -            String ret = p.typeName(processingEnv);
 79.1419 -            TypeElement e = processingEnv.getElementUtils().getTypeElement(ret);
 79.1420 -            if (e == null) {
 79.1421 -                isModel[0] = true;
 79.1422 -                isEnum[0] = false;
 79.1423 -                isPrimitive[0] = false;
 79.1424 -                return ret;
 79.1425 -            }
 79.1426 -            tm = e.asType();
 79.1427 -        } catch (MirroredTypeException ex) {
 79.1428 -            tm = ex.getTypeMirror();
 79.1429 -        }
 79.1430 -        tm = processingEnv.getTypeUtils().erasure(tm);
 79.1431 -        if (isPrimitive[0] = tm.getKind().isPrimitive()) {
 79.1432 -            isEnum[0] = false;
 79.1433 -            isModel[0] = false;
 79.1434 -            return tm.toString();
 79.1435 -        }
 79.1436 -        final Element e = processingEnv.getTypeUtils().asElement(tm);
 79.1437 -        if (e.getKind() == ElementKind.CLASS && tm.getKind() == TypeKind.ERROR) {
 79.1438 -            isModel[0] = true;
 79.1439 -            isEnum[0] = false;
 79.1440 -            return e.getSimpleName().toString();
 79.1441 -        }
 79.1442 -        
 79.1443 -        final Model m = e == null ? null : e.getAnnotation(Model.class);
 79.1444 -        String ret;
 79.1445 -        if (m != null) {
 79.1446 -            ret = findPkgName(e) + '.' + m.className();
 79.1447 -            isModel[0] = true;
 79.1448 -            models.put(e, m.className());
 79.1449 -        } else if (findModelForMthd(e)) {
 79.1450 -            ret = ((TypeElement)e).getQualifiedName().toString();
 79.1451 -            isModel[0] = true;
 79.1452 -        } else {
 79.1453 -            ret = tm.toString();
 79.1454 -        }
 79.1455 -        TypeMirror enm = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType();
 79.1456 -        enm = processingEnv.getTypeUtils().erasure(enm);
 79.1457 -        isEnum[0] = processingEnv.getTypeUtils().isSubtype(tm, enm);
 79.1458 -        return ret;
 79.1459 -    }
 79.1460 -    
 79.1461 -    private static boolean findModelForMthd(Element clazz) {
 79.1462 -        if (clazz == null) {
 79.1463 -            return false;
 79.1464 -        }
 79.1465 -        for (Element e : clazz.getEnclosedElements()) {
 79.1466 -            if (e.getKind() == ElementKind.METHOD) {
 79.1467 -                ExecutableElement ee = (ExecutableElement)e;
 79.1468 -                if (
 79.1469 -                    ee.getSimpleName().contentEquals("modelFor") &&
 79.1470 -                    ee.getParameters().isEmpty()
 79.1471 -                ) {
 79.1472 -                    return true;
 79.1473 -                }
 79.1474 -            }
 79.1475 -        }
 79.1476 -        return false;
 79.1477 -    }
 79.1478 -
 79.1479 -    private Iterable<String> findParamNames(
 79.1480 -        Element e, String url, String jsonParam, StringBuilder... both
 79.1481 -    ) {
 79.1482 -        List<String> params = new ArrayList<String>();
 79.1483 -        int wasJSON = 0;
 79.1484 -
 79.1485 -        for (int pos = 0; ;) {
 79.1486 -            int next = url.indexOf('{', pos);
 79.1487 -            if (next == -1) {
 79.1488 -                both[wasJSON].append('"')
 79.1489 -                    .append(url.substring(pos))
 79.1490 -                    .append('"');
 79.1491 -                return params;
 79.1492 -            }
 79.1493 -            int close = url.indexOf('}', next);
 79.1494 -            if (close == -1) {
 79.1495 -                error("Unbalanced '{' and '}' in " + url, e);
 79.1496 -                return params;
 79.1497 -            }
 79.1498 -            final String paramName = url.substring(next + 1, close);
 79.1499 -            params.add(paramName);
 79.1500 -            if (paramName.equals(jsonParam) && !jsonParam.isEmpty()) {
 79.1501 -                both[wasJSON].append('"')
 79.1502 -                    .append(url.substring(pos, next))
 79.1503 -                    .append('"');
 79.1504 -                wasJSON = 1;
 79.1505 -            } else {
 79.1506 -                both[wasJSON].append('"')
 79.1507 -                    .append(url.substring(pos, next))
 79.1508 -                    .append("\" + ").append(paramName).append(" + ");
 79.1509 -            }
 79.1510 -            pos = close + 1;
 79.1511 -        }
 79.1512 -    }
 79.1513 -
 79.1514 -    private static Prprt findPrprt(Prprt[] properties, String propName) {
 79.1515 -        for (Prprt p : properties) {
 79.1516 -            if (propName.equals(p.name())) {
 79.1517 -                return p;
 79.1518 -            }
 79.1519 -        }
 79.1520 -        return null;
 79.1521 -    }
 79.1522 -
 79.1523 -    private boolean isPrimitive(String type) {
 79.1524 -        return 
 79.1525 -            "int".equals(type) ||
 79.1526 -            "double".equals(type) ||
 79.1527 -            "long".equals(type) ||
 79.1528 -            "short".equals(type) ||
 79.1529 -            "byte".equals(type) ||
 79.1530 -            "char".equals(type) ||
 79.1531 -            "boolean".equals(type) ||
 79.1532 -            "float".equals(type);
 79.1533 -    }
 79.1534 -
 79.1535 -    private static Collection<String> findDerivedFrom(Map<String, Collection<String>> propsDeps, String derivedProp) {
 79.1536 -        Set<String> names = new HashSet<String>();
 79.1537 -        for (Map.Entry<String, Collection<String>> e : propsDeps.entrySet()) {
 79.1538 -            if (e.getValue().contains(derivedProp)) {
 79.1539 -                names.add(e.getKey());
 79.1540 -            }
 79.1541 -        }
 79.1542 -        return names;
 79.1543 -    }
 79.1544 -    
 79.1545 -    private Prprt[] createProps(Element e, Property[] arr) {
 79.1546 -        Prprt[] ret = Prprt.wrap(processingEnv, e, arr);
 79.1547 -        Prprt[] prev = verify.put(e, ret);
 79.1548 -        if (prev != null) {
 79.1549 -            error("Two sets of properties for ", e);
 79.1550 -        }
 79.1551 -        return ret;
 79.1552 -    }
 79.1553 -    
 79.1554 -    private static String strip(String s) {
 79.1555 -        int indx = s.indexOf("__");
 79.1556 -        if (indx >= 0) {
 79.1557 -            return s.substring(0, indx);
 79.1558 -        } else {
 79.1559 -            return s;
 79.1560 -        }
 79.1561 -    }
 79.1562 -
 79.1563 -    private String findDataSpecified(ExecutableElement e, OnReceive onR) {
 79.1564 -        try {
 79.1565 -            return onR.data().getName();
 79.1566 -        } catch (MirroredTypeException ex) {
 79.1567 -            final TypeMirror tm = ex.getTypeMirror();
 79.1568 -            String name;
 79.1569 -            final Element te = processingEnv.getTypeUtils().asElement(tm);
 79.1570 -            if (te.getKind() == ElementKind.CLASS && tm.getKind() == TypeKind.ERROR) {
 79.1571 -                name = te.getSimpleName().toString();
 79.1572 -            } else {
 79.1573 -                name = tm.toString();
 79.1574 -            }
 79.1575 -            return "java.lang.Object".equals(name) ? null : name;
 79.1576 -        } catch (Exception ex) {
 79.1577 -            // fallback
 79.1578 -        }
 79.1579 -        
 79.1580 -        AnnotationMirror found = null;
 79.1581 -        for (AnnotationMirror am : e.getAnnotationMirrors()) {
 79.1582 -            if (am.getAnnotationType().toString().equals(OnReceive.class.getName())) {
 79.1583 -                found = am;
 79.1584 -            }
 79.1585 -        }
 79.1586 -        if (found == null) {
 79.1587 -            return null;
 79.1588 -        }
 79.1589 -        
 79.1590 -        for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : found.getElementValues().entrySet()) {
 79.1591 -            ExecutableElement ee = entry.getKey();
 79.1592 -            AnnotationValue av = entry.getValue();
 79.1593 -            if (ee.getSimpleName().contentEquals("data")) {
 79.1594 -                List<? extends Object> values = getAnnoValues(processingEnv, e, found);
 79.1595 -                for (Object v : values) {
 79.1596 -                    String sv = v.toString();
 79.1597 -                    if (sv.startsWith("data = ") && sv.endsWith(".class")) {
 79.1598 -                        return sv.substring(7, sv.length() - 6);
 79.1599 -                    }
 79.1600 -                }
 79.1601 -                return "error";
 79.1602 -            }
 79.1603 -        }
 79.1604 -        return null;
 79.1605 -    }
 79.1606 -
 79.1607 -    static List<? extends Object> getAnnoValues(ProcessingEnvironment pe, Element e, AnnotationMirror am) {
 79.1608 -        try {
 79.1609 -            Class<?> trees = Class.forName("com.sun.tools.javac.api.JavacTrees");
 79.1610 -            Method m = trees.getMethod("instance", ProcessingEnvironment.class);
 79.1611 -            Object instance = m.invoke(null, pe);
 79.1612 -            m = instance.getClass().getMethod("getPath", Element.class, AnnotationMirror.class);
 79.1613 -            Object path = m.invoke(instance, e, am);
 79.1614 -            m = path.getClass().getMethod("getLeaf");
 79.1615 -            Object leaf = m.invoke(path);
 79.1616 -            m = leaf.getClass().getMethod("getArguments");
 79.1617 -            return (List) m.invoke(leaf);
 79.1618 -        } catch (Exception ex) {
 79.1619 -            return Collections.emptyList();
 79.1620 -        }
 79.1621 -    }
 79.1622 -
 79.1623 -    private static class Prprt {
 79.1624 -        private final Element e;
 79.1625 -        private final AnnotationMirror tm;
 79.1626 -        private final Property p;
 79.1627 -
 79.1628 -        public Prprt(Element e, AnnotationMirror tm, Property p) {
 79.1629 -            this.e = e;
 79.1630 -            this.tm = tm;
 79.1631 -            this.p = p;
 79.1632 -        }
 79.1633 -        
 79.1634 -        String name() {
 79.1635 -            return p.name();
 79.1636 -        }
 79.1637 -        
 79.1638 -        boolean array() {
 79.1639 -            return p.array();
 79.1640 -        }
 79.1641 -
 79.1642 -        String typeName(ProcessingEnvironment env) {
 79.1643 -            RuntimeException ex;
 79.1644 -            try {
 79.1645 -                return p.type().getName();
 79.1646 -            } catch (IncompleteAnnotationException e) {
 79.1647 -                ex = e;
 79.1648 -            } catch (AnnotationTypeMismatchException e) {
 79.1649 -                ex = e;
 79.1650 -            }
 79.1651 -            for (Object v : getAnnoValues(env, e, tm)) {
 79.1652 -                String s = v.toString().replace(" ", "");
 79.1653 -                if (s.startsWith("type=") && s.endsWith(".class")) {
 79.1654 -                    return s.substring(5, s.length() - 6);
 79.1655 -                }
 79.1656 -            }
 79.1657 -            throw ex;
 79.1658 -        }
 79.1659 -        
 79.1660 -        
 79.1661 -        static Prprt[] wrap(ProcessingEnvironment pe, Element e, Property[] arr) {
 79.1662 -            if (arr.length == 0) {
 79.1663 -                return new Prprt[0];
 79.1664 -            }
 79.1665 -            
 79.1666 -            if (e.getKind() != ElementKind.CLASS) {
 79.1667 -                throw new IllegalStateException("" + e.getKind());
 79.1668 -            }
 79.1669 -            TypeElement te = (TypeElement)e;
 79.1670 -            List<? extends AnnotationValue> val = null;
 79.1671 -            for (AnnotationMirror an : te.getAnnotationMirrors()) {
 79.1672 -                for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : an.getElementValues().entrySet()) {
 79.1673 -                    if (entry.getKey().getSimpleName().contentEquals("properties")) {
 79.1674 -                        val = (List)entry.getValue().getValue();
 79.1675 -                        break;
 79.1676 -                    }
 79.1677 -                }
 79.1678 -            }
 79.1679 -            if (val == null || val.size() != arr.length) {
 79.1680 -                pe.getMessager().printMessage(Diagnostic.Kind.ERROR, "" + val, e);
 79.1681 -                return new Prprt[0];
 79.1682 -            }
 79.1683 -            Prprt[] ret = new Prprt[arr.length];
 79.1684 -            BIG: for (int i = 0; i < ret.length; i++) {
 79.1685 -                AnnotationMirror am = (AnnotationMirror)val.get(i).getValue();
 79.1686 -                ret[i] = new Prprt(e, am, arr[i]);
 79.1687 -                
 79.1688 -            }
 79.1689 -            return ret;
 79.1690 -        }
 79.1691 -    }
 79.1692 -
 79.1693 -    @Override
 79.1694 -    public Iterable<? extends Completion> getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) {
 79.1695 -        final Level l = Level.FINE;
 79.1696 -        LOG.log(l, " element: {0}", element);
 79.1697 -        LOG.log(l, " annotation: {0}", annotation);
 79.1698 -        LOG.log(l, " member: {0}", member);
 79.1699 -        LOG.log(l, " userText: {0}", userText);
 79.1700 -        LOG.log(l, "str: {0}", annotation.getAnnotationType().toString());
 79.1701 -        if (annotation.getAnnotationType().toString().equals(OnReceive.class.getName())) {
 79.1702 -            if (member.getSimpleName().contentEquals("method")) {
 79.1703 -                return Arrays.asList(
 79.1704 -                    methodOf("GET"),
 79.1705 -                    methodOf("POST"),
 79.1706 -                    methodOf("PUT"),
 79.1707 -                    methodOf("DELETE"),
 79.1708 -                    methodOf("HEAD"),
 79.1709 -                    methodOf("WebSocket")
 79.1710 -                );
 79.1711 -            }
 79.1712 -        }
 79.1713 -        
 79.1714 -        return super.getCompletions(element, annotation, member, userText);
 79.1715 -    }
 79.1716 -    
 79.1717 -    private static final Completion methodOf(String method) {
 79.1718 -        ResourceBundle rb = ResourceBundle.getBundle("org.apidesign.html.json.impl.Bundle");
 79.1719 -        return Completions.of('"' + method + '"', rb.getString("MSG_Completion_" + method));
 79.1720 -    }
 79.1721 -    
 79.1722 -    private boolean findOnError(ExecutableElement errElem, TypeElement te, String name, String className) {
 79.1723 -        String err = null;
 79.1724 -        METHODS:
 79.1725 -        for (Element e : te.getEnclosedElements()) {
 79.1726 -            if (e.getKind() != ElementKind.METHOD) {
 79.1727 -                continue;
 79.1728 -            }
 79.1729 -            if (!e.getSimpleName().contentEquals(name)) {
 79.1730 -                continue;
 79.1731 -            }
 79.1732 -            if (!e.getModifiers().contains(Modifier.STATIC)) {
 79.1733 -                errElem = (ExecutableElement) e;
 79.1734 -                err = "Would have to be static";
 79.1735 -                continue;
 79.1736 -            }
 79.1737 -            ExecutableElement ee = (ExecutableElement) e;
 79.1738 -            TypeMirror excType = processingEnv.getElementUtils().getTypeElement(Exception.class.getName()).asType();
 79.1739 -            final List<? extends VariableElement> params = ee.getParameters();
 79.1740 -            boolean error = false;
 79.1741 -            if (params.size() != 2) {
 79.1742 -                error = true;
 79.1743 -            } else {
 79.1744 -                String firstType = params.get(0).asType().toString();
 79.1745 -                int lastDot = firstType.lastIndexOf('.');
 79.1746 -                if (lastDot != -1) {
 79.1747 -                    firstType = firstType.substring(lastDot + 1);
 79.1748 -                }
 79.1749 -                if (!firstType.equals(className)) {
 79.1750 -                    error = true;
 79.1751 -                }
 79.1752 -                if (!processingEnv.getTypeUtils().isAssignable(excType, params.get(1).asType())) {
 79.1753 -                    error = true;
 79.1754 -                }
 79.1755 -            }
 79.1756 -            if (error) {
 79.1757 -                errElem = (ExecutableElement) e;
 79.1758 -                err = "Error method first argument needs to be " + className + " and second Exception";
 79.1759 -                continue;
 79.1760 -            }
 79.1761 -            return true;
 79.1762 -        }
 79.1763 -        if (err == null) {
 79.1764 -            err = "Cannot find " + name + "(" + className + ", Exception) method in this class";
 79.1765 -        }
 79.1766 -        error(err, errElem);
 79.1767 -        return false;
 79.1768 -    }
 79.1769 -    
 79.1770 -}
    80.1 --- a/json/src/main/java/org/apidesign/html/json/impl/PropertyBindingAccessor.java	Mon Dec 16 15:48:09 2013 +0100
    80.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    80.3 @@ -1,135 +0,0 @@
    80.4 -/**
    80.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    80.6 - *
    80.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    80.8 - *
    80.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   80.10 - * Other names may be trademarks of their respective owners.
   80.11 - *
   80.12 - * The contents of this file are subject to the terms of either the GNU
   80.13 - * General Public License Version 2 only ("GPL") or the Common
   80.14 - * Development and Distribution License("CDDL") (collectively, the
   80.15 - * "License"). You may not use this file except in compliance with the
   80.16 - * License. You can obtain a copy of the License at
   80.17 - * http://www.netbeans.org/cddl-gplv2.html
   80.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   80.19 - * specific language governing permissions and limitations under the
   80.20 - * License.  When distributing the software, include this License Header
   80.21 - * Notice in each file and include the License file at
   80.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   80.23 - * particular file as subject to the "Classpath" exception as provided
   80.24 - * by Oracle in the GPL Version 2 section of the License file that
   80.25 - * accompanied this code. If applicable, add the following below the
   80.26 - * License Header, with the fields enclosed by brackets [] replaced by
   80.27 - * your own identifying information:
   80.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   80.29 - *
   80.30 - * Contributor(s):
   80.31 - *
   80.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   80.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   80.34 - *
   80.35 - * If you wish your version of this file to be governed by only the CDDL
   80.36 - * or only the GPL Version 2, indicate your decision by adding
   80.37 - * "[Contributor] elects to include this software in this distribution
   80.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   80.39 - * single choice of license, a recipient has the option to distribute
   80.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   80.41 - * to extend the choice of license to its licensees as provided above.
   80.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   80.43 - * Version 2 license, then the option applies only if the new code is
   80.44 - * made subject to such option by the copyright holder.
   80.45 - */
   80.46 -package org.apidesign.html.json.impl;
   80.47 -
   80.48 -import net.java.html.BrwsrCtx;
   80.49 -import org.apidesign.html.json.spi.FunctionBinding;
   80.50 -import org.apidesign.html.json.spi.JSONCall;
   80.51 -import org.apidesign.html.json.spi.PropertyBinding;
   80.52 -
   80.53 -/**
   80.54 - *
   80.55 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   80.56 - */
   80.57 -public abstract class PropertyBindingAccessor {
   80.58 -    private static PropertyBindingAccessor DEFAULT;
   80.59 -
   80.60 -    protected PropertyBindingAccessor() {
   80.61 -        if (DEFAULT != null) throw new IllegalStateException();
   80.62 -        DEFAULT = this;
   80.63 -    }
   80.64 -    
   80.65 -    static {
   80.66 -        JSON.initClass(PropertyBinding.class);
   80.67 -    }
   80.68 -
   80.69 -    protected abstract <M> PropertyBinding newBinding(PBData<M> d);
   80.70 -    protected abstract <M> FunctionBinding newFunction(FBData<M> d);
   80.71 -    protected abstract JSONCall newCall(
   80.72 -        BrwsrCtx ctx, RcvrJSON callback, String urlBefore, String urlAfter,
   80.73 -        String method, Object data
   80.74 -    );
   80.75 -
   80.76 -    
   80.77 -    static <M> PropertyBinding create(PBData<M> d) {
   80.78 -        return DEFAULT.newBinding(d);
   80.79 -    }
   80.80 -    static <M> FunctionBinding createFunction(FBData<M> d) {
   80.81 -        return DEFAULT.newFunction(d);
   80.82 -    }
   80.83 -    static JSONCall createCall(
   80.84 -        BrwsrCtx ctx, RcvrJSON callback, String urlBefore, String urlAfter, 
   80.85 -        String method, Object data
   80.86 -    ) {
   80.87 -        return DEFAULT.newCall(ctx, callback, urlBefore, urlAfter, method, data);
   80.88 -    }
   80.89 -
   80.90 -    public static final class PBData<M> {
   80.91 -        public final String name;
   80.92 -        public final boolean readOnly;
   80.93 -        private final M model;
   80.94 -        private final SetAndGet<M> access;
   80.95 -        private final Bindings<?> bindings;
   80.96 -
   80.97 -        public PBData(Bindings<?> bindings, String name, M model, SetAndGet<M> access, boolean readOnly) {
   80.98 -            this.bindings = bindings;
   80.99 -            this.name = name;
  80.100 -            this.model = model;
  80.101 -            this.access = access;
  80.102 -            this.readOnly = readOnly;
  80.103 -        }
  80.104 -
  80.105 -        public void setValue(Object v) {
  80.106 -            access.setValue(model, v);
  80.107 -        }
  80.108 -
  80.109 -        public Object getValue() {
  80.110 -            return access.getValue(model);
  80.111 -        }
  80.112 -
  80.113 -        public boolean isReadOnly() {
  80.114 -            return readOnly;
  80.115 -        }
  80.116 -
  80.117 -        public Bindings getBindings() {
  80.118 -            return bindings;
  80.119 -        }
  80.120 -    } // end of PBData
  80.121 -    
  80.122 -    public static final class FBData<M> {
  80.123 -        public final String name;
  80.124 -        private final M model;
  80.125 -        private final Callback<M> access;
  80.126 -
  80.127 -        public FBData(String name, M model, Callback<M> access) {
  80.128 -            this.name = name;
  80.129 -            this.model = model;
  80.130 -            this.access = access;
  80.131 -        }
  80.132 -
  80.133 -
  80.134 -        public void call(Object data, Object ev) {
  80.135 -            access.call(model, data, ev);
  80.136 -        }
  80.137 -    } // end of FBData
  80.138 -}
    81.1 --- a/json/src/main/java/org/apidesign/html/json/impl/RcvrJSON.java	Mon Dec 16 15:48:09 2013 +0100
    81.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    81.3 @@ -1,149 +0,0 @@
    81.4 -/**
    81.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    81.6 - *
    81.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    81.8 - *
    81.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   81.10 - * Other names may be trademarks of their respective owners.
   81.11 - *
   81.12 - * The contents of this file are subject to the terms of either the GNU
   81.13 - * General Public License Version 2 only ("GPL") or the Common
   81.14 - * Development and Distribution License("CDDL") (collectively, the
   81.15 - * "License"). You may not use this file except in compliance with the
   81.16 - * License. You can obtain a copy of the License at
   81.17 - * http://www.netbeans.org/cddl-gplv2.html
   81.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   81.19 - * specific language governing permissions and limitations under the
   81.20 - * License.  When distributing the software, include this License Header
   81.21 - * Notice in each file and include the License file at
   81.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   81.23 - * particular file as subject to the "Classpath" exception as provided
   81.24 - * by Oracle in the GPL Version 2 section of the License file that
   81.25 - * accompanied this code. If applicable, add the following below the
   81.26 - * License Header, with the fields enclosed by brackets [] replaced by
   81.27 - * your own identifying information:
   81.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   81.29 - *
   81.30 - * Contributor(s):
   81.31 - *
   81.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   81.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   81.34 - *
   81.35 - * If you wish your version of this file to be governed by only the CDDL
   81.36 - * or only the GPL Version 2, indicate your decision by adding
   81.37 - * "[Contributor] elects to include this software in this distribution
   81.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   81.39 - * single choice of license, a recipient has the option to distribute
   81.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   81.41 - * to extend the choice of license to its licensees as provided above.
   81.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   81.43 - * Version 2 license, then the option applies only if the new code is
   81.44 - * made subject to such option by the copyright holder.
   81.45 - */
   81.46 -package org.apidesign.html.json.impl;
   81.47 -
   81.48 -import net.java.html.BrwsrCtx;
   81.49 -
   81.50 -/** Super type for those who wish to receive JSON messages.
   81.51 - *
   81.52 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   81.53 - */
   81.54 -public abstract class RcvrJSON {
   81.55 -    protected void onOpen(MsgEvnt msg) {}
   81.56 -    protected abstract void onMessage(MsgEvnt msg);
   81.57 -    protected void onClose(MsgEvnt msg) {}
   81.58 -    protected abstract void onError(MsgEvnt msg);
   81.59 -    
   81.60 -    public abstract static class MsgEvnt {
   81.61 -        MsgEvnt() {
   81.62 -        }
   81.63 -        
   81.64 -        public Throwable getError() {
   81.65 -            return null;
   81.66 -        }
   81.67 -        
   81.68 -        public final Exception getException() {
   81.69 -            Throwable t = getError();
   81.70 -            if (t instanceof Exception) {
   81.71 -                return (Exception)t;
   81.72 -            }
   81.73 -            if (t == null) {
   81.74 -                return null;
   81.75 -            }
   81.76 -            return new Exception(t);
   81.77 -        }
   81.78 -        
   81.79 -        public int dataSize() {
   81.80 -            return -1;
   81.81 -        }
   81.82 -        
   81.83 -        public <Data> void dataRead(BrwsrCtx ctx, Class<? extends Data> type, Data[] fillTheArray) {
   81.84 -        }
   81.85 -
   81.86 -        public abstract void dispatch(RcvrJSON r);
   81.87 -        
   81.88 -        public static MsgEvnt createError(final Throwable t) {
   81.89 -            return new MsgEvnt() {
   81.90 -                @Override
   81.91 -                public Throwable getError() {
   81.92 -                    return t;
   81.93 -                }
   81.94 -
   81.95 -                @Override
   81.96 -                public void dispatch(RcvrJSON r) {
   81.97 -                    r.onError(this);
   81.98 -                }
   81.99 -            };
  81.100 -        }
  81.101 -        
  81.102 -        public static MsgEvnt createMessage(final Object value) {
  81.103 -            return new MsgEvnt() {
  81.104 -                @Override
  81.105 -                public int dataSize() {
  81.106 -                    if (value instanceof Object[]) {
  81.107 -                        return ((Object[])value).length;
  81.108 -                    } else {
  81.109 -                        return 1;
  81.110 -                    }
  81.111 -                }
  81.112 -                
  81.113 -                @Override
  81.114 -                public <Data> void dataRead(BrwsrCtx context, Class<? extends Data> type, Data[] arr) {
  81.115 -                    if (value instanceof Object[]) {
  81.116 -                        Object[] data = ((Object[]) value);
  81.117 -                        for (int i = 0; i < data.length && i < arr.length; i++) {
  81.118 -                            arr[i] = org.apidesign.html.json.impl.JSON.read(context, type, data[i]);
  81.119 -                        }
  81.120 -                    } else {
  81.121 -                        if (arr.length > 0) {
  81.122 -                            arr[0] = org.apidesign.html.json.impl.JSON.read(context, type, value);
  81.123 -                        }
  81.124 -                    }
  81.125 -                }
  81.126 -                
  81.127 -                @Override
  81.128 -                public void dispatch(RcvrJSON r) {
  81.129 -                    r.onMessage(this);
  81.130 -                }
  81.131 -            };
  81.132 -        }
  81.133 -        
  81.134 -        public static MsgEvnt createOpen() {
  81.135 -            return new MsgEvnt() {
  81.136 -                @Override
  81.137 -                public void dispatch(RcvrJSON r) {
  81.138 -                    r.onOpen(this);
  81.139 -                }
  81.140 -            };
  81.141 -        }
  81.142 -
  81.143 -        public static MsgEvnt createClose() {
  81.144 -            return new MsgEvnt() {
  81.145 -                @Override
  81.146 -                public void dispatch(RcvrJSON r) {
  81.147 -                    r.onClose(this);
  81.148 -                }
  81.149 -            };
  81.150 -        }
  81.151 -    } // end MsgEvnt
  81.152 -}
    82.1 --- a/json/src/main/java/org/apidesign/html/json/impl/SetAndGet.java	Mon Dec 16 15:48:09 2013 +0100
    82.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    82.3 @@ -1,54 +0,0 @@
    82.4 -/**
    82.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    82.6 - *
    82.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    82.8 - *
    82.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   82.10 - * Other names may be trademarks of their respective owners.
   82.11 - *
   82.12 - * The contents of this file are subject to the terms of either the GNU
   82.13 - * General Public License Version 2 only ("GPL") or the Common
   82.14 - * Development and Distribution License("CDDL") (collectively, the
   82.15 - * "License"). You may not use this file except in compliance with the
   82.16 - * License. You can obtain a copy of the License at
   82.17 - * http://www.netbeans.org/cddl-gplv2.html
   82.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   82.19 - * specific language governing permissions and limitations under the
   82.20 - * License.  When distributing the software, include this License Header
   82.21 - * Notice in each file and include the License file at
   82.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   82.23 - * particular file as subject to the "Classpath" exception as provided
   82.24 - * by Oracle in the GPL Version 2 section of the License file that
   82.25 - * accompanied this code. If applicable, add the following below the
   82.26 - * License Header, with the fields enclosed by brackets [] replaced by
   82.27 - * your own identifying information:
   82.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   82.29 - *
   82.30 - * Contributor(s):
   82.31 - *
   82.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   82.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   82.34 - *
   82.35 - * If you wish your version of this file to be governed by only the CDDL
   82.36 - * or only the GPL Version 2, indicate your decision by adding
   82.37 - * "[Contributor] elects to include this software in this distribution
   82.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   82.39 - * single choice of license, a recipient has the option to distribute
   82.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   82.41 - * to extend the choice of license to its licensees as provided above.
   82.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   82.43 - * Version 2 license, then the option applies only if the new code is
   82.44 - * made subject to such option by the copyright holder.
   82.45 - */
   82.46 -package org.apidesign.html.json.impl;
   82.47 -
   82.48 -import org.apidesign.html.json.spi.PropertyBinding;
   82.49 -
   82.50 -/** A way to implement a {@link PropertyBinding}.
   82.51 - *
   82.52 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   82.53 - */
   82.54 -public interface SetAndGet<Data> {
   82.55 -    public void setValue(Data data, Object value);
   82.56 -    public Object getValue(Data data);
   82.57 -}
    83.1 --- a/json/src/main/java/org/apidesign/html/json/impl/WrapperObject.java	Mon Dec 16 15:48:09 2013 +0100
    83.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    83.3 @@ -1,82 +0,0 @@
    83.4 -/**
    83.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    83.6 - *
    83.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    83.8 - *
    83.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   83.10 - * Other names may be trademarks of their respective owners.
   83.11 - *
   83.12 - * The contents of this file are subject to the terms of either the GNU
   83.13 - * General Public License Version 2 only ("GPL") or the Common
   83.14 - * Development and Distribution License("CDDL") (collectively, the
   83.15 - * "License"). You may not use this file except in compliance with the
   83.16 - * License. You can obtain a copy of the License at
   83.17 - * http://www.netbeans.org/cddl-gplv2.html
   83.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   83.19 - * specific language governing permissions and limitations under the
   83.20 - * License.  When distributing the software, include this License Header
   83.21 - * Notice in each file and include the License file at
   83.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   83.23 - * particular file as subject to the "Classpath" exception as provided
   83.24 - * by Oracle in the GPL Version 2 section of the License file that
   83.25 - * accompanied this code. If applicable, add the following below the
   83.26 - * License Header, with the fields enclosed by brackets [] replaced by
   83.27 - * your own identifying information:
   83.28 - * "Portions Copyrighted [year] [name of copyright owner]"
   83.29 - *
   83.30 - * Contributor(s):
   83.31 - *
   83.32 - * The Original Software is NetBeans. The Initial Developer of the Original
   83.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   83.34 - *
   83.35 - * If you wish your version of this file to be governed by only the CDDL
   83.36 - * or only the GPL Version 2, indicate your decision by adding
   83.37 - * "[Contributor] elects to include this software in this distribution
   83.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
   83.39 - * single choice of license, a recipient has the option to distribute
   83.40 - * your version of this file under either the CDDL, the GPL Version 2 or
   83.41 - * to extend the choice of license to its licensees as provided above.
   83.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
   83.43 - * Version 2 license, then the option applies only if the new code is
   83.44 - * made subject to such option by the copyright holder.
   83.45 - */
   83.46 -package org.apidesign.html.json.impl;
   83.47 -
   83.48 -import java.util.Collection;
   83.49 -import org.apidesign.html.json.impl.PropertyBindingAccessor.PBData;
   83.50 -
   83.51 -/** A way to extract real object from a model classes.
   83.52 - *
   83.53 - * @author Jaroslav Tulach <jtulach@netbeans.org>
   83.54 - */
   83.55 -public final class WrapperObject {
   83.56 -    private Object ko;
   83.57 -    
   83.58 -    private WrapperObject() {
   83.59 -    }
   83.60 -    
   83.61 -    public void setRealObject(Object ko) {
   83.62 -        this.ko = ko;
   83.63 -    }
   83.64 -    
   83.65 -    public static Object find(Object object) {
   83.66 -        return find(object, null);
   83.67 -    }
   83.68 -    
   83.69 -    public static Object find(Object object, Bindings model) {
   83.70 -        if (object == null) {
   83.71 -            return null;
   83.72 -        }
   83.73 -        
   83.74 -        if (object instanceof JSONList) {
   83.75 -            return ((JSONList<?>)object).koData();
   83.76 -        }
   83.77 -        if (object instanceof Collection) {
   83.78 -            return JSONList.koData((Collection<?>)object, model);
   83.79 -        }
   83.80 -        
   83.81 -        WrapperObject ro = new WrapperObject();
   83.82 -        object.equals(ro);
   83.83 -        return ro.ko;
   83.84 -    }
   83.85 -}
    84.1 --- a/json/src/main/java/org/apidesign/html/json/spi/FunctionBinding.java	Mon Dec 16 15:48:09 2013 +0100
    84.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/FunctionBinding.java	Mon Dec 16 16:59:43 2013 +0100
    84.3 @@ -44,7 +44,7 @@
    84.4  
    84.5  import net.java.html.json.Function;
    84.6  import net.java.html.json.Model;
    84.7 -import org.apidesign.html.json.impl.PropertyBindingAccessor.FBData;
    84.8 +import org.netbeans.html.json.impl.PropertyBindingAccessor.FBData;
    84.9  
   84.10  /** Describes a function provided by the {@link Model} and 
   84.11   * annotated by {@link Function} annotation.
    85.1 --- a/json/src/main/java/org/apidesign/html/json/spi/JSONCall.java	Mon Dec 16 15:48:09 2013 +0100
    85.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/JSONCall.java	Mon Dec 16 16:59:43 2013 +0100
    85.3 @@ -45,8 +45,8 @@
    85.4  import java.io.IOException;
    85.5  import java.io.OutputStream;
    85.6  import net.java.html.BrwsrCtx;
    85.7 -import org.apidesign.html.json.impl.JSON;
    85.8 -import org.apidesign.html.json.impl.RcvrJSON;
    85.9 +import org.netbeans.html.json.impl.JSON;
   85.10 +import org.netbeans.html.json.impl.RcvrJSON;
   85.11  
   85.12  /** Description of a JSON call request that is supposed to be processed
   85.13   * by {@link Transfer#loadJSON(org.apidesign.html.json.spi.JSONCall)} implementors.
    86.1 --- a/json/src/main/java/org/apidesign/html/json/spi/PropertyBinding.java	Mon Dec 16 15:48:09 2013 +0100
    86.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/PropertyBinding.java	Mon Dec 16 16:59:43 2013 +0100
    86.3 @@ -43,10 +43,10 @@
    86.4  package org.apidesign.html.json.spi;
    86.5  
    86.6  import net.java.html.BrwsrCtx;
    86.7 -import org.apidesign.html.json.impl.PropertyBindingAccessor;
    86.8 -import org.apidesign.html.json.impl.PropertyBindingAccessor.PBData;
    86.9 -import org.apidesign.html.json.impl.RcvrJSON;
   86.10 -import org.apidesign.html.json.impl.WrapperObject;
   86.11 +import org.netbeans.html.json.impl.PropertyBindingAccessor;
   86.12 +import org.netbeans.html.json.impl.PropertyBindingAccessor.PBData;
   86.13 +import org.netbeans.html.json.impl.RcvrJSON;
   86.14 +import org.netbeans.html.json.impl.WrapperObject;
   86.15  
   86.16  /** Describes a property when one is asked to 
   86.17   * bind it 
    87.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    87.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/Bindings.java	Mon Dec 16 16:59:43 2013 +0100
    87.3 @@ -0,0 +1,113 @@
    87.4 +/**
    87.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    87.6 + *
    87.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    87.8 + *
    87.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   87.10 + * Other names may be trademarks of their respective owners.
   87.11 + *
   87.12 + * The contents of this file are subject to the terms of either the GNU
   87.13 + * General Public License Version 2 only ("GPL") or the Common
   87.14 + * Development and Distribution License("CDDL") (collectively, the
   87.15 + * "License"). You may not use this file except in compliance with the
   87.16 + * License. You can obtain a copy of the License at
   87.17 + * http://www.netbeans.org/cddl-gplv2.html
   87.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   87.19 + * specific language governing permissions and limitations under the
   87.20 + * License.  When distributing the software, include this License Header
   87.21 + * Notice in each file and include the License file at
   87.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   87.23 + * particular file as subject to the "Classpath" exception as provided
   87.24 + * by Oracle in the GPL Version 2 section of the License file that
   87.25 + * accompanied this code. If applicable, add the following below the
   87.26 + * License Header, with the fields enclosed by brackets [] replaced by
   87.27 + * your own identifying information:
   87.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   87.29 + *
   87.30 + * Contributor(s):
   87.31 + *
   87.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   87.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   87.34 + *
   87.35 + * If you wish your version of this file to be governed by only the CDDL
   87.36 + * or only the GPL Version 2, indicate your decision by adding
   87.37 + * "[Contributor] elects to include this software in this distribution
   87.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   87.39 + * single choice of license, a recipient has the option to distribute
   87.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   87.41 + * to extend the choice of license to its licensees as provided above.
   87.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   87.43 + * Version 2 license, then the option applies only if the new code is
   87.44 + * made subject to such option by the copyright holder.
   87.45 + */
   87.46 +package org.netbeans.html.json.impl;
   87.47 +
   87.48 +import org.apidesign.html.json.spi.PropertyBinding;
   87.49 +import net.java.html.BrwsrCtx;
   87.50 +import org.netbeans.html.json.impl.PropertyBindingAccessor.FBData;
   87.51 +import org.netbeans.html.json.impl.PropertyBindingAccessor.PBData;
   87.52 +import org.apidesign.html.json.spi.FunctionBinding;
   87.53 +import org.apidesign.html.json.spi.Technology;
   87.54 +
   87.55 +/**
   87.56 + *
   87.57 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   87.58 + */
   87.59 +public final class Bindings<Data> {
   87.60 +    private Data data;
   87.61 +    private final Technology<Data> bp;
   87.62 +
   87.63 +    private Bindings(Technology<Data> bp) {
   87.64 +        this.bp = bp;
   87.65 +    }
   87.66 +    
   87.67 +    public <M> PropertyBinding registerProperty(String propName, M model, SetAndGet<M> access, boolean readOnly) {
   87.68 +        return PropertyBindingAccessor.create(new PBData<M>(this, propName, model, access, readOnly));
   87.69 +    }
   87.70 +
   87.71 +    public <M> FunctionBinding registerFunction(String name, M model, Callback<M> access) {
   87.72 +        return PropertyBindingAccessor.createFunction(new FBData<M>(name, model, access));
   87.73 +    }
   87.74 +    
   87.75 +    public static Bindings<?> apply(BrwsrCtx c, Object model) {
   87.76 +        Technology<?> bp = JSON.findTechnology(c);
   87.77 +        return apply(bp);
   87.78 +    }
   87.79 +    
   87.80 +    private static <Data> Bindings<Data> apply(Technology<Data> bp) {
   87.81 +        return new Bindings<Data>(bp);
   87.82 +    }
   87.83 +    
   87.84 +    public final void finish(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
   87.85 +        assert data == null;
   87.86 +        if (bp instanceof Technology.BatchInit) {
   87.87 +            Technology.BatchInit<Data> bi = (Technology.BatchInit<Data>)bp;
   87.88 +            data = bi.wrapModel(model, propArr, funcArr);
   87.89 +        } else {
   87.90 +            data = bp.wrapModel(model);
   87.91 +            for (PropertyBinding b : propArr) {
   87.92 +                bp.bind(b, model, data);
   87.93 +            }
   87.94 +            for (FunctionBinding b : funcArr) {
   87.95 +                bp.expose(b, model, data);
   87.96 +            }
   87.97 +        }
   87.98 +    }
   87.99 +    
  87.100 +    
  87.101 +    public Data koData() {
  87.102 +        return data;
  87.103 +    }
  87.104 +
  87.105 +    public void valueHasMutated(String firstName) {
  87.106 +        bp.valueHasMutated(data, firstName);
  87.107 +    }
  87.108 +    
  87.109 +    public void applyBindings() {
  87.110 +        bp.applyBindings(data);
  87.111 +    }
  87.112 +
  87.113 +    Object wrapArray(Object[] arr) {
  87.114 +        return bp.wrapArray(arr);
  87.115 +    }
  87.116 +}
    88.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    88.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/Callback.java	Mon Dec 16 16:59:43 2013 +0100
    88.3 @@ -0,0 +1,51 @@
    88.4 +/**
    88.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    88.6 + *
    88.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    88.8 + *
    88.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   88.10 + * Other names may be trademarks of their respective owners.
   88.11 + *
   88.12 + * The contents of this file are subject to the terms of either the GNU
   88.13 + * General Public License Version 2 only ("GPL") or the Common
   88.14 + * Development and Distribution License("CDDL") (collectively, the
   88.15 + * "License"). You may not use this file except in compliance with the
   88.16 + * License. You can obtain a copy of the License at
   88.17 + * http://www.netbeans.org/cddl-gplv2.html
   88.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   88.19 + * specific language governing permissions and limitations under the
   88.20 + * License.  When distributing the software, include this License Header
   88.21 + * Notice in each file and include the License file at
   88.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   88.23 + * particular file as subject to the "Classpath" exception as provided
   88.24 + * by Oracle in the GPL Version 2 section of the License file that
   88.25 + * accompanied this code. If applicable, add the following below the
   88.26 + * License Header, with the fields enclosed by brackets [] replaced by
   88.27 + * your own identifying information:
   88.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   88.29 + *
   88.30 + * Contributor(s):
   88.31 + *
   88.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   88.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   88.34 + *
   88.35 + * If you wish your version of this file to be governed by only the CDDL
   88.36 + * or only the GPL Version 2, indicate your decision by adding
   88.37 + * "[Contributor] elects to include this software in this distribution
   88.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   88.39 + * single choice of license, a recipient has the option to distribute
   88.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   88.41 + * to extend the choice of license to its licensees as provided above.
   88.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   88.43 + * Version 2 license, then the option applies only if the new code is
   88.44 + * made subject to such option by the copyright holder.
   88.45 + */
   88.46 +package org.netbeans.html.json.impl;
   88.47 +
   88.48 +/**
   88.49 + *
   88.50 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   88.51 + */
   88.52 +public interface Callback<Data> {
   88.53 +    public void call(Data model, Object data, Object ev);
   88.54 +}
    89.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    89.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/FromJSON.java	Mon Dec 16 16:59:43 2013 +0100
    89.3 @@ -0,0 +1,55 @@
    89.4 +/**
    89.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    89.6 + *
    89.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    89.8 + *
    89.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   89.10 + * Other names may be trademarks of their respective owners.
   89.11 + *
   89.12 + * The contents of this file are subject to the terms of either the GNU
   89.13 + * General Public License Version 2 only ("GPL") or the Common
   89.14 + * Development and Distribution License("CDDL") (collectively, the
   89.15 + * "License"). You may not use this file except in compliance with the
   89.16 + * License. You can obtain a copy of the License at
   89.17 + * http://www.netbeans.org/cddl-gplv2.html
   89.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   89.19 + * specific language governing permissions and limitations under the
   89.20 + * License.  When distributing the software, include this License Header
   89.21 + * Notice in each file and include the License file at
   89.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   89.23 + * particular file as subject to the "Classpath" exception as provided
   89.24 + * by Oracle in the GPL Version 2 section of the License file that
   89.25 + * accompanied this code. If applicable, add the following below the
   89.26 + * License Header, with the fields enclosed by brackets [] replaced by
   89.27 + * your own identifying information:
   89.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   89.29 + *
   89.30 + * Contributor(s):
   89.31 + *
   89.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   89.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   89.34 + *
   89.35 + * If you wish your version of this file to be governed by only the CDDL
   89.36 + * or only the GPL Version 2, indicate your decision by adding
   89.37 + * "[Contributor] elects to include this software in this distribution
   89.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   89.39 + * single choice of license, a recipient has the option to distribute
   89.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   89.41 + * to extend the choice of license to its licensees as provided above.
   89.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   89.43 + * Version 2 license, then the option applies only if the new code is
   89.44 + * made subject to such option by the copyright holder.
   89.45 + */
   89.46 +package org.netbeans.html.json.impl;
   89.47 +
   89.48 +import net.java.html.BrwsrCtx;
   89.49 +
   89.50 +/**
   89.51 + *
   89.52 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   89.53 + */
   89.54 +public interface FromJSON<Data> {
   89.55 +    public Class<Data> factoryFor();
   89.56 +    public Data read(BrwsrCtx c, Object d);
   89.57 +    public Data cloneTo(Object d, BrwsrCtx c);
   89.58 +}
    90.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    90.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/JSON.java	Mon Dec 16 16:59:43 2013 +0100
    90.3 @@ -0,0 +1,474 @@
    90.4 +/**
    90.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    90.6 + *
    90.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    90.8 + *
    90.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   90.10 + * Other names may be trademarks of their respective owners.
   90.11 + *
   90.12 + * The contents of this file are subject to the terms of either the GNU
   90.13 + * General Public License Version 2 only ("GPL") or the Common
   90.14 + * Development and Distribution License("CDDL") (collectively, the
   90.15 + * "License"). You may not use this file except in compliance with the
   90.16 + * License. You can obtain a copy of the License at
   90.17 + * http://www.netbeans.org/cddl-gplv2.html
   90.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   90.19 + * specific language governing permissions and limitations under the
   90.20 + * License.  When distributing the software, include this License Header
   90.21 + * Notice in each file and include the License file at
   90.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   90.23 + * particular file as subject to the "Classpath" exception as provided
   90.24 + * by Oracle in the GPL Version 2 section of the License file that
   90.25 + * accompanied this code. If applicable, add the following below the
   90.26 + * License Header, with the fields enclosed by brackets [] replaced by
   90.27 + * your own identifying information:
   90.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   90.29 + *
   90.30 + * Contributor(s):
   90.31 + *
   90.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   90.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   90.34 + *
   90.35 + * If you wish your version of this file to be governed by only the CDDL
   90.36 + * or only the GPL Version 2, indicate your decision by adding
   90.37 + * "[Contributor] elects to include this software in this distribution
   90.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   90.39 + * single choice of license, a recipient has the option to distribute
   90.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   90.41 + * to extend the choice of license to its licensees as provided above.
   90.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   90.43 + * Version 2 license, then the option applies only if the new code is
   90.44 + * made subject to such option by the copyright holder.
   90.45 + */
   90.46 +package org.netbeans.html.json.impl;
   90.47 +
   90.48 +import java.io.IOException;
   90.49 +import java.io.InputStream;
   90.50 +import java.util.HashMap;
   90.51 +import java.util.Map;
   90.52 +import net.java.html.BrwsrCtx;
   90.53 +import org.apidesign.html.context.spi.Contexts;
   90.54 +import org.apidesign.html.json.spi.FunctionBinding;
   90.55 +import org.apidesign.html.json.spi.JSONCall;
   90.56 +import org.apidesign.html.json.spi.PropertyBinding;
   90.57 +import org.apidesign.html.json.spi.Technology;
   90.58 +import org.apidesign.html.json.spi.Transfer;
   90.59 +import org.apidesign.html.json.spi.WSTransfer;
   90.60 +
   90.61 +/**
   90.62 + *
   90.63 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   90.64 + */
   90.65 +public final class JSON {
   90.66 +    private JSON() {
   90.67 +    }
   90.68 +
   90.69 +    static Technology<?> findTechnology(BrwsrCtx c) {
   90.70 +        Technology<?> t = Contexts.find(c, Technology.class);
   90.71 +        return t == null ? EmptyTech.EMPTY : t;
   90.72 +    }
   90.73 +
   90.74 +    static Transfer findTransfer(BrwsrCtx c) {
   90.75 +        Transfer t = Contexts.find(c, Transfer.class);
   90.76 +        return t == null ? EmptyTech.EMPTY : t;
   90.77 +    }
   90.78 +
   90.79 +    static WSTransfer<?> findWSTransfer(BrwsrCtx c) {
   90.80 +        WSTransfer<?> t = Contexts.find(c, WSTransfer.class);
   90.81 +        return t == null ? EmptyTech.EMPTY : t;
   90.82 +    }
   90.83 +    
   90.84 +    public static void runInBrowser(BrwsrCtx c, Runnable runnable) {
   90.85 +        findTechnology(c).runSafe(runnable);
   90.86 +    }
   90.87 +    
   90.88 +    public static void extract(BrwsrCtx c, Object value, String[] props, Object[] values) {
   90.89 +        Transfer t = findTransfer(c);
   90.90 +        t.extract(value, props, values);
   90.91 +    }
   90.92 +    
   90.93 +    private static Object getProperty(BrwsrCtx c, Object obj, String prop) {
   90.94 +        if (prop == null) return obj;
   90.95 +        
   90.96 +        String[] arr = { prop };
   90.97 +        Object[] val = { null };
   90.98 +        extract(c, obj, arr, val);
   90.99 +        return val[0];
  90.100 +    }
  90.101 +
  90.102 +    public static Object toJSON(Object value) {
  90.103 +        if (value == null) {
  90.104 +            return "null";
  90.105 +        }
  90.106 +        if (value instanceof Enum) {
  90.107 +            value = value.toString();
  90.108 +        }
  90.109 +        if (value instanceof String) {
  90.110 +            String s = (String)value;
  90.111 +            int len = s.length();
  90.112 +            StringBuilder sb = new StringBuilder(len + 10);
  90.113 +            sb.append('"');
  90.114 +            for (int i = 0; i < len; i++) {
  90.115 +                char ch = s.charAt(i);
  90.116 +                switch (ch) {
  90.117 +                    case '\"': sb.append("\\\""); break;
  90.118 +                    case '\n': sb.append("\\n"); break;
  90.119 +                    case '\r': sb.append("\\r"); break;
  90.120 +                    case '\t': sb.append("\\t"); break;
  90.121 +                    case '\\': sb.append("\\\\"); break;
  90.122 +                    default: sb.append(ch);
  90.123 +                }
  90.124 +            }
  90.125 +            sb.append('"');
  90.126 +            return sb.toString();
  90.127 +        }
  90.128 +        return value.toString();
  90.129 +    }
  90.130 +
  90.131 +    public static String toString(BrwsrCtx c, Object obj, String prop) {
  90.132 +        obj = getProperty(c, obj, prop);
  90.133 +        return obj instanceof String ? (String)obj : null;
  90.134 +    }
  90.135 +    public static Number toNumber(BrwsrCtx c, Object obj, String prop) {
  90.136 +        obj = getProperty(c, obj, prop);
  90.137 +        if (!(obj instanceof Number)) {
  90.138 +            obj = Double.NaN;
  90.139 +        }
  90.140 +        return (Number)obj;
  90.141 +    }
  90.142 +    public static <M> M toModel(BrwsrCtx c, Class<M> aClass, Object data, Object object) {
  90.143 +        Technology<?> t = findTechnology(c);
  90.144 +        Object o = t.toModel(aClass, data);
  90.145 +        return aClass.cast(o);
  90.146 +    }
  90.147 +    
  90.148 +    public static boolean isSame(int a, int b) {
  90.149 +        return a == b;
  90.150 +    }
  90.151 +    
  90.152 +    public static boolean isSame(double a, double b) {
  90.153 +        return a == b;
  90.154 +    }
  90.155 +    
  90.156 +    public static boolean isSame(Object a, Object b) {
  90.157 +        if (a == b) {
  90.158 +            return true;
  90.159 +        }
  90.160 +        if (a == null || b == null) {
  90.161 +            return false;
  90.162 +        }
  90.163 +        return a.equals(b);
  90.164 +    }
  90.165 +    
  90.166 +    public static int hashPlus(Object o, int h) {
  90.167 +        return o == null ? h : h ^ o.hashCode();
  90.168 +    }
  90.169 +
  90.170 +    public static <T> T extractValue(Class<T> type, Object val) {
  90.171 +        if (Number.class.isAssignableFrom(type)) {
  90.172 +            val = numberValue(val);
  90.173 +        }
  90.174 +        if (Boolean.class == type) {
  90.175 +            val = boolValue(val);
  90.176 +        }
  90.177 +        if (String.class == type) {
  90.178 +            val = stringValue(val);
  90.179 +        }
  90.180 +        if (Character.class == type) {
  90.181 +            val = charValue(val);
  90.182 +        }
  90.183 +        if (Integer.class == type) {
  90.184 +            val = val instanceof Number ? ((Number)val).intValue() : 0;
  90.185 +        }
  90.186 +        if (Long.class == type) {
  90.187 +            val = val instanceof Number  ? ((Number)val).longValue() : 0;
  90.188 +        }
  90.189 +        if (Short.class == type) {
  90.190 +            val = val instanceof Number ? ((Number)val).shortValue() : 0;
  90.191 +        }
  90.192 +        if (Byte.class == type) {
  90.193 +            val = val instanceof Number ? ((Number)val).byteValue() : 0;
  90.194 +        }        
  90.195 +        if (Double.class == type) {
  90.196 +            val = val instanceof Number ? ((Number)val).doubleValue() : Double.NaN;
  90.197 +        }
  90.198 +        if (Float.class == type) {
  90.199 +            val = val instanceof Number ? ((Number)val).floatValue() : Float.NaN;
  90.200 +        }
  90.201 +        return type.cast(val);
  90.202 +    }
  90.203 +    
  90.204 +    protected static boolean isNumeric(Object val) {
  90.205 +        return ((val instanceof Integer) || (val instanceof Long) || (val instanceof Short) || (val instanceof Byte));
  90.206 +    }
  90.207 +    
  90.208 +    public static String stringValue(Object val) {
  90.209 +        if (val instanceof Boolean) {
  90.210 +            return ((Boolean)val ? "true" : "false");
  90.211 +        }
  90.212 +        if (isNumeric(val)) {
  90.213 +            return Long.toString(((Number)val).longValue());
  90.214 +        }
  90.215 +        if (val instanceof Float) {
  90.216 +            return Float.toString((Float)val);
  90.217 +        }
  90.218 +        if (val instanceof Double) {
  90.219 +            return Double.toString((Double)val);
  90.220 +        }
  90.221 +        return (String)val;
  90.222 +    }
  90.223 +
  90.224 +    public static Number numberValue(Object val) {
  90.225 +        if (val instanceof String) {
  90.226 +            try {
  90.227 +                return Double.valueOf((String)val);
  90.228 +            } catch (NumberFormatException ex) {
  90.229 +                return Double.NaN;
  90.230 +            }
  90.231 +        }
  90.232 +        if (val instanceof Boolean) {
  90.233 +            return (Boolean)val ? 1 : 0;
  90.234 +        }
  90.235 +        return (Number)val;
  90.236 +    }
  90.237 +
  90.238 +    public static Character charValue(Object val) {
  90.239 +        if (val instanceof Number) {
  90.240 +            return Character.toChars(numberValue(val).intValue())[0];
  90.241 +        }
  90.242 +        if (val instanceof Boolean) {
  90.243 +            return (Boolean)val ? (char)1 : (char)0;
  90.244 +        }
  90.245 +        if (val instanceof String) {
  90.246 +            String s = (String)val;
  90.247 +            return s.isEmpty() ? (char)0 : s.charAt(0);
  90.248 +        }
  90.249 +        return (Character)val;
  90.250 +    }
  90.251 +    
  90.252 +    public static Boolean boolValue(Object val) {
  90.253 +        if (val instanceof String) {
  90.254 +            return Boolean.parseBoolean((String)val);
  90.255 +        }
  90.256 +        if (val instanceof Number) {
  90.257 +            return numberValue(val).doubleValue() != 0.0;
  90.258 +        }
  90.259 +    
  90.260 +        return Boolean.TRUE.equals(val);
  90.261 +    }
  90.262 +    
  90.263 +    public static void loadJSON(
  90.264 +        BrwsrCtx c, RcvrJSON callback,
  90.265 +        String urlBefore, String urlAfter, String method,
  90.266 +        Object data
  90.267 +    ) {
  90.268 +        JSONCall call = PropertyBindingAccessor.createCall(c, callback, urlBefore, urlAfter, method, data);
  90.269 +        Transfer t = findTransfer(c);
  90.270 +        t.loadJSON(call);
  90.271 +    }
  90.272 +    public static WS openWS(
  90.273 +        BrwsrCtx c, RcvrJSON r, String url, Object data
  90.274 +    ) {
  90.275 +        WS ws = WSImpl.create(findWSTransfer(c), r);
  90.276 +        ws.send(c, url, data);
  90.277 +        return ws;
  90.278 +    }
  90.279 +    
  90.280 +    public static abstract class WS {
  90.281 +        private WS() {
  90.282 +        }
  90.283 +        
  90.284 +        public abstract void send(BrwsrCtx ctx, String url, Object model);
  90.285 +    }
  90.286 +    
  90.287 +    private static final class WSImpl<Socket> extends WS {
  90.288 +
  90.289 +        private final WSTransfer<Socket> trans;
  90.290 +        private final RcvrJSON rcvr;
  90.291 +        private Socket socket;
  90.292 +        private String prevURL;
  90.293 +
  90.294 +        private WSImpl(WSTransfer<Socket> trans, RcvrJSON rcvr) {
  90.295 +            this.trans = trans;
  90.296 +            this.rcvr = rcvr;
  90.297 +        }
  90.298 +        
  90.299 +        static <Socket> WS create(WSTransfer<Socket> t, RcvrJSON r) {
  90.300 +            return new WSImpl<Socket>(t, r);
  90.301 +        }
  90.302 +
  90.303 +        @Override
  90.304 +        public void send(BrwsrCtx ctx, String url, Object data) {
  90.305 +            Socket s = socket;
  90.306 +            if (s == null) {
  90.307 +                if (data != null) {
  90.308 +                    throw new IllegalStateException("WebSocket is not opened yet. Call with null data, was: " + data);
  90.309 +                }
  90.310 +                JSONCall call = PropertyBindingAccessor.createCall(ctx, rcvr, url, null, "WebSocket", null);
  90.311 +                socket = trans.open(url, call);
  90.312 +                prevURL = url;
  90.313 +                return;
  90.314 +            }
  90.315 +            if (data == null) {
  90.316 +                trans.close(s);
  90.317 +                socket = null;
  90.318 +                return;
  90.319 +            }
  90.320 +            if (!prevURL.equals(url)) {
  90.321 +                throw new IllegalStateException(
  90.322 +                    "Can't call to different URL " + url + " was: " + prevURL + "!"
  90.323 +                    + " Close the socket by calling it will null data first!"
  90.324 +                );
  90.325 +            }
  90.326 +            JSONCall call = PropertyBindingAccessor.createCall(ctx, rcvr, prevURL, null, "WebSocket", data);
  90.327 +            trans.send(s, call);
  90.328 +        }
  90.329 +        
  90.330 +    }
  90.331 +    
  90.332 +    private static final Map<Class,FromJSON<?>> froms;
  90.333 +    static {
  90.334 +        Map<Class,FromJSON<?>> m = new HashMap<Class,FromJSON<?>>();
  90.335 +        froms = m;
  90.336 +    }
  90.337 +    public static void register(FromJSON<?> from) {
  90.338 +        froms.put(from.factoryFor(), from);
  90.339 +    }
  90.340 +    
  90.341 +    public static boolean isModel(Class<?> clazz) {
  90.342 +        return findFrom(clazz) != null; 
  90.343 +    }
  90.344 +    
  90.345 +    private static FromJSON<?> findFrom(Class<?> clazz) {
  90.346 +        for (int i = 0; i < 2; i++) {
  90.347 +            FromJSON<?> from = froms.get(clazz);
  90.348 +            if (from == null) {
  90.349 +                initClass(clazz);
  90.350 +            } else {
  90.351 +                return from;
  90.352 +            }
  90.353 +        }
  90.354 +        return null;
  90.355 +    }
  90.356 +    
  90.357 +    public static <Model> Model bindTo(Model model, BrwsrCtx c) {
  90.358 +        FromJSON<?> from = findFrom(model.getClass());
  90.359 +        if (from == null) {
  90.360 +            throw new IllegalArgumentException();
  90.361 +        }
  90.362 +        return (Model) from.cloneTo(model, c);
  90.363 +    }
  90.364 +    
  90.365 +    public static <T> T readStream(BrwsrCtx c, Class<T> modelClazz, InputStream data) 
  90.366 +    throws IOException {
  90.367 +        Transfer tr = findTransfer(c);
  90.368 +        return read(c, modelClazz, tr.toJSON((InputStream)data));
  90.369 +    }
  90.370 +    public static <T> T read(BrwsrCtx c, Class<T> modelClazz, Object data) {
  90.371 +        if (data == null) {
  90.372 +            return null;
  90.373 +        }
  90.374 +        if (modelClazz == String.class) {
  90.375 +            return modelClazz.cast(data.toString());
  90.376 +        }
  90.377 +        for (int i = 0; i < 2; i++) {
  90.378 +            FromJSON<?> from = froms.get(modelClazz);
  90.379 +            if (from == null) {
  90.380 +                initClass(modelClazz);
  90.381 +            } else {
  90.382 +                return modelClazz.cast(from.read(c, data));
  90.383 +            }
  90.384 +        }
  90.385 +        throw new NullPointerException();
  90.386 +    }
  90.387 +    static void initClass(Class<?> modelClazz) {
  90.388 +        try {
  90.389 +            // try to resolve the class
  90.390 +            ClassLoader l;
  90.391 +            try {
  90.392 +                l = modelClazz.getClassLoader();
  90.393 +            } catch (SecurityException ex) {
  90.394 +                l = null;
  90.395 +            }
  90.396 +            if (l != null) {
  90.397 +                Class.forName(modelClazz.getName(), true, l);
  90.398 +            }
  90.399 +            modelClazz.newInstance();
  90.400 +        } catch (Exception ex) {
  90.401 +            // ignore and try again
  90.402 +        }
  90.403 +    }
  90.404 +    
  90.405 +    private static final class EmptyTech
  90.406 +    implements Technology<Object>, Transfer, WSTransfer<Void> {
  90.407 +        private static final EmptyTech EMPTY = new EmptyTech();
  90.408 +
  90.409 +        @Override
  90.410 +        public Object wrapModel(Object model) {
  90.411 +            return model;
  90.412 +        }
  90.413 +
  90.414 +        @Override
  90.415 +        public void valueHasMutated(Object data, String propertyName) {
  90.416 +        }
  90.417 +
  90.418 +        @Override
  90.419 +        public void bind(PropertyBinding b, Object model, Object data) {
  90.420 +        }
  90.421 +
  90.422 +        @Override
  90.423 +        public void expose(FunctionBinding fb, Object model, Object d) {
  90.424 +        }
  90.425 +
  90.426 +        @Override
  90.427 +        public void applyBindings(Object data) {
  90.428 +        }
  90.429 +
  90.430 +        @Override
  90.431 +        public Object wrapArray(Object[] arr) {
  90.432 +            return arr;
  90.433 +        }
  90.434 +
  90.435 +        @Override
  90.436 +        public void extract(Object obj, String[] props, Object[] values) {
  90.437 +            for (int i = 0; i < values.length; i++) {
  90.438 +                values[i] = null;
  90.439 +            }
  90.440 +        }
  90.441 +
  90.442 +        @Override
  90.443 +        public void loadJSON(JSONCall call) {
  90.444 +            call.notifyError(new UnsupportedOperationException());
  90.445 +        }
  90.446 +
  90.447 +        @Override
  90.448 +        public <M> M toModel(Class<M> modelClass, Object data) {
  90.449 +            return modelClass.cast(data);
  90.450 +        }
  90.451 +
  90.452 +        @Override
  90.453 +        public Object toJSON(InputStream is) throws IOException {
  90.454 +            throw new IOException("Not supported");
  90.455 +        }
  90.456 +
  90.457 +        @Override
  90.458 +        public synchronized void runSafe(Runnable r) {
  90.459 +            r.run();
  90.460 +        }
  90.461 +
  90.462 +        @Override
  90.463 +        public Void open(String url, JSONCall onReply) {
  90.464 +            onReply.notifyError(new UnsupportedOperationException("WebSockets not supported!"));
  90.465 +            return null;
  90.466 +        }
  90.467 +
  90.468 +        @Override
  90.469 +        public void send(Void socket, JSONCall data) {
  90.470 +        }
  90.471 +
  90.472 +        @Override
  90.473 +        public void close(Void socket) {
  90.474 +        }
  90.475 +    }
  90.476 +    
  90.477 +}
    91.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    91.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/JSONList.java	Mon Dec 16 16:59:43 2013 +0100
    91.3 @@ -0,0 +1,236 @@
    91.4 +/**
    91.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    91.6 + *
    91.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    91.8 + *
    91.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   91.10 + * Other names may be trademarks of their respective owners.
   91.11 + *
   91.12 + * The contents of this file are subject to the terms of either the GNU
   91.13 + * General Public License Version 2 only ("GPL") or the Common
   91.14 + * Development and Distribution License("CDDL") (collectively, the
   91.15 + * "License"). You may not use this file except in compliance with the
   91.16 + * License. You can obtain a copy of the License at
   91.17 + * http://www.netbeans.org/cddl-gplv2.html
   91.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   91.19 + * specific language governing permissions and limitations under the
   91.20 + * License.  When distributing the software, include this License Header
   91.21 + * Notice in each file and include the License file at
   91.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   91.23 + * particular file as subject to the "Classpath" exception as provided
   91.24 + * by Oracle in the GPL Version 2 section of the License file that
   91.25 + * accompanied this code. If applicable, add the following below the
   91.26 + * License Header, with the fields enclosed by brackets [] replaced by
   91.27 + * your own identifying information:
   91.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   91.29 + *
   91.30 + * Contributor(s):
   91.31 + *
   91.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   91.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   91.34 + *
   91.35 + * If you wish your version of this file to be governed by only the CDDL
   91.36 + * or only the GPL Version 2, indicate your decision by adding
   91.37 + * "[Contributor] elects to include this software in this distribution
   91.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   91.39 + * single choice of license, a recipient has the option to distribute
   91.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   91.41 + * to extend the choice of license to its licensees as provided above.
   91.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   91.43 + * Version 2 license, then the option applies only if the new code is
   91.44 + * made subject to such option by the copyright holder.
   91.45 + */
   91.46 +package org.netbeans.html.json.impl;
   91.47 +
   91.48 +import java.lang.reflect.Array;
   91.49 +import java.util.ArrayList;
   91.50 +import java.util.Arrays;
   91.51 +import java.util.Collection;
   91.52 +import java.util.Iterator;
   91.53 +import java.util.List;
   91.54 +import net.java.html.BrwsrCtx;
   91.55 +
   91.56 +/**
   91.57 + *
   91.58 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   91.59 + */
   91.60 +public final class JSONList<T> extends ArrayList<T> {
   91.61 +    private final String name;
   91.62 +    private final String[] deps;
   91.63 +    private Bindings[] model;
   91.64 +    private Runnable onchange;
   91.65 +
   91.66 +    public JSONList(Bindings[] model, String name, String... deps) {
   91.67 +        assert model.length == 1;
   91.68 +        this.model = model;
   91.69 +        this.name = name;
   91.70 +        this.deps = deps;
   91.71 +    }
   91.72 +    
   91.73 +    public void init(T... values) {
   91.74 +        if (values == null || values.length == 0) {
   91.75 +            return;
   91.76 +        }
   91.77 +        if (this.model[0] != null || !isEmpty()) {
   91.78 +            throw new IllegalStateException();
   91.79 +        }
   91.80 +        super.addAll(Arrays.asList(values));
   91.81 +    }
   91.82 +    
   91.83 +    public void init(Object values) {
   91.84 +        int len;
   91.85 +        if (values == null || (len = Array.getLength(values)) == 0) {
   91.86 +            return;
   91.87 +        }
   91.88 +        if (this.model[0] != null || !isEmpty()) {
   91.89 +            throw new IllegalStateException();
   91.90 +        }
   91.91 +        for (int i = 0; i < len; i++) {
   91.92 +            Object data = Array.get(values, i);
   91.93 +            super.add((T)data);
   91.94 +        }
   91.95 +    }
   91.96 +    
   91.97 +    public JSONList<T> onChange(Runnable r) {
   91.98 +        if (this.onchange != null) {
   91.99 +            throw new IllegalStateException();
  91.100 +        }
  91.101 +        this.onchange = r;
  91.102 +        return this;
  91.103 +    }
  91.104 +
  91.105 +    @Override
  91.106 +    public boolean add(T e) {
  91.107 +        boolean ret = super.add(e);
  91.108 +        notifyChange();
  91.109 +        return ret;
  91.110 +    }
  91.111 +
  91.112 +    @Override
  91.113 +    public boolean addAll(Collection<? extends T> c) {
  91.114 +        boolean ret = super.addAll(c);
  91.115 +        notifyChange();
  91.116 +        return ret;
  91.117 +    }
  91.118 +
  91.119 +    @Override
  91.120 +    public boolean addAll(int index, Collection<? extends T> c) {
  91.121 +        boolean ret = super.addAll(index, c);
  91.122 +        notifyChange();
  91.123 +        return ret;
  91.124 +    }
  91.125 +
  91.126 +    @Override
  91.127 +    public boolean remove(Object o) {
  91.128 +        boolean ret = super.remove(o);
  91.129 +        notifyChange();
  91.130 +        return ret;
  91.131 +    }
  91.132 +
  91.133 +    @Override
  91.134 +    public void clear() {
  91.135 +        super.clear();
  91.136 +        notifyChange();
  91.137 +    }
  91.138 +
  91.139 +    @Override
  91.140 +    public boolean removeAll(Collection<?> c) {
  91.141 +        boolean ret = super.removeAll(c);
  91.142 +        notifyChange();
  91.143 +        return ret;
  91.144 +    }
  91.145 +
  91.146 +    @Override
  91.147 +    public boolean retainAll(Collection<?> c) {
  91.148 +        boolean ret = super.retainAll(c);
  91.149 +        notifyChange();
  91.150 +        return ret;
  91.151 +    }
  91.152 +
  91.153 +    @Override
  91.154 +    public T set(int index, T element) {
  91.155 +        T ret = super.set(index, element);
  91.156 +        notifyChange();
  91.157 +        return ret;
  91.158 +    }
  91.159 +
  91.160 +    @Override
  91.161 +    public void add(int index, T element) {
  91.162 +        super.add(index, element);
  91.163 +        notifyChange();
  91.164 +    }
  91.165 +
  91.166 +    @Override
  91.167 +    public T remove(int index) {
  91.168 +        T ret = super.remove(index);
  91.169 +        notifyChange();
  91.170 +        return ret;
  91.171 +    }
  91.172 +
  91.173 +    @Override
  91.174 +    public String toString() {
  91.175 +        Iterator<T> it = iterator();
  91.176 +        if (!it.hasNext()) {
  91.177 +            return "[]";
  91.178 +        }
  91.179 +        String sep = "";
  91.180 +        StringBuilder sb = new StringBuilder();
  91.181 +        sb.append('[');
  91.182 +        while (it.hasNext()) {
  91.183 +            T t = it.next();
  91.184 +            sb.append(sep);
  91.185 +            sb.append(JSON.toJSON(t));
  91.186 +            sep = ",";
  91.187 +        }
  91.188 +        sb.append(']');
  91.189 +        return sb.toString();
  91.190 +    }
  91.191 +
  91.192 +    private void notifyChange() {
  91.193 +        Bindings m = model[0];
  91.194 +        if (m != null) {
  91.195 +            m.valueHasMutated(name);
  91.196 +            for (String dependant : deps) {
  91.197 +                m.valueHasMutated(dependant);
  91.198 +            }
  91.199 +            Runnable r = onchange;
  91.200 +            if (r != null) {
  91.201 +                r.run();
  91.202 +            }
  91.203 +        }
  91.204 +    }
  91.205 +    
  91.206 +    public void cloneAll(BrwsrCtx c, Collection<T> other) {
  91.207 +        Boolean isModel = null;
  91.208 +        for (T t : other) {
  91.209 +            if (isModel == null) {
  91.210 +                isModel = JSON.isModel(t.getClass());
  91.211 +            }
  91.212 +            if (isModel) {
  91.213 +                add(JSON.bindTo(t, c));
  91.214 +            } else {
  91.215 +                add(t);
  91.216 +            }
  91.217 +        }
  91.218 +    }
  91.219 +
  91.220 +    @Override
  91.221 +    public JSONList clone() {
  91.222 +        throw new UnsupportedOperationException();
  91.223 +    }
  91.224 +
  91.225 +    static final Object koData(Collection<?> c, Bindings m) {
  91.226 +        Object[] arr = c.toArray(new Object[c.size()]);
  91.227 +        for (int i = 0; i < arr.length; i++) {
  91.228 +            Object r = WrapperObject.find(arr[i], m);
  91.229 +            if (r != null) {
  91.230 +                arr[i] = r;
  91.231 +            }
  91.232 +        }
  91.233 +        return m.wrapArray(arr);
  91.234 +    }
  91.235 +
  91.236 +    final Object koData() {
  91.237 +        return koData(this, model[0]);
  91.238 +    }
  91.239 +}
    92.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    92.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java	Mon Dec 16 16:59:43 2013 +0100
    92.3 @@ -0,0 +1,1767 @@
    92.4 +/**
    92.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    92.6 + *
    92.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    92.8 + *
    92.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   92.10 + * Other names may be trademarks of their respective owners.
   92.11 + *
   92.12 + * The contents of this file are subject to the terms of either the GNU
   92.13 + * General Public License Version 2 only ("GPL") or the Common
   92.14 + * Development and Distribution License("CDDL") (collectively, the
   92.15 + * "License"). You may not use this file except in compliance with the
   92.16 + * License. You can obtain a copy of the License at
   92.17 + * http://www.netbeans.org/cddl-gplv2.html
   92.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   92.19 + * specific language governing permissions and limitations under the
   92.20 + * License.  When distributing the software, include this License Header
   92.21 + * Notice in each file and include the License file at
   92.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   92.23 + * particular file as subject to the "Classpath" exception as provided
   92.24 + * by Oracle in the GPL Version 2 section of the License file that
   92.25 + * accompanied this code. If applicable, add the following below the
   92.26 + * License Header, with the fields enclosed by brackets [] replaced by
   92.27 + * your own identifying information:
   92.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   92.29 + *
   92.30 + * Contributor(s):
   92.31 + *
   92.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   92.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   92.34 + *
   92.35 + * If you wish your version of this file to be governed by only the CDDL
   92.36 + * or only the GPL Version 2, indicate your decision by adding
   92.37 + * "[Contributor] elects to include this software in this distribution
   92.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   92.39 + * single choice of license, a recipient has the option to distribute
   92.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   92.41 + * to extend the choice of license to its licensees as provided above.
   92.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   92.43 + * Version 2 license, then the option applies only if the new code is
   92.44 + * made subject to such option by the copyright holder.
   92.45 + */
   92.46 +package org.netbeans.html.json.impl;
   92.47 +
   92.48 +import java.io.IOException;
   92.49 +import java.io.OutputStreamWriter;
   92.50 +import java.io.StringWriter;
   92.51 +import java.io.Writer;
   92.52 +import java.lang.annotation.AnnotationTypeMismatchException;
   92.53 +import java.lang.annotation.IncompleteAnnotationException;
   92.54 +import java.lang.reflect.Method;
   92.55 +import java.util.ArrayList;
   92.56 +import java.util.Arrays;
   92.57 +import java.util.Collection;
   92.58 +import java.util.Collections;
   92.59 +import java.util.HashMap;
   92.60 +import java.util.HashSet;
   92.61 +import java.util.LinkedHashSet;
   92.62 +import java.util.List;
   92.63 +import java.util.Map;
   92.64 +import java.util.ResourceBundle;
   92.65 +import java.util.Set;
   92.66 +import java.util.WeakHashMap;
   92.67 +import java.util.logging.Level;
   92.68 +import java.util.logging.Logger;
   92.69 +import javax.annotation.processing.AbstractProcessor;
   92.70 +import javax.annotation.processing.Completion;
   92.71 +import javax.annotation.processing.Completions;
   92.72 +import javax.annotation.processing.ProcessingEnvironment;
   92.73 +import javax.annotation.processing.Processor;
   92.74 +import javax.annotation.processing.RoundEnvironment;
   92.75 +import javax.annotation.processing.SupportedAnnotationTypes;
   92.76 +import javax.annotation.processing.SupportedSourceVersion;
   92.77 +import javax.lang.model.SourceVersion;
   92.78 +import javax.lang.model.element.AnnotationMirror;
   92.79 +import javax.lang.model.element.AnnotationValue;
   92.80 +import javax.lang.model.element.Element;
   92.81 +import javax.lang.model.element.ElementKind;
   92.82 +import javax.lang.model.element.ExecutableElement;
   92.83 +import javax.lang.model.element.Modifier;
   92.84 +import javax.lang.model.element.PackageElement;
   92.85 +import javax.lang.model.element.TypeElement;
   92.86 +import javax.lang.model.element.VariableElement;
   92.87 +import javax.lang.model.type.ArrayType;
   92.88 +import javax.lang.model.type.DeclaredType;
   92.89 +import javax.lang.model.type.MirroredTypeException;
   92.90 +import javax.lang.model.type.TypeKind;
   92.91 +import javax.lang.model.type.TypeMirror;
   92.92 +import javax.lang.model.util.Elements;
   92.93 +import javax.lang.model.util.Types;
   92.94 +import javax.tools.Diagnostic;
   92.95 +import javax.tools.FileObject;
   92.96 +import net.java.html.json.ComputedProperty;
   92.97 +import net.java.html.json.Model;
   92.98 +import net.java.html.json.Function;
   92.99 +import net.java.html.json.ModelOperation;
  92.100 +import net.java.html.json.OnPropertyChange;
  92.101 +import net.java.html.json.OnReceive;
  92.102 +import net.java.html.json.Property;
  92.103 +import org.openide.util.lookup.ServiceProvider;
  92.104 +
  92.105 +/** Annotation processor to process {@link Model @Model} annotations and
  92.106 + * generate appropriate model classes.
  92.107 + *
  92.108 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  92.109 + */
  92.110 +@ServiceProvider(service=Processor.class)
  92.111 +@SupportedSourceVersion(SourceVersion.RELEASE_6)
  92.112 +@SupportedAnnotationTypes({
  92.113 +    "net.java.html.json.Model",
  92.114 +    "net.java.html.json.ModelOperation",
  92.115 +    "net.java.html.json.Function",
  92.116 +    "net.java.html.json.OnReceive",
  92.117 +    "net.java.html.json.OnPropertyChange",
  92.118 +    "net.java.html.json.ComputedProperty",
  92.119 +    "net.java.html.json.Property"
  92.120 +})
  92.121 +public final class ModelProcessor extends AbstractProcessor {
  92.122 +    private static final Logger LOG = Logger.getLogger(ModelProcessor.class.getName());
  92.123 +    private final Map<Element,String> models = new WeakHashMap<Element,String>();
  92.124 +    private final Map<Element,Prprt[]> verify = new WeakHashMap<Element,Prprt[]>();
  92.125 +    @Override
  92.126 +    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
  92.127 +        boolean ok = true;
  92.128 +        for (Element e : roundEnv.getElementsAnnotatedWith(Model.class)) {
  92.129 +            if (!processModel(e)) {
  92.130 +                ok = false;
  92.131 +            }
  92.132 +        }
  92.133 +        if (roundEnv.processingOver()) {
  92.134 +            models.clear();
  92.135 +            for (Map.Entry<Element, Prprt[]> entry : verify.entrySet()) {
  92.136 +                TypeElement te = (TypeElement)entry.getKey();
  92.137 +                String fqn = processingEnv.getElementUtils().getBinaryName(te).toString();
  92.138 +                Element finalElem = processingEnv.getElementUtils().getTypeElement(fqn);
  92.139 +                if (finalElem == null) {
  92.140 +                    continue;
  92.141 +                }
  92.142 +                Prprt[] props;
  92.143 +                Model m = finalElem.getAnnotation(Model.class);
  92.144 +                if (m == null) {
  92.145 +                    continue;
  92.146 +                }
  92.147 +                props = Prprt.wrap(processingEnv, finalElem, m.properties());
  92.148 +                for (Prprt p : props) {
  92.149 +                    boolean[] isModel = { false };
  92.150 +                    boolean[] isEnum = { false };
  92.151 +                    boolean[] isPrimitive = { false };
  92.152 +                    String t = checkType(p, isModel, isEnum, isPrimitive);
  92.153 +                    if (isEnum[0]) {
  92.154 +                        continue;
  92.155 +                    }
  92.156 +                    if (isPrimitive[0]) {
  92.157 +                        continue;
  92.158 +                    }
  92.159 +                    if (isModel[0]) {
  92.160 +                        continue;
  92.161 +                    }
  92.162 +                    if ("java.lang.String".equals(t)) {
  92.163 +                        continue;
  92.164 +                    }
  92.165 +                    error("The type " + t + " should be defined by @Model annotation", entry.getKey());
  92.166 +                }
  92.167 +            }
  92.168 +            verify.clear();
  92.169 +        }
  92.170 +        return ok;
  92.171 +    }
  92.172 +
  92.173 +    private void error(String msg, Element e) {
  92.174 +        processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e);
  92.175 +    }
  92.176 +    
  92.177 +    private boolean processModel(Element e) {
  92.178 +        boolean ok = true;
  92.179 +        Model m = e.getAnnotation(Model.class);
  92.180 +        if (m == null) {
  92.181 +            return true;
  92.182 +        }
  92.183 +        String pkg = findPkgName(e);
  92.184 +        Writer w;
  92.185 +        String className = m.className();
  92.186 +        models.put(e, className);
  92.187 +        try {
  92.188 +            StringWriter body = new StringWriter();
  92.189 +            List<String> propsGetSet = new ArrayList<String>();
  92.190 +            List<String> functions = new ArrayList<String>();
  92.191 +            Map<String, Collection<String>> propsDeps = new HashMap<String, Collection<String>>();
  92.192 +            Map<String, Collection<String>> functionDeps = new HashMap<String, Collection<String>>();
  92.193 +            Prprt[] props = createProps(e, m.properties());
  92.194 +            
  92.195 +            if (!generateComputedProperties(body, props, e.getEnclosedElements(), propsGetSet, propsDeps)) {
  92.196 +                ok = false;
  92.197 +            }
  92.198 +            if (!generateOnChange(e, propsDeps, props, className, functionDeps)) {
  92.199 +                ok = false;
  92.200 +            }
  92.201 +            if (!generateProperties(e, body, props, propsGetSet, propsDeps, functionDeps)) {
  92.202 +                ok = false;
  92.203 +            }
  92.204 +            if (!generateFunctions(e, body, className, e.getEnclosedElements(), functions)) {
  92.205 +                ok = false;
  92.206 +            }
  92.207 +            if (!generateReceive(e, body, className, e.getEnclosedElements(), functions)) {
  92.208 +                ok = false;
  92.209 +            }
  92.210 +            if (!generateOperation(e, body, className, e.getEnclosedElements())) {
  92.211 +                ok = false;
  92.212 +            }
  92.213 +            FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e);
  92.214 +            w = new OutputStreamWriter(java.openOutputStream());
  92.215 +            try {
  92.216 +                w.append("package " + pkg + ";\n");
  92.217 +                w.append("import net.java.html.json.*;\n");
  92.218 +                w.append("public final class ").append(className).append(" implements Cloneable {\n");
  92.219 +                w.append("  private boolean locked;\n");
  92.220 +                w.append("  private net.java.html.BrwsrCtx context;\n");
  92.221 +                w.append("  private org.netbeans.html.json.impl.Bindings[] ko = { null };\n");
  92.222 +                w.append(body.toString());
  92.223 +                w.append("  private static Class<" + inPckName(e) + "> modelFor() { return null; }\n");
  92.224 +                w.append("  private ").append(className).append("(net.java.html.BrwsrCtx context) {\n");
  92.225 +                w.append("    this.context = context;\n");
  92.226 +                w.append("  };\n");
  92.227 +                w.append("  public ").append(className).append("() {\n");
  92.228 +                w.append("    this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n");
  92.229 +                for (Prprt p : props) {
  92.230 +                    if (p.array()) {
  92.231 +                        continue;
  92.232 +                    }
  92.233 +                    boolean[] isModel = {false};
  92.234 +                    boolean[] isEnum = {false};
  92.235 +                    boolean isPrimitive[] = {false};
  92.236 +                    String tn = checkType(p, isModel, isEnum, isPrimitive);
  92.237 +                    if (isModel[0]) {
  92.238 +                        w.write("    prop_" + p.name() + " = new " + tn + "();\n");
  92.239 +                    }
  92.240 +                }
  92.241 +                w.append("  };\n");
  92.242 +                if (props.length > 0) {
  92.243 +                    w.append("  public ").append(className).append("(");
  92.244 +                    Prprt firstArray = null;
  92.245 +                    String sep = "";
  92.246 +                    for (Prprt p : props) {
  92.247 +                        if (p.array()) {
  92.248 +                            if (firstArray == null) {
  92.249 +                                firstArray = p;
  92.250 +                            }
  92.251 +                            continue;
  92.252 +                        }
  92.253 +                        String tn = typeName(e, p);
  92.254 +                        w.write(sep);
  92.255 +                        w.write(tn);
  92.256 +                        w.write(" " + p.name());
  92.257 +                        sep = ", ";
  92.258 +                    }
  92.259 +                    if (firstArray != null) {
  92.260 +                        String tn;
  92.261 +                        boolean[] isModel = {false};
  92.262 +                        boolean[] isEnum = {false};
  92.263 +                        boolean isPrimitive[] = {false};
  92.264 +                        tn = checkType(firstArray, isModel, isEnum, isPrimitive);
  92.265 +                        w.write(sep);
  92.266 +                        w.write(tn);
  92.267 +                        w.write("... " + firstArray.name());
  92.268 +                    }
  92.269 +                    w.append(") {\n");
  92.270 +                    w.append("    this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n");
  92.271 +                    for (Prprt p : props) {
  92.272 +                        if (p.array()) {
  92.273 +                            continue;
  92.274 +                        }
  92.275 +                        w.write("    this.prop_" + p.name() + " = " + p.name() + ";\n");
  92.276 +                    }
  92.277 +                    if (firstArray != null) {
  92.278 +                        w.write("    this.prop_" + firstArray.name() + ".init(" + firstArray.name() + ");\n");
  92.279 +                    }
  92.280 +                    w.append("  };\n");
  92.281 +                }
  92.282 +                w.append("  private org.netbeans.html.json.impl.Bindings intKnckt() {\n");
  92.283 +                w.append("    if (ko[0] != null) return ko[0];\n");
  92.284 +                w.append("    ko[0] = org.netbeans.html.json.impl.Bindings.apply(context, this);\n");
  92.285 +                {
  92.286 +                    w.append("    org.apidesign.html.json.spi.PropertyBinding[] propArr = {\n");
  92.287 +                    for (int i = 0; i < propsGetSet.size(); i += 5) {
  92.288 +                        w.append("      ko[0].registerProperty(\"").append(propsGetSet.get(i)).append("\", this, new P(");
  92.289 +                        w.append((i / 5) + "), " + (propsGetSet.get(i + 2) == null) + "),\n");
  92.290 +                    }
  92.291 +                    w.append("    };\n");
  92.292 +                }
  92.293 +                {
  92.294 +                    w.append("    org.apidesign.html.json.spi.FunctionBinding[] funcArr = {\n");
  92.295 +                    for (int i = 0; i < functions.size(); i += 2) {
  92.296 +                        w.append("      ko[0].registerFunction(\"").append(functions.get(i)).append("\", this, new P(");
  92.297 +                        w.append((i / 2) + ")),\n");
  92.298 +                    }
  92.299 +                    w.append("    };\n");
  92.300 +                }
  92.301 +                w.append("    ko[0].finish(this, propArr, funcArr);\n");
  92.302 +                w.append("    return ko[0];\n");
  92.303 +                w.append("  };\n");
  92.304 +                w.append("  private static final class P implements org.netbeans.html.json.impl.SetAndGet<" + className + ">,\n");
  92.305 +                w.append("  org.netbeans.html.json.impl.Callback<" + className + ">,\n");
  92.306 +                w.append("  org.netbeans.html.json.impl.FromJSON<" + className + "> {\n");
  92.307 +                w.append("    private final int type;\n");
  92.308 +                w.append("    P(int t) { type = t; };\n");
  92.309 +                w.append("    public void setValue(" + className + " data, Object value) {\n");
  92.310 +                w.append("      switch (type) {\n");
  92.311 +                for (int i = 0; i < propsGetSet.size(); i += 5) {
  92.312 +                    final String set = propsGetSet.get(i + 2);
  92.313 +                    String tn = propsGetSet.get(i + 4);
  92.314 +                    String btn = findBoxedType(tn);
  92.315 +                    if (btn != null) {
  92.316 +                        tn = btn;
  92.317 +                    }
  92.318 +                    if (set != null) {
  92.319 +                        w.append("        case " + (i / 5) + ": data." + strip(set) + "(org.netbeans.html.json.impl.JSON.extractValue(" + tn + ".class, value)); return;\n");
  92.320 +                    }
  92.321 +                }
  92.322 +                w.append("      }\n");
  92.323 +                w.append("    }\n");
  92.324 +                w.append("    public Object getValue(" + className + " data) {\n");
  92.325 +                w.append("      switch (type) {\n");
  92.326 +                for (int i = 0; i < propsGetSet.size(); i += 5) {
  92.327 +                    final String get = propsGetSet.get(i + 1);
  92.328 +                    if (get != null) {
  92.329 +                        w.append("        case " + (i / 5) + ": return data." + strip(get) + "();\n");
  92.330 +                    }
  92.331 +                }
  92.332 +                w.append("      }\n");
  92.333 +                w.append("      throw new UnsupportedOperationException();\n");
  92.334 +                w.append("    }\n");
  92.335 +                w.append("    public void call(" + className + " model, Object data, Object ev) {\n");
  92.336 +                w.append("      switch (type) {\n");
  92.337 +                for (int i = 0; i < functions.size(); i += 2) {
  92.338 +                    final String name = functions.get(i);
  92.339 +                    w.append("        case " + (i / 2) + ": model." + name + "(data, ev); return;\n");
  92.340 +                }
  92.341 +                w.append("      }\n");
  92.342 +                w.append("      throw new UnsupportedOperationException();\n");
  92.343 +                w.append("    }\n");
  92.344 +                w.append("    public Class<" + className + "> factoryFor() { return " + className + ".class; }\n");
  92.345 +                w.append("    public " + className + " read(net.java.html.BrwsrCtx c, Object json) { return new " + className + "(c, json); }\n");
  92.346 +                w.append("    public " + className + " cloneTo(Object o, net.java.html.BrwsrCtx c) { return ((" + className + ")o).clone(c); }\n");
  92.347 +                w.append("  }\n");
  92.348 +                w.append("  static { org.netbeans.html.json.impl.JSON.register(new P(0)); }\n");
  92.349 +                w.append("  private ").append(className).append("(net.java.html.BrwsrCtx c, Object json) {\n");
  92.350 +                w.append("    this.context = c;\n");
  92.351 +                int values = 0;
  92.352 +                for (int i = 0; i < propsGetSet.size(); i += 5) {
  92.353 +                    Prprt p = findPrprt(props, propsGetSet.get(i));
  92.354 +                    if (p == null) {
  92.355 +                        continue;
  92.356 +                    }
  92.357 +                    values++;
  92.358 +                }
  92.359 +                w.append("    Object[] ret = new Object[" + values + "];\n");
  92.360 +                w.append("    org.netbeans.html.json.impl.JSON.extract(context, json, new String[] {\n");
  92.361 +                for (int i = 0; i < propsGetSet.size(); i += 5) {
  92.362 +                    Prprt p = findPrprt(props, propsGetSet.get(i));
  92.363 +                    if (p == null) {
  92.364 +                        continue;
  92.365 +                    }
  92.366 +                    w.append("      \"").append(propsGetSet.get(i)).append("\",\n");
  92.367 +                }
  92.368 +                w.append("    }, ret);\n");
  92.369 +                for (int i = 0, cnt = 0, prop = 0; i < propsGetSet.size(); i += 5) {
  92.370 +                    final String pn = propsGetSet.get(i);
  92.371 +                    Prprt p = findPrprt(props, pn);
  92.372 +                    if (p == null) {
  92.373 +                        continue;
  92.374 +                    }
  92.375 +                    boolean[] isModel = { false };
  92.376 +                    boolean[] isEnum = { false };
  92.377 +                    boolean isPrimitive[] = { false };
  92.378 +                    String type = checkType(props[prop++], isModel, isEnum, isPrimitive);
  92.379 +                    if (p.array()) {
  92.380 +                        w.append("    if (ret[" + cnt + "] instanceof Object[]) {\n");
  92.381 +                        w.append("      for (Object e : ((Object[])ret[" + cnt + "])) {\n");
  92.382 +                        if (isModel[0]) {
  92.383 +                            w.append("        this.prop_").append(pn).append(".add(org.netbeans.html.json.impl.JSON.read");
  92.384 +                            w.append("(c, " + type + ".class, e));\n");
  92.385 +                        } else if (isEnum[0]) {
  92.386 +                            w.append("        this.prop_").append(pn);
  92.387 +                            w.append(".add(e == null ? null : ");
  92.388 +                            w.append(type).append(".valueOf(org.netbeans.html.json.impl.JSON.stringValue(e)));\n");
  92.389 +                        } else {
  92.390 +                            if (isPrimitive(type)) {
  92.391 +                                w.append("        this.prop_").append(pn).append(".add(org.netbeans.html.json.impl.JSON.numberValue(e).");
  92.392 +                                w.append(type).append("Value());\n");
  92.393 +                            } else {
  92.394 +                                w.append("        this.prop_").append(pn).append(".add((");
  92.395 +                                w.append(type).append(")e);\n");
  92.396 +                            }
  92.397 +                        }
  92.398 +                        w.append("      }\n");
  92.399 +                        w.append("    }\n");
  92.400 +                    } else {
  92.401 +                        if (isEnum[0]) {
  92.402 +                            w.append("    try {\n");
  92.403 +                            w.append("    this.prop_").append(pn);
  92.404 +                            w.append(" = ret[" + cnt + "] == null ? null : ");
  92.405 +                            w.append(type).append(".valueOf(org.netbeans.html.json.impl.JSON.stringValue(ret[" + cnt + "]));\n");
  92.406 +                            w.append("    } catch (IllegalArgumentException ex) {\n");
  92.407 +                            w.append("      ex.printStackTrace();\n");
  92.408 +                            w.append("    }\n");
  92.409 +                        } else if (isPrimitive(type)) {
  92.410 +                            w.append("    this.prop_").append(pn);
  92.411 +                            w.append(" = ret[" + cnt + "] == null ? ");
  92.412 +                            if ("char".equals(type)) {
  92.413 +                                w.append("0 : (org.netbeans.html.json.impl.JSON.charValue(");
  92.414 +                            } else if ("boolean".equals(type)) {
  92.415 +                                w.append("false : (org.netbeans.html.json.impl.JSON.boolValue(");
  92.416 +                            } else {
  92.417 +                                w.append("0 : (org.netbeans.html.json.impl.JSON.numberValue(");
  92.418 +                            }
  92.419 +                            w.append("ret[" + cnt + "])).");
  92.420 +                            w.append(type).append("Value();\n");
  92.421 +                        } else if (isModel[0]) {
  92.422 +                            w.append("    this.prop_").append(pn).append(" = org.netbeans.html.json.impl.JSON.read");
  92.423 +                            w.append("(c, " + type + ".class, ");
  92.424 +                            w.append("ret[" + cnt + "]);\n");
  92.425 +                        }else {
  92.426 +                            w.append("    this.prop_").append(pn);
  92.427 +                            w.append(" = (").append(type).append(')');
  92.428 +                            w.append("ret[" + cnt + "];\n");
  92.429 +                        }
  92.430 +                    }
  92.431 +                    cnt++;
  92.432 +                }
  92.433 +                w.append("  };\n");
  92.434 +                writeToString(props, w);
  92.435 +                writeClone(className, props, w);
  92.436 +                w.write("  /** Activates this model instance in the current {@link \n"
  92.437 +                    + "net.java.html.json.Models#bind(java.lang.Object, net.java.html.BrwsrCtx) browser context}. \n"
  92.438 +                    + "In case of using Knockout technology, this means to \n"
  92.439 +                    + "bind JSON like data in this model instance with Knockout tags in \n"
  92.440 +                    + "the surrounding HTML page.\n"
  92.441 +                    + "*/\n"
  92.442 +                );
  92.443 +                w.write("  public " + className + " applyBindings() {\n");
  92.444 +                w.write("    intKnckt().applyBindings();\n");
  92.445 +                w.write("    return this;\n");
  92.446 +                w.write("  }\n");
  92.447 +                w.write("  public boolean equals(Object o) {\n");
  92.448 +                w.write("    if (o == this) return true;\n");
  92.449 +                w.write("    if (o instanceof org.netbeans.html.json.impl.WrapperObject) {\n");
  92.450 +                w.write("      ((org.netbeans.html.json.impl.WrapperObject)o).setRealObject(intKnckt().koData());\n");
  92.451 +                w.write("      return false;\n");
  92.452 +                w.write("    }\n");
  92.453 +                w.write("    if (!(o instanceof " + className + ")) return false;\n");
  92.454 +                w.write("    " + className + " p = (" + className + ")o;\n");
  92.455 +                for (Prprt p : props) {
  92.456 +                    w.write("    if (!org.netbeans.html.json.impl.JSON.isSame(prop_" + p.name() + ", p.prop_" + p.name() + ")) return false;\n");
  92.457 +                }
  92.458 +                w.write("    return true;\n");
  92.459 +                w.write("  }\n");
  92.460 +                w.write("  public int hashCode() {\n");
  92.461 +                w.write("    int h = " + className + ".class.getName().hashCode();\n");
  92.462 +                for (Prprt p : props) {
  92.463 +                    w.write("    h = org.netbeans.html.json.impl.JSON.hashPlus(prop_" + p.name() + ", h);\n");
  92.464 +                }
  92.465 +                w.write("    return h;\n");
  92.466 +                w.write("  }\n");
  92.467 +                w.write("}\n");
  92.468 +            } finally {
  92.469 +                w.close();
  92.470 +            }
  92.471 +        } catch (IOException ex) {
  92.472 +            error("Can't create " + className + ".java", e);
  92.473 +            return false;
  92.474 +        }
  92.475 +        return ok;
  92.476 +    }
  92.477 +    
  92.478 +    private boolean generateProperties(
  92.479 +        Element where,
  92.480 +        Writer w, Prprt[] properties,
  92.481 +        Collection<String> props, 
  92.482 +        Map<String,Collection<String>> deps,
  92.483 +        Map<String,Collection<String>> functionDeps
  92.484 +    ) throws IOException {
  92.485 +        boolean ok = true;
  92.486 +        for (Prprt p : properties) {
  92.487 +            final String tn;
  92.488 +            tn = typeName(where, p);
  92.489 +            String[] gs = toGetSet(p.name(), tn, p.array());
  92.490 +            String castTo;
  92.491 +            
  92.492 +            if (p.array()) {
  92.493 +                w.write("  private org.netbeans.html.json.impl.JSONList<" + tn + "> prop_" + p.name() + " = new org.netbeans.html.json.impl.JSONList<" + tn + ">(ko, \""
  92.494 +                    + p.name() + "\"");
  92.495 +                Collection<String> dependants = deps.get(p.name());
  92.496 +                if (dependants != null) {
  92.497 +                    for (String depProp : dependants) {
  92.498 +                        w.write(", ");
  92.499 +                        w.write('\"');
  92.500 +                        w.write(depProp);
  92.501 +                        w.write('\"');
  92.502 +                    }
  92.503 +                }
  92.504 +                w.write(")");
  92.505 +                
  92.506 +                dependants = functionDeps.get(p.name());
  92.507 +                if (dependants != null) {
  92.508 +                    w.write(".onChange(new Runnable() { public void run() {\n");
  92.509 +                    for (String call : dependants) {
  92.510 +                        w.append("  ").append(call);
  92.511 +                    }
  92.512 +                    w.write("  }})");
  92.513 +                }
  92.514 +                w.write(";\n");
  92.515 +            
  92.516 +                castTo = "java.util.List";
  92.517 +                w.write("  public java.util.List<" + tn + "> " + gs[0] + "() {\n");
  92.518 +                w.write("    if (locked) throw new IllegalStateException();\n");
  92.519 +                w.write("    return prop_" + p.name() + ";\n");
  92.520 +                w.write("  }\n");
  92.521 +            } else {
  92.522 +                castTo = tn;
  92.523 +                w.write("  private " + tn + " prop_" + p.name() + ";\n");
  92.524 +                w.write("  public " + tn + " " + gs[0] + "() {\n");
  92.525 +                w.write("    if (locked) throw new IllegalStateException();\n");
  92.526 +                w.write("    return prop_" + p.name() + ";\n");
  92.527 +                w.write("  }\n");
  92.528 +                w.write("  public void " + gs[1] + "(" + tn + " v) {\n");
  92.529 +                w.write("    if (locked) throw new IllegalStateException();\n");
  92.530 +                w.write("    if (org.netbeans.html.json.impl.JSON.isSame(prop_" + p.name() + ", v)) return;\n");
  92.531 +                w.write("    prop_" + p.name() + " = v;\n");
  92.532 +                w.write("    org.netbeans.html.json.impl.Bindings b = ko[0];\n");
  92.533 +                w.write("    if (b != null) {\n");
  92.534 +                w.write("      b.valueHasMutated(\"" + p.name() + "\");\n");
  92.535 +                Collection<String> dependants = deps.get(p.name());
  92.536 +                if (dependants != null) {
  92.537 +                    for (String depProp : dependants) {
  92.538 +                        w.write("      b.valueHasMutated(\"" + depProp + "\");\n");
  92.539 +                    }
  92.540 +                }
  92.541 +                w.write("    }\n");
  92.542 +                dependants = functionDeps.get(p.name());
  92.543 +                if (dependants != null) {
  92.544 +                    for (String call : dependants) {
  92.545 +                        w.append("  ").append(call);
  92.546 +                    }
  92.547 +                }
  92.548 +                w.write("  }\n");
  92.549 +            }
  92.550 +            
  92.551 +            props.add(p.name());
  92.552 +            props.add(gs[2]);
  92.553 +            props.add(gs[3]);
  92.554 +            props.add(gs[0]);
  92.555 +            props.add(castTo);
  92.556 +        }
  92.557 +        return ok;
  92.558 +    }
  92.559 +
  92.560 +    private boolean generateComputedProperties(
  92.561 +        Writer w, Prprt[] fixedProps,
  92.562 +        Collection<? extends Element> arr, Collection<String> props,
  92.563 +        Map<String,Collection<String>> deps
  92.564 +    ) throws IOException {
  92.565 +        boolean ok = true;
  92.566 +        for (Element e : arr) {
  92.567 +            if (e.getKind() != ElementKind.METHOD) {
  92.568 +                continue;
  92.569 +            }
  92.570 +            if (e.getAnnotation(ComputedProperty.class) == null) {
  92.571 +                continue;
  92.572 +            }
  92.573 +            if (!e.getModifiers().contains(Modifier.STATIC)) {
  92.574 +                error("Method " + e.getSimpleName() + " has to be static when annotated by @ComputedProperty", e);
  92.575 +                ok = false;
  92.576 +                continue;
  92.577 +            }
  92.578 +            ExecutableElement ee = (ExecutableElement)e;
  92.579 +            final TypeMirror rt = ee.getReturnType();
  92.580 +            final Types tu = processingEnv.getTypeUtils();
  92.581 +            TypeMirror ert = tu.erasure(rt);
  92.582 +            String tn = fqn(ert, ee);
  92.583 +            boolean array = false;
  92.584 +            final TypeMirror toCheck;
  92.585 +            if (tn.equals("java.util.List")) {
  92.586 +                array = true;
  92.587 +                toCheck = ((DeclaredType)rt).getTypeArguments().get(0);
  92.588 +            } else {
  92.589 +                toCheck = rt;
  92.590 +            }
  92.591 +            
  92.592 +            final String sn = ee.getSimpleName().toString();
  92.593 +            
  92.594 +            if (toCheck.getKind().isPrimitive()) {
  92.595 +                // OK
  92.596 +            } else {
  92.597 +                TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
  92.598 +                TypeMirror enumType = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType();
  92.599 +
  92.600 +                if (tu.isSubtype(toCheck, stringType)) {
  92.601 +                    // OK
  92.602 +                } else if (tu.isSubtype(tu.erasure(toCheck), tu.erasure(enumType))) {
  92.603 +                    // OK
  92.604 +                } else if (isModel(toCheck)) {
  92.605 +                    // OK
  92.606 +                } else {
  92.607 +                    ok = false;
  92.608 +                    error(sn + " cannot return " + toCheck, e);
  92.609 +                }
  92.610 +            }
  92.611 +            
  92.612 +            String[] gs = toGetSet(sn, tn, array);
  92.613 +            
  92.614 +            w.write("  public " + tn + " " + gs[0] + "() {\n");
  92.615 +            w.write("    if (locked) throw new IllegalStateException();\n");
  92.616 +            int arg = 0;
  92.617 +            for (VariableElement pe : ee.getParameters()) {
  92.618 +                final String dn = pe.getSimpleName().toString();
  92.619 +                
  92.620 +                if (!verifyPropName(pe, dn, fixedProps)) {
  92.621 +                    ok = false;
  92.622 +                }
  92.623 +                
  92.624 +                final String dt = fqn(pe.asType(), ee);
  92.625 +                String[] call = toGetSet(dn, dt, false);
  92.626 +                w.write("    " + dt + " arg" + (++arg) + " = ");
  92.627 +                w.write(call[0] + "();\n");
  92.628 +                
  92.629 +                Collection<String> depends = deps.get(dn);
  92.630 +                if (depends == null) {
  92.631 +                    depends = new LinkedHashSet<String>();
  92.632 +                    deps.put(dn, depends);
  92.633 +                }
  92.634 +                depends.add(sn);
  92.635 +            }
  92.636 +            w.write("    try {\n");
  92.637 +            w.write("      locked = true;\n");
  92.638 +            w.write("      return " + fqn(ee.getEnclosingElement().asType(), ee) + '.' + e.getSimpleName() + "(");
  92.639 +            String sep = "";
  92.640 +            for (int i = 1; i <= arg; i++) {
  92.641 +                w.write(sep);
  92.642 +                w.write("arg" + i);
  92.643 +                sep = ", ";
  92.644 +            }
  92.645 +            w.write(");\n");
  92.646 +            w.write("    } finally {\n");
  92.647 +            w.write("      locked = false;\n");
  92.648 +            w.write("    }\n");
  92.649 +            w.write("  }\n");
  92.650 +
  92.651 +            props.add(e.getSimpleName().toString());
  92.652 +            props.add(gs[2]);
  92.653 +            props.add(null);
  92.654 +            props.add(gs[0]);
  92.655 +            props.add(tn);
  92.656 +        }
  92.657 +        
  92.658 +        return ok;
  92.659 +    }
  92.660 +
  92.661 +    private static String[] toGetSet(String name, String type, boolean array) {
  92.662 +        String n = Character.toUpperCase(name.charAt(0)) + name.substring(1);
  92.663 +        String bck2brwsrType = "L" + type.replace('.', '_') + "_2";
  92.664 +        if ("int".equals(type)) {
  92.665 +            bck2brwsrType = "I";
  92.666 +        }
  92.667 +        if ("double".equals(type)) {
  92.668 +            bck2brwsrType = "D";
  92.669 +        }
  92.670 +        String pref = "get";
  92.671 +        if ("boolean".equals(type)) {
  92.672 +            pref = "is";
  92.673 +            bck2brwsrType = "Z";
  92.674 +        }
  92.675 +        final String nu = n.replace('.', '_');
  92.676 +        if (array) {
  92.677 +            return new String[] { 
  92.678 +                "get" + n,
  92.679 +                null,
  92.680 +                "get" + nu + "__Ljava_util_List_2",
  92.681 +                null
  92.682 +            };
  92.683 +        }
  92.684 +        return new String[]{
  92.685 +            pref + n, 
  92.686 +            "set" + n, 
  92.687 +            pref + nu + "__" + bck2brwsrType,
  92.688 +            "set" + nu + "__V" + bck2brwsrType
  92.689 +        };
  92.690 +    }
  92.691 +
  92.692 +    private String typeName(Element where, Prprt p) {
  92.693 +        String ret;
  92.694 +        boolean[] isModel = { false };
  92.695 +        boolean[] isEnum = { false };
  92.696 +        boolean isPrimitive[] = { false };
  92.697 +        ret = checkType(p, isModel, isEnum, isPrimitive);
  92.698 +        if (p.array()) {
  92.699 +            String bt = findBoxedType(ret);
  92.700 +            if (bt != null) {
  92.701 +                return bt;
  92.702 +            }
  92.703 +        }
  92.704 +        return ret;
  92.705 +    }
  92.706 +    
  92.707 +    private static String findBoxedType(String ret) {
  92.708 +        if (ret.equals("boolean")) {
  92.709 +            return Boolean.class.getName();
  92.710 +        }
  92.711 +        if (ret.equals("byte")) {
  92.712 +            return Byte.class.getName();
  92.713 +        }
  92.714 +        if (ret.equals("short")) {
  92.715 +            return Short.class.getName();
  92.716 +        }
  92.717 +        if (ret.equals("char")) {
  92.718 +            return Character.class.getName();
  92.719 +        }
  92.720 +        if (ret.equals("int")) {
  92.721 +            return Integer.class.getName();
  92.722 +        }
  92.723 +        if (ret.equals("long")) {
  92.724 +            return Long.class.getName();
  92.725 +        }
  92.726 +        if (ret.equals("float")) {
  92.727 +            return Float.class.getName();
  92.728 +        }
  92.729 +        if (ret.equals("double")) {
  92.730 +            return Double.class.getName();
  92.731 +        }
  92.732 +        return null;
  92.733 +    }
  92.734 +
  92.735 +    private boolean verifyPropName(Element e, String propName, Prprt[] existingProps) {
  92.736 +        StringBuilder sb = new StringBuilder();
  92.737 +        String sep = "";
  92.738 +        for (Prprt Prprt : existingProps) {
  92.739 +            if (Prprt.name().equals(propName)) {
  92.740 +                return true;
  92.741 +            }
  92.742 +            sb.append(sep);
  92.743 +            sb.append('"');
  92.744 +            sb.append(Prprt.name());
  92.745 +            sb.append('"');
  92.746 +            sep = ", ";
  92.747 +        }
  92.748 +        error(
  92.749 +            propName + " is not one of known properties: " + sb
  92.750 +            , e
  92.751 +        );
  92.752 +        return false;
  92.753 +    }
  92.754 +
  92.755 +    private static String findPkgName(Element e) {
  92.756 +        for (;;) {
  92.757 +            if (e.getKind() == ElementKind.PACKAGE) {
  92.758 +                return ((PackageElement)e).getQualifiedName().toString();
  92.759 +            }
  92.760 +            e = e.getEnclosingElement();
  92.761 +        }
  92.762 +    }
  92.763 +
  92.764 +    private boolean generateFunctions(
  92.765 +        Element clazz, StringWriter body, String className, 
  92.766 +        List<? extends Element> enclosedElements, List<String> functions
  92.767 +    ) {
  92.768 +        for (Element m : enclosedElements) {
  92.769 +            if (m.getKind() != ElementKind.METHOD) {
  92.770 +                continue;
  92.771 +            }
  92.772 +            ExecutableElement e = (ExecutableElement)m;
  92.773 +            Function onF = e.getAnnotation(Function.class);
  92.774 +            if (onF == null) {
  92.775 +                continue;
  92.776 +            }
  92.777 +            if (!e.getModifiers().contains(Modifier.STATIC)) {
  92.778 +                error("@OnFunction method needs to be static", e);
  92.779 +                return false;
  92.780 +            }
  92.781 +            if (e.getModifiers().contains(Modifier.PRIVATE)) {
  92.782 +                error("@OnFunction method cannot be private", e);
  92.783 +                return false;
  92.784 +            }
  92.785 +            if (e.getReturnType().getKind() != TypeKind.VOID) {
  92.786 +                error("@OnFunction method should return void", e);
  92.787 +                return false;
  92.788 +            }
  92.789 +            String n = e.getSimpleName().toString();
  92.790 +            body.append("  private void ").append(n).append("(Object data, Object ev) {\n");
  92.791 +            body.append("    ").append(((TypeElement)clazz).getQualifiedName()).append(".").append(n).append("(");
  92.792 +            body.append(wrapParams(e, null, className, "ev", "data"));
  92.793 +            body.append(");\n");
  92.794 +            body.append("  }\n");
  92.795 +            
  92.796 +            functions.add(n);
  92.797 +            functions.add(n + "__VLjava_lang_Object_2Ljava_lang_Object_2");
  92.798 +        }
  92.799 +        return true;
  92.800 +    }
  92.801 +
  92.802 +    private boolean generateOnChange(Element clazz, Map<String,Collection<String>> propDeps,
  92.803 +        Prprt[] properties, String className, 
  92.804 +        Map<String, Collection<String>> functionDeps
  92.805 +    ) {
  92.806 +        for (Element m : clazz.getEnclosedElements()) {
  92.807 +            if (m.getKind() != ElementKind.METHOD) {
  92.808 +                continue;
  92.809 +            }
  92.810 +            ExecutableElement e = (ExecutableElement) m;
  92.811 +            OnPropertyChange onPC = e.getAnnotation(OnPropertyChange.class);
  92.812 +            if (onPC == null) {
  92.813 +                continue;
  92.814 +            }
  92.815 +            for (String pn : onPC.value()) {
  92.816 +                if (findPrprt(properties, pn) == null && findDerivedFrom(propDeps, pn).isEmpty()) {
  92.817 +                    error("No Prprt named '" + pn + "' in the model", clazz);
  92.818 +                    return false;
  92.819 +                }
  92.820 +            }
  92.821 +            if (!e.getModifiers().contains(Modifier.STATIC)) {
  92.822 +                error("@OnPrprtChange method needs to be static", e);
  92.823 +                return false;
  92.824 +            }
  92.825 +            if (e.getModifiers().contains(Modifier.PRIVATE)) {
  92.826 +                error("@OnPrprtChange method cannot be private", e);
  92.827 +                return false;
  92.828 +            }
  92.829 +            if (e.getReturnType().getKind() != TypeKind.VOID) {
  92.830 +                error("@OnPrprtChange method should return void", e);
  92.831 +                return false;
  92.832 +            }
  92.833 +            String n = e.getSimpleName().toString();
  92.834 +            
  92.835 +            
  92.836 +            for (String pn : onPC.value()) {
  92.837 +                StringBuilder call = new StringBuilder();
  92.838 +                call.append("  ").append(clazz.getSimpleName()).append(".").append(n).append("(");
  92.839 +                call.append(wrapPropName(e, className, "name", pn));
  92.840 +                call.append(");\n");
  92.841 +                
  92.842 +                Collection<String> change = functionDeps.get(pn);
  92.843 +                if (change == null) {
  92.844 +                    change = new ArrayList<String>();
  92.845 +                    functionDeps.put(pn, change);
  92.846 +                }
  92.847 +                change.add(call.toString());
  92.848 +                for (String dpn : findDerivedFrom(propDeps, pn)) {
  92.849 +                    change = functionDeps.get(dpn);
  92.850 +                    if (change == null) {
  92.851 +                        change = new ArrayList<String>();
  92.852 +                        functionDeps.put(dpn, change);
  92.853 +                    }
  92.854 +                    change.add(call.toString());
  92.855 +                }
  92.856 +            }
  92.857 +        }
  92.858 +        return true;
  92.859 +    }
  92.860 +
  92.861 +    private boolean generateOperation(Element clazz, 
  92.862 +        StringWriter body, String className, 
  92.863 +        List<? extends Element> enclosedElements
  92.864 +    ) {
  92.865 +        for (Element m : enclosedElements) {
  92.866 +            if (m.getKind() != ElementKind.METHOD) {
  92.867 +                continue;
  92.868 +            }
  92.869 +            ExecutableElement e = (ExecutableElement)m;
  92.870 +            ModelOperation mO = e.getAnnotation(ModelOperation.class);
  92.871 +            if (mO == null) {
  92.872 +                continue;
  92.873 +            }
  92.874 +            if (!e.getModifiers().contains(Modifier.STATIC)) {
  92.875 +                error("@ModelOperation method needs to be static", e);
  92.876 +                return false;
  92.877 +            }
  92.878 +            if (e.getModifiers().contains(Modifier.PRIVATE)) {
  92.879 +                error("@ModelOperation method cannot be private", e);
  92.880 +                return false;
  92.881 +            }
  92.882 +            if (e.getReturnType().getKind() != TypeKind.VOID) {
  92.883 +                error("@ModelOperation method should return void", e);
  92.884 +                return false;
  92.885 +            }
  92.886 +            List<String> args = new ArrayList<String>();
  92.887 +            {
  92.888 +                body.append("  public void ").append(m.getSimpleName()).append("(");
  92.889 +                String sep = "";
  92.890 +                boolean checkFirst = true;
  92.891 +                for (VariableElement ve : e.getParameters()) {
  92.892 +                    final TypeMirror type = ve.asType();
  92.893 +                    CharSequence simpleName;
  92.894 +                    if (type.getKind() == TypeKind.DECLARED) {
  92.895 +                        simpleName = ((DeclaredType)type).asElement().getSimpleName();
  92.896 +                    } else {
  92.897 +                        simpleName = type.toString();
  92.898 +                    }
  92.899 +                    if (simpleName.toString().equals(className)) {
  92.900 +                        checkFirst = false;
  92.901 +                    } else {
  92.902 +                        if (checkFirst) {
  92.903 +                            error("First parameter of @ModelOperation method must be " + className, m);
  92.904 +                            return false;
  92.905 +                        }
  92.906 +                        args.add(ve.getSimpleName().toString());
  92.907 +                        body.append(sep).append("final ");
  92.908 +                        body.append(ve.asType().toString()).append(" ");
  92.909 +                        body.append(ve.toString());
  92.910 +                        sep = ", ";
  92.911 +                    }
  92.912 +                }
  92.913 +                body.append(") {\n");
  92.914 +                body.append("    org.netbeans.html.json.impl.JSON.runInBrowser(this.context, new Runnable() { public void run() {\n");
  92.915 +                body.append("      ").append(clazz.getSimpleName()).append(".").append(m.getSimpleName()).append("(");
  92.916 +                body.append(className).append(".this");
  92.917 +                for (String s : args) {
  92.918 +                    body.append(", ").append(s);
  92.919 +                }
  92.920 +                body.append(");\n");
  92.921 +                body.append("    }});\n");
  92.922 +                body.append("  }\n");
  92.923 +            }
  92.924 +            
  92.925 +        }
  92.926 +        return true;
  92.927 +    }
  92.928 +    
  92.929 +    
  92.930 +    private boolean generateReceive(
  92.931 +        Element clazz, StringWriter body, String className, 
  92.932 +        List<? extends Element> enclosedElements, List<String> functions
  92.933 +    ) {
  92.934 +        for (Element m : enclosedElements) {
  92.935 +            if (m.getKind() != ElementKind.METHOD) {
  92.936 +                continue;
  92.937 +            }
  92.938 +            ExecutableElement e = (ExecutableElement)m;
  92.939 +            OnReceive onR = e.getAnnotation(OnReceive.class);
  92.940 +            if (onR == null) {
  92.941 +                continue;
  92.942 +            }
  92.943 +            if (!e.getModifiers().contains(Modifier.STATIC)) {
  92.944 +                error("@OnReceive method needs to be static", e);
  92.945 +                return false;
  92.946 +            }
  92.947 +            if (e.getModifiers().contains(Modifier.PRIVATE)) {
  92.948 +                error("@OnReceive method cannot be private", e);
  92.949 +                return false;
  92.950 +            }
  92.951 +            if (e.getReturnType().getKind() != TypeKind.VOID) {
  92.952 +                error("@OnReceive method should return void", e);
  92.953 +                return false;
  92.954 +            }
  92.955 +            if (!onR.jsonp().isEmpty() && !"GET".equals(onR.method())) {
  92.956 +                error("JSONP works only with GET transport method", e);
  92.957 +            }
  92.958 +            String dataMirror = findDataSpecified(e, onR);
  92.959 +            if ("PUT".equals(onR.method()) && dataMirror == null) {
  92.960 +                error("PUT method needs to specify a data() class", e);
  92.961 +                return false;
  92.962 +            }
  92.963 +            if ("POST".equals(onR.method()) && dataMirror == null) {
  92.964 +                error("POST method needs to specify a data() class", e);
  92.965 +                return false;
  92.966 +            }
  92.967 +            String modelClass = null;
  92.968 +            boolean expectsList = false;
  92.969 +            List<String> args = new ArrayList<String>();
  92.970 +            {
  92.971 +                for (VariableElement ve : e.getParameters()) {
  92.972 +                    TypeMirror modelType = null;
  92.973 +                    final TypeMirror type = ve.asType();
  92.974 +                    CharSequence simpleName;
  92.975 +                    if (type.getKind() == TypeKind.DECLARED) {
  92.976 +                        simpleName = ((DeclaredType)type).asElement().getSimpleName();
  92.977 +                    } else {
  92.978 +                        simpleName = type.toString();
  92.979 +                    }
  92.980 +                    if (simpleName.toString().equals(className)) {
  92.981 +                        args.add(className + ".this");
  92.982 +                    } else if (isModel(ve.asType())) {
  92.983 +                        modelType = ve.asType();
  92.984 +                    } else if (ve.asType().getKind() == TypeKind.ARRAY) {
  92.985 +                        modelType = ((ArrayType)ve.asType()).getComponentType();
  92.986 +                        expectsList = true;
  92.987 +                    } else if (ve.asType().toString().equals("java.lang.String")) {
  92.988 +                        modelType = ve.asType();
  92.989 +                    }
  92.990 +                    if (modelType != null) {
  92.991 +                        if (modelClass != null) {
  92.992 +                            error("There can be only one model class among arguments", e);
  92.993 +                        } else {
  92.994 +                            modelClass = modelType.toString();
  92.995 +                            if (expectsList) {
  92.996 +                                args.add("arr");
  92.997 +                            } else {
  92.998 +                                args.add("arr[0]");
  92.999 +                            }
 92.1000 +                        }
 92.1001 +                    }
 92.1002 +                }
 92.1003 +            }
 92.1004 +            if (modelClass == null) {
 92.1005 +                error("The method needs to have one @Model class as parameter", e);
 92.1006 +            }
 92.1007 +            String n = e.getSimpleName().toString();
 92.1008 +            if ("WebSocket".equals(onR.method())) {
 92.1009 +                body.append("  /** Performs WebSocket communication. Call with <code>null</code> data parameter\n");
 92.1010 +                body.append("  * to open the connection (even if not required). Call with non-null data to\n");
 92.1011 +                body.append("  * send messages to server. Call again with <code>null</code> data to close the socket.\n");
 92.1012 +                body.append("  */\n");
 92.1013 +            }
 92.1014 +            body.append("  public void ").append(n).append("(");
 92.1015 +            StringBuilder urlBefore = new StringBuilder();
 92.1016 +            StringBuilder urlAfter = new StringBuilder();
 92.1017 +            String jsonpVarName = null;
 92.1018 +            {
 92.1019 +                String sep = "";
 92.1020 +                boolean skipJSONP = onR.jsonp().isEmpty();
 92.1021 +                for (String p : findParamNames(e, onR.url(), onR.jsonp(), urlBefore, urlAfter)) {
 92.1022 +                    if (!skipJSONP && p.equals(onR.jsonp())) {
 92.1023 +                        skipJSONP = true;
 92.1024 +                        jsonpVarName = p;
 92.1025 +                        continue;
 92.1026 +                    }
 92.1027 +                    body.append(sep);
 92.1028 +                    body.append("String ").append(p);
 92.1029 +                    sep = ", ";
 92.1030 +                }
 92.1031 +                if (!skipJSONP) {
 92.1032 +                    error(
 92.1033 +                        "Name of jsonp attribute ('" + onR.jsonp() + 
 92.1034 +                        "') is not used in url attribute '" + onR.url() + "'", e
 92.1035 +                    );
 92.1036 +                }
 92.1037 +                if (dataMirror != null) {
 92.1038 +                    body.append(sep).append(dataMirror.toString()).append(" data");
 92.1039 +                }
 92.1040 +            }
 92.1041 +            body.append(") {\n");
 92.1042 +            boolean webSocket = onR.method().equals("WebSocket");
 92.1043 +            if (webSocket) {
 92.1044 +                if (generateWSReceiveBody(body, onR, e, clazz, className, expectsList, modelClass, n, args, urlBefore, jsonpVarName, urlAfter, dataMirror)) {
 92.1045 +                    return false;
 92.1046 +                }
 92.1047 +                body.append("  }\n");
 92.1048 +                body.append("  private org.netbeans.html.json.impl.JSON.WS ws_" + e.getSimpleName() + ";\n");
 92.1049 +            } else {
 92.1050 +                if (generateJSONReceiveBody(body, onR, e, clazz, className, expectsList, modelClass, n, args, urlBefore, jsonpVarName, urlAfter, dataMirror)) {
 92.1051 +                    return false;
 92.1052 +                }
 92.1053 +                body.append("  }\n");
 92.1054 +            }
 92.1055 +        }
 92.1056 +        return true;
 92.1057 +    }
 92.1058 +
 92.1059 +    private boolean generateJSONReceiveBody(StringWriter body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List<String> args, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror) {
 92.1060 +        body.append(
 92.1061 +            "    class ProcessResult extends org.netbeans.html.json.impl.RcvrJSON {\n" +
 92.1062 +            "      @Override\n" +
 92.1063 +            "      public void onError(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" +
 92.1064 +            "        Exception value = ev.getException();\n"
 92.1065 +            );
 92.1066 +        if (onR.onError().isEmpty()) {
 92.1067 +            body.append(
 92.1068 +                "        value.printStackTrace();\n"
 92.1069 +                );
 92.1070 +        } else {
 92.1071 +            if (!findOnError(e, ((TypeElement)clazz), onR.onError(), className)) {
 92.1072 +                return true;
 92.1073 +            }
 92.1074 +            body.append("        ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("(");
 92.1075 +            body.append(className).append(".this, value);\n");
 92.1076 +        }
 92.1077 +        body.append(
 92.1078 +            "      }\n" +
 92.1079 +            "      @Override\n" +
 92.1080 +            "      public void onMessage(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n"
 92.1081 +            );
 92.1082 +        if (expectsList) {
 92.1083 +            body.append(
 92.1084 +                "        " + modelClass + "[] arr = new " + modelClass + "[ev.dataSize()];\n"
 92.1085 +                );
 92.1086 +        } else {
 92.1087 +            body.append(
 92.1088 +                "        " + modelClass + "[] arr = { null };\n"
 92.1089 +                );
 92.1090 +        }
 92.1091 +        body.append(
 92.1092 +            "        ev.dataRead(context, " + modelClass + ".class, arr);\n"
 92.1093 +            );
 92.1094 +        {
 92.1095 +            body.append("        ").append(clazz.getSimpleName()).append(".").append(n).append("(");
 92.1096 +            String sep = "";
 92.1097 +            for (String arg : args) {
 92.1098 +                body.append(sep);
 92.1099 +                body.append(arg);
 92.1100 +                sep = ", ";
 92.1101 +            }
 92.1102 +            body.append(");\n");
 92.1103 +        }
 92.1104 +        body.append(
 92.1105 +            "      }\n" +
 92.1106 +            "    }\n"
 92.1107 +            );
 92.1108 +        body.append("    ProcessResult pr = new ProcessResult();\n");
 92.1109 +        body.append("    org.netbeans.html.json.impl.JSON.loadJSON(context, pr,\n        ");
 92.1110 +        body.append(urlBefore).append(", ");
 92.1111 +        if (jsonpVarName != null) {
 92.1112 +            body.append(urlAfter);
 92.1113 +        } else {
 92.1114 +            body.append("null");
 92.1115 +        }
 92.1116 +        if (!"GET".equals(onR.method()) || dataMirror != null) {
 92.1117 +            body.append(", \"").append(onR.method()).append('"');
 92.1118 +            if (dataMirror != null) {
 92.1119 +                body.append(", data");
 92.1120 +            } else {
 92.1121 +                body.append(", null");
 92.1122 +            }
 92.1123 +        } else {
 92.1124 +            body.append(", null, null");
 92.1125 +        }
 92.1126 +        body.append(");\n");
 92.1127 +        return false;
 92.1128 +    }
 92.1129 +    
 92.1130 +    private boolean generateWSReceiveBody(StringWriter body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List<String> args, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror) {
 92.1131 +        body.append(
 92.1132 +            "    class ProcessResult extends org.netbeans.html.json.impl.RcvrJSON {\n" +
 92.1133 +            "      @Override\n" +
 92.1134 +            "      public void onOpen(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n"
 92.1135 +        );
 92.1136 +        body.append("        ").append(clazz.getSimpleName()).append(".").append(n).append("(");
 92.1137 +        {
 92.1138 +            String sep = "";
 92.1139 +            for (String arg : args) {
 92.1140 +                body.append(sep);
 92.1141 +                if (arg.startsWith("arr")) {
 92.1142 +                    body.append("null");
 92.1143 +                } else {
 92.1144 +                    body.append(arg);
 92.1145 +                }
 92.1146 +                sep = ", ";
 92.1147 +            }
 92.1148 +        }
 92.1149 +        body.append(");\n");
 92.1150 +        body.append(
 92.1151 +            "      }\n" +
 92.1152 +            "      @Override\n" +
 92.1153 +            "      public void onError(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n" +
 92.1154 +            "        Exception value = ev.getException();\n"
 92.1155 +            );
 92.1156 +        if (onR.onError().isEmpty()) {
 92.1157 +            body.append(
 92.1158 +                "        value.printStackTrace();\n"
 92.1159 +                );
 92.1160 +        } else {
 92.1161 +            if (!findOnError(e, ((TypeElement)clazz), onR.onError(), className)) {
 92.1162 +                return true;
 92.1163 +            }
 92.1164 +            body.append("        ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("(");
 92.1165 +            body.append(className).append(".this, value);\n");
 92.1166 +        }
 92.1167 +        body.append(
 92.1168 +            "      }\n" +
 92.1169 +            "      @Override\n" +
 92.1170 +            "      public void onMessage(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n"
 92.1171 +        );
 92.1172 +        if (expectsList) {
 92.1173 +            body.append(
 92.1174 +                "        " + modelClass + "[] arr = new " + modelClass + "[ev.dataSize()];\n"
 92.1175 +                );
 92.1176 +        } else {
 92.1177 +            body.append(
 92.1178 +                "        " + modelClass + "[] arr = { null };\n"
 92.1179 +                );
 92.1180 +        }
 92.1181 +        body.append(
 92.1182 +            "        ev.dataRead(context, " + modelClass + ".class, arr);\n"
 92.1183 +            );
 92.1184 +        {
 92.1185 +            body.append("        ").append(clazz.getSimpleName()).append(".").append(n).append("(");
 92.1186 +            String sep = "";
 92.1187 +            for (String arg : args) {
 92.1188 +                body.append(sep);
 92.1189 +                body.append(arg);
 92.1190 +                sep = ", ";
 92.1191 +            }
 92.1192 +            body.append(");\n");
 92.1193 +        }
 92.1194 +        body.append(
 92.1195 +            "      }\n"
 92.1196 +        );
 92.1197 +        if (!onR.onError().isEmpty()) {
 92.1198 +            body.append(
 92.1199 +                "      @Override\n"
 92.1200 +              + "      public void onClose(org.netbeans.html.json.impl.RcvrJSON.MsgEvnt ev) {\n"
 92.1201 +            );
 92.1202 +            body.append("        ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("(");
 92.1203 +            body.append(className).append(".this, null);\n");
 92.1204 +            body.append(
 92.1205 +                "      }\n"
 92.1206 +            );
 92.1207 +        }
 92.1208 +        body.append("    }\n");
 92.1209 +        body.append("    if (this.ws_").append(e.getSimpleName()).append(" == null) {\n");
 92.1210 +        body.append("      ProcessResult pr = new ProcessResult();\n");
 92.1211 +        body.append("      this.ws_").append(e.getSimpleName());
 92.1212 +        body.append("= org.netbeans.html.json.impl.JSON.openWS(context, pr,\n        ");
 92.1213 +        body.append(urlBefore).append(", data);\n");
 92.1214 +        body.append("    } else {\n");
 92.1215 +        body.append("      this.ws_").append(e.getSimpleName()).append(".send(context, ").append(urlBefore).append(", data);\n");
 92.1216 +        body.append("    }\n");
 92.1217 +        return false;
 92.1218 +    }
 92.1219 +
 92.1220 +    private CharSequence wrapParams(
 92.1221 +        ExecutableElement ee, String id, String className, String evName, String dataName
 92.1222 +    ) {
 92.1223 +        TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
 92.1224 +        StringBuilder params = new StringBuilder();
 92.1225 +        boolean first = true;
 92.1226 +        for (VariableElement ve : ee.getParameters()) {
 92.1227 +            if (!first) {
 92.1228 +                params.append(", ");
 92.1229 +            }
 92.1230 +            first = false;
 92.1231 +            String toCall = null;
 92.1232 +            String toFinish = null;
 92.1233 +            if (ve.asType() == stringType) {
 92.1234 +                if (ve.getSimpleName().contentEquals("id")) {
 92.1235 +                    params.append('"').append(id).append('"');
 92.1236 +                    continue;
 92.1237 +                }
 92.1238 +                toCall = "org.netbeans.html.json.impl.JSON.toString(context, ";
 92.1239 +            }
 92.1240 +            if (ve.asType().getKind() == TypeKind.DOUBLE) {
 92.1241 +                toCall = "org.netbeans.html.json.impl.JSON.toNumber(context, ";
 92.1242 +                toFinish = ".doubleValue()";
 92.1243 +            }
 92.1244 +            if (ve.asType().getKind() == TypeKind.INT) {
 92.1245 +                toCall = "org.netbeans.html.json.impl.JSON.toNumber(context, ";
 92.1246 +                toFinish = ".intValue()";
 92.1247 +            }
 92.1248 +            if (dataName != null && ve.getSimpleName().contentEquals(dataName) && isModel(ve.asType())) {
 92.1249 +                toCall = "org.netbeans.html.json.impl.JSON.toModel(context, " + ve.asType() + ".class, ";
 92.1250 +            }
 92.1251 +
 92.1252 +            if (toCall != null) {
 92.1253 +                params.append(toCall);
 92.1254 +                if (dataName != null && ve.getSimpleName().contentEquals(dataName)) {
 92.1255 +                    params.append(dataName);
 92.1256 +                    params.append(", null");
 92.1257 +                } else {
 92.1258 +                    if (evName == null) {
 92.1259 +                        final StringBuilder sb = new StringBuilder();
 92.1260 +                        sb.append("Unexpected string parameter name.");
 92.1261 +                        if (dataName != null) {
 92.1262 +                            sb.append(" Try \"").append(dataName).append("\"");
 92.1263 +                        }
 92.1264 +                        error(sb.toString(), ee);
 92.1265 +                    }
 92.1266 +                    params.append(evName);
 92.1267 +                    params.append(", \"");
 92.1268 +                    params.append(ve.getSimpleName().toString());
 92.1269 +                    params.append("\"");
 92.1270 +                }
 92.1271 +                params.append(")");
 92.1272 +                if (toFinish != null) {
 92.1273 +                    params.append(toFinish);
 92.1274 +                }
 92.1275 +                continue;
 92.1276 +            }
 92.1277 +            String rn = fqn(ve.asType(), ee);
 92.1278 +            int last = rn.lastIndexOf('.');
 92.1279 +            if (last >= 0) {
 92.1280 +                rn = rn.substring(last + 1);
 92.1281 +            }
 92.1282 +            if (rn.equals(className)) {
 92.1283 +                params.append(className).append(".this");
 92.1284 +                continue;
 92.1285 +            }
 92.1286 +            error(
 92.1287 +                "The annotated method can only accept " + className + " argument or argument named 'data'",
 92.1288 +                ee
 92.1289 +            );
 92.1290 +        }
 92.1291 +        return params;
 92.1292 +    }
 92.1293 +    
 92.1294 +    
 92.1295 +    private CharSequence wrapPropName(
 92.1296 +        ExecutableElement ee, String className, String propName, String propValue
 92.1297 +    ) {
 92.1298 +        TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
 92.1299 +        StringBuilder params = new StringBuilder();
 92.1300 +        boolean first = true;
 92.1301 +        for (VariableElement ve : ee.getParameters()) {
 92.1302 +            if (!first) {
 92.1303 +                params.append(", ");
 92.1304 +            }
 92.1305 +            first = false;
 92.1306 +            if (ve.asType() == stringType) {
 92.1307 +                if (propName != null && ve.getSimpleName().contentEquals(propName)) {
 92.1308 +                    params.append('"').append(propValue).append('"');
 92.1309 +                } else {
 92.1310 +                    error("Unexpected string parameter name. Try \"" + propName + "\".", ee);
 92.1311 +                }
 92.1312 +                continue;
 92.1313 +            }
 92.1314 +            String rn = fqn(ve.asType(), ee);
 92.1315 +            int last = rn.lastIndexOf('.');
 92.1316 +            if (last >= 0) {
 92.1317 +                rn = rn.substring(last + 1);
 92.1318 +            }
 92.1319 +            if (rn.equals(className)) {
 92.1320 +                params.append(className).append(".this");
 92.1321 +                continue;
 92.1322 +            }
 92.1323 +            error(
 92.1324 +                "@OnPrprtChange method can only accept String or " + className + " arguments",
 92.1325 +                ee);
 92.1326 +        }
 92.1327 +        return params;
 92.1328 +    }
 92.1329 +    
 92.1330 +    private boolean isModel(TypeMirror tm) {
 92.1331 +        if (tm.getKind() == TypeKind.ERROR) {
 92.1332 +            return true;
 92.1333 +        }
 92.1334 +        final Element e = processingEnv.getTypeUtils().asElement(tm);
 92.1335 +        if (e == null) {
 92.1336 +            return false;
 92.1337 +        }
 92.1338 +        for (Element ch : e.getEnclosedElements()) {
 92.1339 +            if (ch.getKind() == ElementKind.METHOD) {
 92.1340 +                ExecutableElement ee = (ExecutableElement)ch;
 92.1341 +                if (ee.getParameters().isEmpty() && ee.getSimpleName().contentEquals("modelFor")) {
 92.1342 +                    return true;
 92.1343 +                }
 92.1344 +            }
 92.1345 +        }
 92.1346 +        return models.values().contains(e.getSimpleName().toString());
 92.1347 +    }
 92.1348 +    
 92.1349 +    private void writeToString(Prprt[] props, Writer w) throws IOException {
 92.1350 +        w.write("  public String toString() {\n");
 92.1351 +        w.write("    StringBuilder sb = new StringBuilder();\n");
 92.1352 +        w.write("    sb.append('{');\n");
 92.1353 +        String sep = "";
 92.1354 +        for (Prprt p : props) {
 92.1355 +            w.write(sep);
 92.1356 +            w.append("    sb.append('\"').append(\"" + p.name() + "\")");
 92.1357 +                w.append(".append('\"').append(\":\");\n");
 92.1358 +            w.append("    sb.append(org.netbeans.html.json.impl.JSON.toJSON(prop_");
 92.1359 +            w.append(p.name()).append("));\n");
 92.1360 +            sep =    "    sb.append(',');\n";
 92.1361 +        }
 92.1362 +        w.write("    sb.append('}');\n");
 92.1363 +        w.write("    return sb.toString();\n");
 92.1364 +        w.write("  }\n");
 92.1365 +    }
 92.1366 +    private void writeClone(String className, Prprt[] props, Writer w) throws IOException {
 92.1367 +        w.write("  public " + className + " clone() {\n");
 92.1368 +        w.write("    return clone(context);\n");
 92.1369 +        w.write("  }\n");
 92.1370 +        w.write("  private " + className + " clone(net.java.html.BrwsrCtx ctx) {\n");
 92.1371 +        w.write("    " + className + " ret = new " + className + "(ctx);\n");
 92.1372 +        for (Prprt p : props) {
 92.1373 +            if (!p.array()) {
 92.1374 +                boolean isModel[] = { false };
 92.1375 +                boolean isEnum[] = { false };
 92.1376 +                boolean isPrimitive[] = { false };
 92.1377 +                checkType(p, isModel, isEnum, isPrimitive);
 92.1378 +                if (!isModel[0]) {
 92.1379 +                    w.write("    ret.prop_" + p.name() + " = prop_" + p.name() + ";\n");
 92.1380 +                    continue;
 92.1381 +                }
 92.1382 +                w.write("    ret.prop_" + p.name() + " =  prop_" + p.name() + "  == null ? null : prop_" + p.name() + ".clone();\n");
 92.1383 +            } else {
 92.1384 +                w.write("    ret.prop_" + p.name() + ".cloneAll(ctx, prop_" + p.name() + ");\n");
 92.1385 +            }
 92.1386 +        }
 92.1387 +        
 92.1388 +        w.write("    return ret;\n");
 92.1389 +        w.write("  }\n");
 92.1390 +    }
 92.1391 +
 92.1392 +    private String inPckName(Element e) {
 92.1393 +        StringBuilder sb = new StringBuilder();
 92.1394 +        while (e.getKind() != ElementKind.PACKAGE) {
 92.1395 +            if (sb.length() == 0) {
 92.1396 +                sb.append(e.getSimpleName());
 92.1397 +            } else {
 92.1398 +                sb.insert(0, '.');
 92.1399 +                sb.insert(0, e.getSimpleName());
 92.1400 +            }
 92.1401 +            e = e.getEnclosingElement();
 92.1402 +        }
 92.1403 +        return sb.toString();
 92.1404 +    }
 92.1405 +
 92.1406 +    private String fqn(TypeMirror pt, Element relative) {
 92.1407 +        if (pt.getKind() == TypeKind.ERROR) {
 92.1408 +            final Elements eu = processingEnv.getElementUtils();
 92.1409 +            PackageElement pckg = eu.getPackageOf(relative);
 92.1410 +            return pckg.getQualifiedName() + "." + pt.toString();
 92.1411 +        }
 92.1412 +        return pt.toString();
 92.1413 +    }
 92.1414 +
 92.1415 +    private String checkType(Prprt p, boolean[] isModel, boolean[] isEnum, boolean[] isPrimitive) {
 92.1416 +        TypeMirror tm;
 92.1417 +        try {
 92.1418 +            String ret = p.typeName(processingEnv);
 92.1419 +            TypeElement e = processingEnv.getElementUtils().getTypeElement(ret);
 92.1420 +            if (e == null) {
 92.1421 +                isModel[0] = true;
 92.1422 +                isEnum[0] = false;
 92.1423 +                isPrimitive[0] = false;
 92.1424 +                return ret;
 92.1425 +            }
 92.1426 +            tm = e.asType();
 92.1427 +        } catch (MirroredTypeException ex) {
 92.1428 +            tm = ex.getTypeMirror();
 92.1429 +        }
 92.1430 +        tm = processingEnv.getTypeUtils().erasure(tm);
 92.1431 +        if (isPrimitive[0] = tm.getKind().isPrimitive()) {
 92.1432 +            isEnum[0] = false;
 92.1433 +            isModel[0] = false;
 92.1434 +            return tm.toString();
 92.1435 +        }
 92.1436 +        final Element e = processingEnv.getTypeUtils().asElement(tm);
 92.1437 +        if (e.getKind() == ElementKind.CLASS && tm.getKind() == TypeKind.ERROR) {
 92.1438 +            isModel[0] = true;
 92.1439 +            isEnum[0] = false;
 92.1440 +            return e.getSimpleName().toString();
 92.1441 +        }
 92.1442 +        
 92.1443 +        final Model m = e == null ? null : e.getAnnotation(Model.class);
 92.1444 +        String ret;
 92.1445 +        if (m != null) {
 92.1446 +            ret = findPkgName(e) + '.' + m.className();
 92.1447 +            isModel[0] = true;
 92.1448 +            models.put(e, m.className());
 92.1449 +        } else if (findModelForMthd(e)) {
 92.1450 +            ret = ((TypeElement)e).getQualifiedName().toString();
 92.1451 +            isModel[0] = true;
 92.1452 +        } else {
 92.1453 +            ret = tm.toString();
 92.1454 +        }
 92.1455 +        TypeMirror enm = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType();
 92.1456 +        enm = processingEnv.getTypeUtils().erasure(enm);
 92.1457 +        isEnum[0] = processingEnv.getTypeUtils().isSubtype(tm, enm);
 92.1458 +        return ret;
 92.1459 +    }
 92.1460 +    
 92.1461 +    private static boolean findModelForMthd(Element clazz) {
 92.1462 +        if (clazz == null) {
 92.1463 +            return false;
 92.1464 +        }
 92.1465 +        for (Element e : clazz.getEnclosedElements()) {
 92.1466 +            if (e.getKind() == ElementKind.METHOD) {
 92.1467 +                ExecutableElement ee = (ExecutableElement)e;
 92.1468 +                if (
 92.1469 +                    ee.getSimpleName().contentEquals("modelFor") &&
 92.1470 +                    ee.getParameters().isEmpty()
 92.1471 +                ) {
 92.1472 +                    return true;
 92.1473 +                }
 92.1474 +            }
 92.1475 +        }
 92.1476 +        return false;
 92.1477 +    }
 92.1478 +
 92.1479 +    private Iterable<String> findParamNames(
 92.1480 +        Element e, String url, String jsonParam, StringBuilder... both
 92.1481 +    ) {
 92.1482 +        List<String> params = new ArrayList<String>();
 92.1483 +        int wasJSON = 0;
 92.1484 +
 92.1485 +        for (int pos = 0; ;) {
 92.1486 +            int next = url.indexOf('{', pos);
 92.1487 +            if (next == -1) {
 92.1488 +                both[wasJSON].append('"')
 92.1489 +                    .append(url.substring(pos))
 92.1490 +                    .append('"');
 92.1491 +                return params;
 92.1492 +            }
 92.1493 +            int close = url.indexOf('}', next);
 92.1494 +            if (close == -1) {
 92.1495 +                error("Unbalanced '{' and '}' in " + url, e);
 92.1496 +                return params;
 92.1497 +            }
 92.1498 +            final String paramName = url.substring(next + 1, close);
 92.1499 +            params.add(paramName);
 92.1500 +            if (paramName.equals(jsonParam) && !jsonParam.isEmpty()) {
 92.1501 +                both[wasJSON].append('"')
 92.1502 +                    .append(url.substring(pos, next))
 92.1503 +                    .append('"');
 92.1504 +                wasJSON = 1;
 92.1505 +            } else {
 92.1506 +                both[wasJSON].append('"')
 92.1507 +                    .append(url.substring(pos, next))
 92.1508 +                    .append("\" + ").append(paramName).append(" + ");
 92.1509 +            }
 92.1510 +            pos = close + 1;
 92.1511 +        }
 92.1512 +    }
 92.1513 +
 92.1514 +    private static Prprt findPrprt(Prprt[] properties, String propName) {
 92.1515 +        for (Prprt p : properties) {
 92.1516 +            if (propName.equals(p.name())) {
 92.1517 +                return p;
 92.1518 +            }
 92.1519 +        }
 92.1520 +        return null;
 92.1521 +    }
 92.1522 +
 92.1523 +    private boolean isPrimitive(String type) {
 92.1524 +        return 
 92.1525 +            "int".equals(type) ||
 92.1526 +            "double".equals(type) ||
 92.1527 +            "long".equals(type) ||
 92.1528 +            "short".equals(type) ||
 92.1529 +            "byte".equals(type) ||
 92.1530 +            "char".equals(type) ||
 92.1531 +            "boolean".equals(type) ||
 92.1532 +            "float".equals(type);
 92.1533 +    }
 92.1534 +
 92.1535 +    private static Collection<String> findDerivedFrom(Map<String, Collection<String>> propsDeps, String derivedProp) {
 92.1536 +        Set<String> names = new HashSet<String>();
 92.1537 +        for (Map.Entry<String, Collection<String>> e : propsDeps.entrySet()) {
 92.1538 +            if (e.getValue().contains(derivedProp)) {
 92.1539 +                names.add(e.getKey());
 92.1540 +            }
 92.1541 +        }
 92.1542 +        return names;
 92.1543 +    }
 92.1544 +    
 92.1545 +    private Prprt[] createProps(Element e, Property[] arr) {
 92.1546 +        Prprt[] ret = Prprt.wrap(processingEnv, e, arr);
 92.1547 +        Prprt[] prev = verify.put(e, ret);
 92.1548 +        if (prev != null) {
 92.1549 +            error("Two sets of properties for ", e);
 92.1550 +        }
 92.1551 +        return ret;
 92.1552 +    }
 92.1553 +    
 92.1554 +    private static String strip(String s) {
 92.1555 +        int indx = s.indexOf("__");
 92.1556 +        if (indx >= 0) {
 92.1557 +            return s.substring(0, indx);
 92.1558 +        } else {
 92.1559 +            return s;
 92.1560 +        }
 92.1561 +    }
 92.1562 +
 92.1563 +    private String findDataSpecified(ExecutableElement e, OnReceive onR) {
 92.1564 +        try {
 92.1565 +            return onR.data().getName();
 92.1566 +        } catch (MirroredTypeException ex) {
 92.1567 +            final TypeMirror tm = ex.getTypeMirror();
 92.1568 +            String name;
 92.1569 +            final Element te = processingEnv.getTypeUtils().asElement(tm);
 92.1570 +            if (te.getKind() == ElementKind.CLASS && tm.getKind() == TypeKind.ERROR) {
 92.1571 +                name = te.getSimpleName().toString();
 92.1572 +            } else {
 92.1573 +                name = tm.toString();
 92.1574 +            }
 92.1575 +            return "java.lang.Object".equals(name) ? null : name;
 92.1576 +        } catch (Exception ex) {
 92.1577 +            // fallback
 92.1578 +        }
 92.1579 +        
 92.1580 +        AnnotationMirror found = null;
 92.1581 +        for (AnnotationMirror am : e.getAnnotationMirrors()) {
 92.1582 +            if (am.getAnnotationType().toString().equals(OnReceive.class.getName())) {
 92.1583 +                found = am;
 92.1584 +            }
 92.1585 +        }
 92.1586 +        if (found == null) {
 92.1587 +            return null;
 92.1588 +        }
 92.1589 +        
 92.1590 +        for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : found.getElementValues().entrySet()) {
 92.1591 +            ExecutableElement ee = entry.getKey();
 92.1592 +            AnnotationValue av = entry.getValue();
 92.1593 +            if (ee.getSimpleName().contentEquals("data")) {
 92.1594 +                List<? extends Object> values = getAnnoValues(processingEnv, e, found);
 92.1595 +                for (Object v : values) {
 92.1596 +                    String sv = v.toString();
 92.1597 +                    if (sv.startsWith("data = ") && sv.endsWith(".class")) {
 92.1598 +                        return sv.substring(7, sv.length() - 6);
 92.1599 +                    }
 92.1600 +                }
 92.1601 +                return "error";
 92.1602 +            }
 92.1603 +        }
 92.1604 +        return null;
 92.1605 +    }
 92.1606 +
 92.1607 +    static List<? extends Object> getAnnoValues(ProcessingEnvironment pe, Element e, AnnotationMirror am) {
 92.1608 +        try {
 92.1609 +            Class<?> trees = Class.forName("com.sun.tools.javac.api.JavacTrees");
 92.1610 +            Method m = trees.getMethod("instance", ProcessingEnvironment.class);
 92.1611 +            Object instance = m.invoke(null, pe);
 92.1612 +            m = instance.getClass().getMethod("getPath", Element.class, AnnotationMirror.class);
 92.1613 +            Object path = m.invoke(instance, e, am);
 92.1614 +            m = path.getClass().getMethod("getLeaf");
 92.1615 +            Object leaf = m.invoke(path);
 92.1616 +            m = leaf.getClass().getMethod("getArguments");
 92.1617 +            return (List) m.invoke(leaf);
 92.1618 +        } catch (Exception ex) {
 92.1619 +            return Collections.emptyList();
 92.1620 +        }
 92.1621 +    }
 92.1622 +
 92.1623 +    private static class Prprt {
 92.1624 +        private final Element e;
 92.1625 +        private final AnnotationMirror tm;
 92.1626 +        private final Property p;
 92.1627 +
 92.1628 +        public Prprt(Element e, AnnotationMirror tm, Property p) {
 92.1629 +            this.e = e;
 92.1630 +            this.tm = tm;
 92.1631 +            this.p = p;
 92.1632 +        }
 92.1633 +        
 92.1634 +        String name() {
 92.1635 +            return p.name();
 92.1636 +        }
 92.1637 +        
 92.1638 +        boolean array() {
 92.1639 +            return p.array();
 92.1640 +        }
 92.1641 +
 92.1642 +        String typeName(ProcessingEnvironment env) {
 92.1643 +            RuntimeException ex;
 92.1644 +            try {
 92.1645 +                return p.type().getName();
 92.1646 +            } catch (IncompleteAnnotationException e) {
 92.1647 +                ex = e;
 92.1648 +            } catch (AnnotationTypeMismatchException e) {
 92.1649 +                ex = e;
 92.1650 +            }
 92.1651 +            for (Object v : getAnnoValues(env, e, tm)) {
 92.1652 +                String s = v.toString().replace(" ", "");
 92.1653 +                if (s.startsWith("type=") && s.endsWith(".class")) {
 92.1654 +                    return s.substring(5, s.length() - 6);
 92.1655 +                }
 92.1656 +            }
 92.1657 +            throw ex;
 92.1658 +        }
 92.1659 +        
 92.1660 +        
 92.1661 +        static Prprt[] wrap(ProcessingEnvironment pe, Element e, Property[] arr) {
 92.1662 +            if (arr.length == 0) {
 92.1663 +                return new Prprt[0];
 92.1664 +            }
 92.1665 +            
 92.1666 +            if (e.getKind() != ElementKind.CLASS) {
 92.1667 +                throw new IllegalStateException("" + e.getKind());
 92.1668 +            }
 92.1669 +            TypeElement te = (TypeElement)e;
 92.1670 +            List<? extends AnnotationValue> val = null;
 92.1671 +            for (AnnotationMirror an : te.getAnnotationMirrors()) {
 92.1672 +                for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : an.getElementValues().entrySet()) {
 92.1673 +                    if (entry.getKey().getSimpleName().contentEquals("properties")) {
 92.1674 +                        val = (List)entry.getValue().getValue();
 92.1675 +                        break;
 92.1676 +                    }
 92.1677 +                }
 92.1678 +            }
 92.1679 +            if (val == null || val.size() != arr.length) {
 92.1680 +                pe.getMessager().printMessage(Diagnostic.Kind.ERROR, "" + val, e);
 92.1681 +                return new Prprt[0];
 92.1682 +            }
 92.1683 +            Prprt[] ret = new Prprt[arr.length];
 92.1684 +            BIG: for (int i = 0; i < ret.length; i++) {
 92.1685 +                AnnotationMirror am = (AnnotationMirror)val.get(i).getValue();
 92.1686 +                ret[i] = new Prprt(e, am, arr[i]);
 92.1687 +                
 92.1688 +            }
 92.1689 +            return ret;
 92.1690 +        }
 92.1691 +    }
 92.1692 +
 92.1693 +    @Override
 92.1694 +    public Iterable<? extends Completion> getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) {
 92.1695 +        final Level l = Level.FINE;
 92.1696 +        LOG.log(l, " element: {0}", element);
 92.1697 +        LOG.log(l, " annotation: {0}", annotation);
 92.1698 +        LOG.log(l, " member: {0}", member);
 92.1699 +        LOG.log(l, " userText: {0}", userText);
 92.1700 +        LOG.log(l, "str: {0}", annotation.getAnnotationType().toString());
 92.1701 +        if (annotation.getAnnotationType().toString().equals(OnReceive.class.getName())) {
 92.1702 +            if (member.getSimpleName().contentEquals("method")) {
 92.1703 +                return Arrays.asList(
 92.1704 +                    methodOf("GET"),
 92.1705 +                    methodOf("POST"),
 92.1706 +                    methodOf("PUT"),
 92.1707 +                    methodOf("DELETE"),
 92.1708 +                    methodOf("HEAD"),
 92.1709 +                    methodOf("WebSocket")
 92.1710 +                );
 92.1711 +            }
 92.1712 +        }
 92.1713 +        
 92.1714 +        return super.getCompletions(element, annotation, member, userText);
 92.1715 +    }
 92.1716 +    
 92.1717 +    private static final Completion methodOf(String method) {
 92.1718 +        ResourceBundle rb = ResourceBundle.getBundle("org.netbeans.html.json.impl.Bundle");
 92.1719 +        return Completions.of('"' + method + '"', rb.getString("MSG_Completion_" + method));
 92.1720 +    }
 92.1721 +    
 92.1722 +    private boolean findOnError(ExecutableElement errElem, TypeElement te, String name, String className) {
 92.1723 +        String err = null;
 92.1724 +        METHODS:
 92.1725 +        for (Element e : te.getEnclosedElements()) {
 92.1726 +            if (e.getKind() != ElementKind.METHOD) {
 92.1727 +                continue;
 92.1728 +            }
 92.1729 +            if (!e.getSimpleName().contentEquals(name)) {
 92.1730 +                continue;
 92.1731 +            }
 92.1732 +            if (!e.getModifiers().contains(Modifier.STATIC)) {
 92.1733 +                errElem = (ExecutableElement) e;
 92.1734 +                err = "Would have to be static";
 92.1735 +                continue;
 92.1736 +            }
 92.1737 +            ExecutableElement ee = (ExecutableElement) e;
 92.1738 +            TypeMirror excType = processingEnv.getElementUtils().getTypeElement(Exception.class.getName()).asType();
 92.1739 +            final List<? extends VariableElement> params = ee.getParameters();
 92.1740 +            boolean error = false;
 92.1741 +            if (params.size() != 2) {
 92.1742 +                error = true;
 92.1743 +            } else {
 92.1744 +                String firstType = params.get(0).asType().toString();
 92.1745 +                int lastDot = firstType.lastIndexOf('.');
 92.1746 +                if (lastDot != -1) {
 92.1747 +                    firstType = firstType.substring(lastDot + 1);
 92.1748 +                }
 92.1749 +                if (!firstType.equals(className)) {
 92.1750 +                    error = true;
 92.1751 +                }
 92.1752 +                if (!processingEnv.getTypeUtils().isAssignable(excType, params.get(1).asType())) {
 92.1753 +                    error = true;
 92.1754 +                }
 92.1755 +            }
 92.1756 +            if (error) {
 92.1757 +                errElem = (ExecutableElement) e;
 92.1758 +                err = "Error method first argument needs to be " + className + " and second Exception";
 92.1759 +                continue;
 92.1760 +            }
 92.1761 +            return true;
 92.1762 +        }
 92.1763 +        if (err == null) {
 92.1764 +            err = "Cannot find " + name + "(" + className + ", Exception) method in this class";
 92.1765 +        }
 92.1766 +        error(err, errElem);
 92.1767 +        return false;
 92.1768 +    }
 92.1769 +    
 92.1770 +}
    93.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    93.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/PropertyBindingAccessor.java	Mon Dec 16 16:59:43 2013 +0100
    93.3 @@ -0,0 +1,135 @@
    93.4 +/**
    93.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    93.6 + *
    93.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    93.8 + *
    93.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   93.10 + * Other names may be trademarks of their respective owners.
   93.11 + *
   93.12 + * The contents of this file are subject to the terms of either the GNU
   93.13 + * General Public License Version 2 only ("GPL") or the Common
   93.14 + * Development and Distribution License("CDDL") (collectively, the
   93.15 + * "License"). You may not use this file except in compliance with the
   93.16 + * License. You can obtain a copy of the License at
   93.17 + * http://www.netbeans.org/cddl-gplv2.html
   93.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   93.19 + * specific language governing permissions and limitations under the
   93.20 + * License.  When distributing the software, include this License Header
   93.21 + * Notice in each file and include the License file at
   93.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   93.23 + * particular file as subject to the "Classpath" exception as provided
   93.24 + * by Oracle in the GPL Version 2 section of the License file that
   93.25 + * accompanied this code. If applicable, add the following below the
   93.26 + * License Header, with the fields enclosed by brackets [] replaced by
   93.27 + * your own identifying information:
   93.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   93.29 + *
   93.30 + * Contributor(s):
   93.31 + *
   93.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   93.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   93.34 + *
   93.35 + * If you wish your version of this file to be governed by only the CDDL
   93.36 + * or only the GPL Version 2, indicate your decision by adding
   93.37 + * "[Contributor] elects to include this software in this distribution
   93.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   93.39 + * single choice of license, a recipient has the option to distribute
   93.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   93.41 + * to extend the choice of license to its licensees as provided above.
   93.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   93.43 + * Version 2 license, then the option applies only if the new code is
   93.44 + * made subject to such option by the copyright holder.
   93.45 + */
   93.46 +package org.netbeans.html.json.impl;
   93.47 +
   93.48 +import net.java.html.BrwsrCtx;
   93.49 +import org.apidesign.html.json.spi.FunctionBinding;
   93.50 +import org.apidesign.html.json.spi.JSONCall;
   93.51 +import org.apidesign.html.json.spi.PropertyBinding;
   93.52 +
   93.53 +/**
   93.54 + *
   93.55 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   93.56 + */
   93.57 +public abstract class PropertyBindingAccessor {
   93.58 +    private static PropertyBindingAccessor DEFAULT;
   93.59 +
   93.60 +    protected PropertyBindingAccessor() {
   93.61 +        if (DEFAULT != null) throw new IllegalStateException();
   93.62 +        DEFAULT = this;
   93.63 +    }
   93.64 +    
   93.65 +    static {
   93.66 +        JSON.initClass(PropertyBinding.class);
   93.67 +    }
   93.68 +
   93.69 +    protected abstract <M> PropertyBinding newBinding(PBData<M> d);
   93.70 +    protected abstract <M> FunctionBinding newFunction(FBData<M> d);
   93.71 +    protected abstract JSONCall newCall(
   93.72 +        BrwsrCtx ctx, RcvrJSON callback, String urlBefore, String urlAfter,
   93.73 +        String method, Object data
   93.74 +    );
   93.75 +
   93.76 +    
   93.77 +    static <M> PropertyBinding create(PBData<M> d) {
   93.78 +        return DEFAULT.newBinding(d);
   93.79 +    }
   93.80 +    static <M> FunctionBinding createFunction(FBData<M> d) {
   93.81 +        return DEFAULT.newFunction(d);
   93.82 +    }
   93.83 +    static JSONCall createCall(
   93.84 +        BrwsrCtx ctx, RcvrJSON callback, String urlBefore, String urlAfter, 
   93.85 +        String method, Object data
   93.86 +    ) {
   93.87 +        return DEFAULT.newCall(ctx, callback, urlBefore, urlAfter, method, data);
   93.88 +    }
   93.89 +
   93.90 +    public static final class PBData<M> {
   93.91 +        public final String name;
   93.92 +        public final boolean readOnly;
   93.93 +        private final M model;
   93.94 +        private final SetAndGet<M> access;
   93.95 +        private final Bindings<?> bindings;
   93.96 +
   93.97 +        public PBData(Bindings<?> bindings, String name, M model, SetAndGet<M> access, boolean readOnly) {
   93.98 +            this.bindings = bindings;
   93.99 +            this.name = name;
  93.100 +            this.model = model;
  93.101 +            this.access = access;
  93.102 +            this.readOnly = readOnly;
  93.103 +        }
  93.104 +
  93.105 +        public void setValue(Object v) {
  93.106 +            access.setValue(model, v);
  93.107 +        }
  93.108 +
  93.109 +        public Object getValue() {
  93.110 +            return access.getValue(model);
  93.111 +        }
  93.112 +
  93.113 +        public boolean isReadOnly() {
  93.114 +            return readOnly;
  93.115 +        }
  93.116 +
  93.117 +        public Bindings getBindings() {
  93.118 +            return bindings;
  93.119 +        }
  93.120 +    } // end of PBData
  93.121 +    
  93.122 +    public static final class FBData<M> {
  93.123 +        public final String name;
  93.124 +        private final M model;
  93.125 +        private final Callback<M> access;
  93.126 +
  93.127 +        public FBData(String name, M model, Callback<M> access) {
  93.128 +            this.name = name;
  93.129 +            this.model = model;
  93.130 +            this.access = access;
  93.131 +        }
  93.132 +
  93.133 +
  93.134 +        public void call(Object data, Object ev) {
  93.135 +            access.call(model, data, ev);
  93.136 +        }
  93.137 +    } // end of FBData
  93.138 +}
    94.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    94.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/RcvrJSON.java	Mon Dec 16 16:59:43 2013 +0100
    94.3 @@ -0,0 +1,149 @@
    94.4 +/**
    94.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    94.6 + *
    94.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    94.8 + *
    94.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   94.10 + * Other names may be trademarks of their respective owners.
   94.11 + *
   94.12 + * The contents of this file are subject to the terms of either the GNU
   94.13 + * General Public License Version 2 only ("GPL") or the Common
   94.14 + * Development and Distribution License("CDDL") (collectively, the
   94.15 + * "License"). You may not use this file except in compliance with the
   94.16 + * License. You can obtain a copy of the License at
   94.17 + * http://www.netbeans.org/cddl-gplv2.html
   94.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   94.19 + * specific language governing permissions and limitations under the
   94.20 + * License.  When distributing the software, include this License Header
   94.21 + * Notice in each file and include the License file at
   94.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   94.23 + * particular file as subject to the "Classpath" exception as provided
   94.24 + * by Oracle in the GPL Version 2 section of the License file that
   94.25 + * accompanied this code. If applicable, add the following below the
   94.26 + * License Header, with the fields enclosed by brackets [] replaced by
   94.27 + * your own identifying information:
   94.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   94.29 + *
   94.30 + * Contributor(s):
   94.31 + *
   94.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   94.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   94.34 + *
   94.35 + * If you wish your version of this file to be governed by only the CDDL
   94.36 + * or only the GPL Version 2, indicate your decision by adding
   94.37 + * "[Contributor] elects to include this software in this distribution
   94.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   94.39 + * single choice of license, a recipient has the option to distribute
   94.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   94.41 + * to extend the choice of license to its licensees as provided above.
   94.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   94.43 + * Version 2 license, then the option applies only if the new code is
   94.44 + * made subject to such option by the copyright holder.
   94.45 + */
   94.46 +package org.netbeans.html.json.impl;
   94.47 +
   94.48 +import net.java.html.BrwsrCtx;
   94.49 +
   94.50 +/** Super type for those who wish to receive JSON messages.
   94.51 + *
   94.52 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   94.53 + */
   94.54 +public abstract class RcvrJSON {
   94.55 +    protected void onOpen(MsgEvnt msg) {}
   94.56 +    protected abstract void onMessage(MsgEvnt msg);
   94.57 +    protected void onClose(MsgEvnt msg) {}
   94.58 +    protected abstract void onError(MsgEvnt msg);
   94.59 +    
   94.60 +    public abstract static class MsgEvnt {
   94.61 +        MsgEvnt() {
   94.62 +        }
   94.63 +        
   94.64 +        public Throwable getError() {
   94.65 +            return null;
   94.66 +        }
   94.67 +        
   94.68 +        public final Exception getException() {
   94.69 +            Throwable t = getError();
   94.70 +            if (t instanceof Exception) {
   94.71 +                return (Exception)t;
   94.72 +            }
   94.73 +            if (t == null) {
   94.74 +                return null;
   94.75 +            }
   94.76 +            return new Exception(t);
   94.77 +        }
   94.78 +        
   94.79 +        public int dataSize() {
   94.80 +            return -1;
   94.81 +        }
   94.82 +        
   94.83 +        public <Data> void dataRead(BrwsrCtx ctx, Class<? extends Data> type, Data[] fillTheArray) {
   94.84 +        }
   94.85 +
   94.86 +        public abstract void dispatch(RcvrJSON r);
   94.87 +        
   94.88 +        public static MsgEvnt createError(final Throwable t) {
   94.89 +            return new MsgEvnt() {
   94.90 +                @Override
   94.91 +                public Throwable getError() {
   94.92 +                    return t;
   94.93 +                }
   94.94 +
   94.95 +                @Override
   94.96 +                public void dispatch(RcvrJSON r) {
   94.97 +                    r.onError(this);
   94.98 +                }
   94.99 +            };
  94.100 +        }
  94.101 +        
  94.102 +        public static MsgEvnt createMessage(final Object value) {
  94.103 +            return new MsgEvnt() {
  94.104 +                @Override
  94.105 +                public int dataSize() {
  94.106 +                    if (value instanceof Object[]) {
  94.107 +                        return ((Object[])value).length;
  94.108 +                    } else {
  94.109 +                        return 1;
  94.110 +                    }
  94.111 +                }
  94.112 +                
  94.113 +                @Override
  94.114 +                public <Data> void dataRead(BrwsrCtx context, Class<? extends Data> type, Data[] arr) {
  94.115 +                    if (value instanceof Object[]) {
  94.116 +                        Object[] data = ((Object[]) value);
  94.117 +                        for (int i = 0; i < data.length && i < arr.length; i++) {
  94.118 +                            arr[i] = org.netbeans.html.json.impl.JSON.read(context, type, data[i]);
  94.119 +                        }
  94.120 +                    } else {
  94.121 +                        if (arr.length > 0) {
  94.122 +                            arr[0] = org.netbeans.html.json.impl.JSON.read(context, type, value);
  94.123 +                        }
  94.124 +                    }
  94.125 +                }
  94.126 +                
  94.127 +                @Override
  94.128 +                public void dispatch(RcvrJSON r) {
  94.129 +                    r.onMessage(this);
  94.130 +                }
  94.131 +            };
  94.132 +        }
  94.133 +        
  94.134 +        public static MsgEvnt createOpen() {
  94.135 +            return new MsgEvnt() {
  94.136 +                @Override
  94.137 +                public void dispatch(RcvrJSON r) {
  94.138 +                    r.onOpen(this);
  94.139 +                }
  94.140 +            };
  94.141 +        }
  94.142 +
  94.143 +        public static MsgEvnt createClose() {
  94.144 +            return new MsgEvnt() {
  94.145 +                @Override
  94.146 +                public void dispatch(RcvrJSON r) {
  94.147 +                    r.onClose(this);
  94.148 +                }
  94.149 +            };
  94.150 +        }
  94.151 +    } // end MsgEvnt
  94.152 +}
    95.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    95.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/SetAndGet.java	Mon Dec 16 16:59:43 2013 +0100
    95.3 @@ -0,0 +1,54 @@
    95.4 +/**
    95.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    95.6 + *
    95.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    95.8 + *
    95.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   95.10 + * Other names may be trademarks of their respective owners.
   95.11 + *
   95.12 + * The contents of this file are subject to the terms of either the GNU
   95.13 + * General Public License Version 2 only ("GPL") or the Common
   95.14 + * Development and Distribution License("CDDL") (collectively, the
   95.15 + * "License"). You may not use this file except in compliance with the
   95.16 + * License. You can obtain a copy of the License at
   95.17 + * http://www.netbeans.org/cddl-gplv2.html
   95.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   95.19 + * specific language governing permissions and limitations under the
   95.20 + * License.  When distributing the software, include this License Header
   95.21 + * Notice in each file and include the License file at
   95.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   95.23 + * particular file as subject to the "Classpath" exception as provided
   95.24 + * by Oracle in the GPL Version 2 section of the License file that
   95.25 + * accompanied this code. If applicable, add the following below the
   95.26 + * License Header, with the fields enclosed by brackets [] replaced by
   95.27 + * your own identifying information:
   95.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   95.29 + *
   95.30 + * Contributor(s):
   95.31 + *
   95.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   95.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   95.34 + *
   95.35 + * If you wish your version of this file to be governed by only the CDDL
   95.36 + * or only the GPL Version 2, indicate your decision by adding
   95.37 + * "[Contributor] elects to include this software in this distribution
   95.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   95.39 + * single choice of license, a recipient has the option to distribute
   95.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   95.41 + * to extend the choice of license to its licensees as provided above.
   95.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   95.43 + * Version 2 license, then the option applies only if the new code is
   95.44 + * made subject to such option by the copyright holder.
   95.45 + */
   95.46 +package org.netbeans.html.json.impl;
   95.47 +
   95.48 +import org.apidesign.html.json.spi.PropertyBinding;
   95.49 +
   95.50 +/** A way to implement a {@link PropertyBinding}.
   95.51 + *
   95.52 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   95.53 + */
   95.54 +public interface SetAndGet<Data> {
   95.55 +    public void setValue(Data data, Object value);
   95.56 +    public Object getValue(Data data);
   95.57 +}
    96.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    96.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/WrapperObject.java	Mon Dec 16 16:59:43 2013 +0100
    96.3 @@ -0,0 +1,82 @@
    96.4 +/**
    96.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    96.6 + *
    96.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    96.8 + *
    96.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   96.10 + * Other names may be trademarks of their respective owners.
   96.11 + *
   96.12 + * The contents of this file are subject to the terms of either the GNU
   96.13 + * General Public License Version 2 only ("GPL") or the Common
   96.14 + * Development and Distribution License("CDDL") (collectively, the
   96.15 + * "License"). You may not use this file except in compliance with the
   96.16 + * License. You can obtain a copy of the License at
   96.17 + * http://www.netbeans.org/cddl-gplv2.html
   96.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   96.19 + * specific language governing permissions and limitations under the
   96.20 + * License.  When distributing the software, include this License Header
   96.21 + * Notice in each file and include the License file at
   96.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   96.23 + * particular file as subject to the "Classpath" exception as provided
   96.24 + * by Oracle in the GPL Version 2 section of the License file that
   96.25 + * accompanied this code. If applicable, add the following below the
   96.26 + * License Header, with the fields enclosed by brackets [] replaced by
   96.27 + * your own identifying information:
   96.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   96.29 + *
   96.30 + * Contributor(s):
   96.31 + *
   96.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   96.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   96.34 + *
   96.35 + * If you wish your version of this file to be governed by only the CDDL
   96.36 + * or only the GPL Version 2, indicate your decision by adding
   96.37 + * "[Contributor] elects to include this software in this distribution
   96.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   96.39 + * single choice of license, a recipient has the option to distribute
   96.40 + * your version of this file under either the CDDL, the GPL Version 2 or
   96.41 + * to extend the choice of license to its licensees as provided above.
   96.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   96.43 + * Version 2 license, then the option applies only if the new code is
   96.44 + * made subject to such option by the copyright holder.
   96.45 + */
   96.46 +package org.netbeans.html.json.impl;
   96.47 +
   96.48 +import java.util.Collection;
   96.49 +import org.netbeans.html.json.impl.PropertyBindingAccessor.PBData;
   96.50 +
   96.51 +/** A way to extract real object from a model classes.
   96.52 + *
   96.53 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   96.54 + */
   96.55 +public final class WrapperObject {
   96.56 +    private Object ko;
   96.57 +    
   96.58 +    private WrapperObject() {
   96.59 +    }
   96.60 +    
   96.61 +    public void setRealObject(Object ko) {
   96.62 +        this.ko = ko;
   96.63 +    }
   96.64 +    
   96.65 +    public static Object find(Object object) {
   96.66 +        return find(object, null);
   96.67 +    }
   96.68 +    
   96.69 +    public static Object find(Object object, Bindings model) {
   96.70 +        if (object == null) {
   96.71 +            return null;
   96.72 +        }
   96.73 +        
   96.74 +        if (object instanceof JSONList) {
   96.75 +            return ((JSONList<?>)object).koData();
   96.76 +        }
   96.77 +        if (object instanceof Collection) {
   96.78 +            return JSONList.koData((Collection<?>)object, model);
   96.79 +        }
   96.80 +        
   96.81 +        WrapperObject ro = new WrapperObject();
   96.82 +        object.equals(ro);
   96.83 +        return ro.ko;
   96.84 +    }
   96.85 +}
    97.1 --- a/json/src/main/resources/org/apidesign/html/json/impl/Bundle.properties	Mon Dec 16 15:48:09 2013 +0100
    97.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    97.3 @@ -1,97 +0,0 @@
    97.4 -#
    97.5 -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    97.6 -#
    97.7 -# Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    97.8 -#
    97.9 -# Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   97.10 -# Other names may be trademarks of their respective owners.
   97.11 -#
   97.12 -# The contents of this file are subject to the terms of either the GNU
   97.13 -# General Public License Version 2 only ("GPL") or the Common
   97.14 -# Development and Distribution License("CDDL") (collectively, the
   97.15 -# "License"). You may not use this file except in compliance with the
   97.16 -# License. You can obtain a copy of the License at
   97.17 -# http://www.netbeans.org/cddl-gplv2.html
   97.18 -# or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   97.19 -# specific language governing permissions and limitations under the
   97.20 -# License.  When distributing the software, include this License Header
   97.21 -# Notice in each file and include the License file at
   97.22 -# nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   97.23 -# particular file as subject to the "Classpath" exception as provided
   97.24 -# by Oracle in the GPL Version 2 section of the License file that
   97.25 -# accompanied this code. If applicable, add the following below the
   97.26 -# License Header, with the fields enclosed by brackets [] replaced by
   97.27 -# your own identifying information:
   97.28 -# "Portions Copyrighted [year] [name of copyright owner]"
   97.29 -#
   97.30 -# Contributor(s):
   97.31 -#
   97.32 -# The Original Software is NetBeans. The Initial Developer of the Original
   97.33 -# Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   97.34 -#
   97.35 -# If you wish your version of this file to be governed by only the CDDL
   97.36 -# or only the GPL Version 2, indicate your decision by adding
   97.37 -# "[Contributor] elects to include this software in this distribution
   97.38 -# under the [CDDL or GPL Version 2] license." If you do not indicate a
   97.39 -# single choice of license, a recipient has the option to distribute
   97.40 -# your version of this file under either the CDDL, the GPL Version 2 or
   97.41 -# to extend the choice of license to its licensees as provided above.
   97.42 -# However, if you add GPL Version 2 code and therefore, elected the GPL
   97.43 -# Version 2 license, then the option applies only if the new code is
   97.44 -# made subject to such option by the copyright holder.
   97.45 -#
   97.46 -
   97.47 -MSG_Completion_GET=The GET method means retrieve whatever information \
   97.48 - (in the form of an entity) is identified by the Request-URI. \
   97.49 - If the Request-URI refers to a data-producing process, \
   97.50 - it is the produced data which shall be returned as the entity in \
   97.51 - the response and not the source text of the process, \
   97.52 - unless that text happens to be the output of the process.
   97.53 -
   97.54 -MSG_Completion_HEAD=The HEAD method is identical to GET except that the server \
   97.55 - MUST NOT return a message-body in the response. The metainformation \
   97.56 - contained in the HTTP headers in response to a HEAD request SHOULD be \
   97.57 - identical to the information sent in response to a GET request. \
   97.58 - This method can be used for obtaining metainformation about the entity implied \
   97.59 - by the request without transferring the entity-body itself. \
   97.60 - This method is often used for testing hypertext links for validity, \
   97.61 - accessibility, and recent modification.
   97.62 -
   97.63 -MSG_Completion_POST=The POST method is used to request that the origin server \
   97.64 - accept the entity enclosed in the request as a new subordinate of the resource \
   97.65 - identified by the Request-URI in the Request-Line. POST is designed to allow \
   97.66 - a uniform method to cover annotation of existing resources,\ 
   97.67 - posting a message to a bulletin board, newsgroup, mailing list, or similar \
   97.68 - group of articles, providing a block of data, such as the result of submitting a \
   97.69 - form, to a data-handling process or extending a database through an append operation. \
   97.70 - The actual function performed by the POST method is determined by the server \
   97.71 - and is usually dependent on the Request-URI. The posted entity is subordinate \
   97.72 - to that URI in the same way that a file is subordinate to a directory containing it, \
   97.73 - a news article is subordinate to a newsgroup to which it is posted, \
   97.74 - or a record is subordinate to a database.
   97.75 -
   97.76 -MSG_Completion_PUT=The PUT method requests that the enclosed entity be stored \
   97.77 - under the supplied Request-URI. If the Request-URI refers to an already \
   97.78 - existing resource, the enclosed entity SHOULD be considered as a modified \
   97.79 - version of the one residing on the origin server. If the Request-URI does \
   97.80 - not point to an existing resource, and that URI is capable of being defined \
   97.81 - as a new resource by the requesting user agent, the origin server can \
   97.82 - create the resource with that URI. If a new resource is created, the origin \
   97.83 - server MUST inform the user agent via the 201 (Created) response. \
   97.84 - If an existing resource is modified, either the 200 (OK) or 204 (No Content) \
   97.85 - response codes SHOULD be sent to indicate successful completion of the request. \
   97.86 - If the resource could not be created or modified with the Request-URI, an \
   97.87 - appropriate error response SHOULD be given that reflects the nature of the problem. \
   97.88 - The recipient of the entity MUST NOT ignore any Content-* (e.g. Content-Range) \
   97.89 - headers that it does not understand or implement and MUST return \
   97.90 - a 501 (Not Implemented) response in such cases.
   97.91 -
   97.92 -MSG_Completion_DELETE=The DELETE method requests that the origin server delete \
   97.93 - the resource identified by the Request-URI. This method MAY be overridden \
   97.94 - by human intervention (or other means) on the origin server. The client \
   97.95 - cannot be guaranteed that the operation has been carried out, even if \
   97.96 - the status code returned from the origin server indicates that the action \
   97.97 - has been completed successfully. However, the server SHOULD NOT indicate \
   97.98 - success unless, at the time the response is given, it intends to delete \
   97.99 - the resource or move it to an inaccessible location.
  97.100 -
    98.1 --- a/json/src/main/resources/org/apidesign/html/json/spi/package.html	Mon Dec 16 15:48:09 2013 +0100
    98.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    98.3 @@ -1,59 +0,0 @@
    98.4 -<!--
    98.5 -
    98.6 -    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    98.7 -
    98.8 -    Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    98.9 -
   98.10 -    Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   98.11 -    Other names may be trademarks of their respective owners.
   98.12 -
   98.13 -    The contents of this file are subject to the terms of either the GNU
   98.14 -    General Public License Version 2 only ("GPL") or the Common
   98.15 -    Development and Distribution License("CDDL") (collectively, the
   98.16 -    "License"). You may not use this file except in compliance with the
   98.17 -    License. You can obtain a copy of the License at
   98.18 -    http://www.netbeans.org/cddl-gplv2.html
   98.19 -    or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   98.20 -    specific language governing permissions and limitations under the
   98.21 -    License.  When distributing the software, include this License Header
   98.22 -    Notice in each file and include the License file at
   98.23 -    nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   98.24 -    particular file as subject to the "Classpath" exception as provided
   98.25 -    by Oracle in the GPL Version 2 section of the License file that
   98.26 -    accompanied this code. If applicable, add the following below the
   98.27 -    License Header, with the fields enclosed by brackets [] replaced by
   98.28 -    your own identifying information:
   98.29 -    "Portions Copyrighted [year] [name of copyright owner]"
   98.30 -
   98.31 -    Contributor(s):
   98.32 -
   98.33 -    The Original Software is NetBeans. The Initial Developer of the Original
   98.34 -    Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   98.35 -
   98.36 -    If you wish your version of this file to be governed by only the CDDL
   98.37 -    or only the GPL Version 2, indicate your decision by adding
   98.38 -    "[Contributor] elects to include this software in this distribution
   98.39 -    under the [CDDL or GPL Version 2] license." If you do not indicate a
   98.40 -    single choice of license, a recipient has the option to distribute
   98.41 -    your version of this file under either the CDDL, the GPL Version 2 or
   98.42 -    to extend the choice of license to its licensees as provided above.
   98.43 -    However, if you add GPL Version 2 code and therefore, elected the GPL
   98.44 -    Version 2 license, then the option applies only if the new code is
   98.45 -    made subject to such option by the copyright holder.
   98.46 -
   98.47 --->
   98.48 -<!DOCTYPE html>
   98.49 -<html>
   98.50 -    <head>
   98.51 -        <title></title>
   98.52 -        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
   98.53 -    </head>
   98.54 -    <body>
   98.55 -        <div>Implement 
   98.56 -            <a href="Technology.html">Technology</a> and
   98.57 -            <a href="Transfer.html">Transfer</a> and use 
   98.58 -            <a href="ContextBuilder.html">ContextBuilder</a> to create an instance
   98.59 -            of <code>Context</code> representing your technology.
   98.60 -        </div>
   98.61 -    </body>
   98.62 -</html>
    99.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    99.2 +++ b/json/src/main/resources/org/netbeans/html/json/impl/Bundle.properties	Mon Dec 16 16:59:43 2013 +0100
    99.3 @@ -0,0 +1,97 @@
    99.4 +#
    99.5 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    99.6 +#
    99.7 +# Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    99.8 +#
    99.9 +# Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   99.10 +# Other names may be trademarks of their respective owners.
   99.11 +#
   99.12 +# The contents of this file are subject to the terms of either the GNU
   99.13 +# General Public License Version 2 only ("GPL") or the Common
   99.14 +# Development and Distribution License("CDDL") (collectively, the
   99.15 +# "License"). You may not use this file except in compliance with the
   99.16 +# License. You can obtain a copy of the License at
   99.17 +# http://www.netbeans.org/cddl-gplv2.html
   99.18 +# or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   99.19 +# specific language governing permissions and limitations under the
   99.20 +# License.  When distributing the software, include this License Header
   99.21 +# Notice in each file and include the License file at
   99.22 +# nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   99.23 +# particular file as subject to the "Classpath" exception as provided
   99.24 +# by Oracle in the GPL Version 2 section of the License file that
   99.25 +# accompanied this code. If applicable, add the following below the
   99.26 +# License Header, with the fields enclosed by brackets [] replaced by
   99.27 +# your own identifying information:
   99.28 +# "Portions Copyrighted [year] [name of copyright owner]"
   99.29 +#
   99.30 +# Contributor(s):
   99.31 +#
   99.32 +# The Original Software is NetBeans. The Initial Developer of the Original
   99.33 +# Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
   99.34 +#
   99.35 +# If you wish your version of this file to be governed by only the CDDL
   99.36 +# or only the GPL Version 2, indicate your decision by adding
   99.37 +# "[Contributor] elects to include this software in this distribution
   99.38 +# under the [CDDL or GPL Version 2] license." If you do not indicate a
   99.39 +# single choice of license, a recipient has the option to distribute
   99.40 +# your version of this file under either the CDDL, the GPL Version 2 or
   99.41 +# to extend the choice of license to its licensees as provided above.
   99.42 +# However, if you add GPL Version 2 code and therefore, elected the GPL
   99.43 +# Version 2 license, then the option applies only if the new code is
   99.44 +# made subject to such option by the copyright holder.
   99.45 +#
   99.46 +
   99.47 +MSG_Completion_GET=The GET method means retrieve whatever information \
   99.48 + (in the form of an entity) is identified by the Request-URI. \
   99.49 + If the Request-URI refers to a data-producing process, \
   99.50 + it is the produced data which shall be returned as the entity in \
   99.51 + the response and not the source text of the process, \
   99.52 + unless that text happens to be the output of the process.
   99.53 +
   99.54 +MSG_Completion_HEAD=The HEAD method is identical to GET except that the server \
   99.55 + MUST NOT return a message-body in the response. The metainformation \
   99.56 + contained in the HTTP headers in response to a HEAD request SHOULD be \
   99.57 + identical to the information sent in response to a GET request. \
   99.58 + This method can be used for obtaining metainformation about the entity implied \
   99.59 + by the request without transferring the entity-body itself. \
   99.60 + This method is often used for testing hypertext links for validity, \
   99.61 + accessibility, and recent modification.
   99.62 +
   99.63 +MSG_Completion_POST=The POST method is used to request that the origin server \
   99.64 + accept the entity enclosed in the request as a new subordinate of the resource \
   99.65 + identified by the Request-URI in the Request-Line. POST is designed to allow \
   99.66 + a uniform method to cover annotation of existing resources,\ 
   99.67 + posting a message to a bulletin board, newsgroup, mailing list, or similar \
   99.68 + group of articles, providing a block of data, such as the result of submitting a \
   99.69 + form, to a data-handling process or extending a database through an append operation. \
   99.70 + The actual function performed by the POST method is determined by the server \
   99.71 + and is usually dependent on the Request-URI. The posted entity is subordinate \
   99.72 + to that URI in the same way that a file is subordinate to a directory containing it, \
   99.73 + a news article is subordinate to a newsgroup to which it is posted, \
   99.74 + or a record is subordinate to a database.
   99.75 +
   99.76 +MSG_Completion_PUT=The PUT method requests that the enclosed entity be stored \
   99.77 + under the supplied Request-URI. If the Request-URI refers to an already \
   99.78 + existing resource, the enclosed entity SHOULD be considered as a modified \
   99.79 + version of the one residing on the origin server. If the Request-URI does \
   99.80 + not point to an existing resource, and that URI is capable of being defined \
   99.81 + as a new resource by the requesting user agent, the origin server can \
   99.82 + create the resource with that URI. If a new resource is created, the origin \
   99.83 + server MUST inform the user agent via the 201 (Created) response. \
   99.84 + If an existing resource is modified, either the 200 (OK) or 204 (No Content) \
   99.85 + response codes SHOULD be sent to indicate successful completion of the request. \
   99.86 + If the resource could not be created or modified with the Request-URI, an \
   99.87 + appropriate error response SHOULD be given that reflects the nature of the problem. \
   99.88 + The recipient of the entity MUST NOT ignore any Content-* (e.g. Content-Range) \
   99.89 + headers that it does not understand or implement and MUST return \
   99.90 + a 501 (Not Implemented) response in such cases.
   99.91 +
   99.92 +MSG_Completion_DELETE=The DELETE method requests that the origin server delete \
   99.93 + the resource identified by the Request-URI. This method MAY be overridden \
   99.94 + by human intervention (or other means) on the origin server. The client \
   99.95 + cannot be guaranteed that the operation has been carried out, even if \
   99.96 + the status code returned from the origin server indicates that the action \
   99.97 + has been completed successfully. However, the server SHOULD NOT indicate \
   99.98 + success unless, at the time the response is given, it intends to delete \
   99.99 + the resource or move it to an inaccessible location.
  99.100 +
   100.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   100.2 +++ b/json/src/main/resources/org/netbeans/html/json/spi/package.html	Mon Dec 16 16:59:43 2013 +0100
   100.3 @@ -0,0 +1,59 @@
   100.4 +<!--
   100.5 +
   100.6 +    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   100.7 +
   100.8 +    Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   100.9 +
  100.10 +    Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  100.11 +    Other names may be trademarks of their respective owners.
  100.12 +
  100.13 +    The contents of this file are subject to the terms of either the GNU
  100.14 +    General Public License Version 2 only ("GPL") or the Common
  100.15 +    Development and Distribution License("CDDL") (collectively, the
  100.16 +    "License"). You may not use this file except in compliance with the
  100.17 +    License. You can obtain a copy of the License at
  100.18 +    http://www.netbeans.org/cddl-gplv2.html
  100.19 +    or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  100.20 +    specific language governing permissions and limitations under the
  100.21 +    License.  When distributing the software, include this License Header
  100.22 +    Notice in each file and include the License file at
  100.23 +    nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  100.24 +    particular file as subject to the "Classpath" exception as provided
  100.25 +    by Oracle in the GPL Version 2 section of the License file that
  100.26 +    accompanied this code. If applicable, add the following below the
  100.27 +    License Header, with the fields enclosed by brackets [] replaced by
  100.28 +    your own identifying information:
  100.29 +    "Portions Copyrighted [year] [name of copyright owner]"
  100.30 +
  100.31 +    Contributor(s):
  100.32 +
  100.33 +    The Original Software is NetBeans. The Initial Developer of the Original
  100.34 +    Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  100.35 +
  100.36 +    If you wish your version of this file to be governed by only the CDDL
  100.37 +    or only the GPL Version 2, indicate your decision by adding
  100.38 +    "[Contributor] elects to include this software in this distribution
  100.39 +    under the [CDDL or GPL Version 2] license." If you do not indicate a
  100.40 +    single choice of license, a recipient has the option to distribute
  100.41 +    your version of this file under either the CDDL, the GPL Version 2 or
  100.42 +    to extend the choice of license to its licensees as provided above.
  100.43 +    However, if you add GPL Version 2 code and therefore, elected the GPL
  100.44 +    Version 2 license, then the option applies only if the new code is
  100.45 +    made subject to such option by the copyright holder.
  100.46 +
  100.47 +-->
  100.48 +<!DOCTYPE html>
  100.49 +<html>
  100.50 +    <head>
  100.51 +        <title></title>
  100.52 +        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  100.53 +    </head>
  100.54 +    <body>
  100.55 +        <div>Implement 
  100.56 +            <a href="Technology.html">Technology</a> and
  100.57 +            <a href="Transfer.html">Transfer</a> and use 
  100.58 +            <a href="ContextBuilder.html">ContextBuilder</a> to create an instance
  100.59 +            of <code>Context</code> representing your technology.
  100.60 +        </div>
  100.61 +    </body>
  100.62 +</html>
   101.1 --- a/json/src/test/java/net/java/html/json/MapModelTest.java	Mon Dec 16 15:48:09 2013 +0100
   101.2 +++ b/json/src/test/java/net/java/html/json/MapModelTest.java	Mon Dec 16 16:59:43 2013 +0100
   101.3 @@ -49,7 +49,7 @@
   101.4  import java.util.HashMap;
   101.5  import java.util.Map;
   101.6  import org.apidesign.html.context.spi.Contexts;
   101.7 -import org.apidesign.html.json.impl.WrapperObject;
   101.8 +import org.netbeans.html.json.impl.WrapperObject;
   101.9  import org.apidesign.html.json.spi.FunctionBinding;
  101.10  import org.apidesign.html.json.spi.JSONCall;
  101.11  import org.apidesign.html.json.spi.PropertyBinding;
   102.1 --- a/json/src/test/java/net/java/html/json/TypesTest.java	Mon Dec 16 15:48:09 2013 +0100
   102.2 +++ b/json/src/test/java/net/java/html/json/TypesTest.java	Mon Dec 16 16:59:43 2013 +0100
   102.3 @@ -46,7 +46,7 @@
   102.4  import java.util.Map;
   102.5  import net.java.html.json.MapModelTest.One;
   102.6  import org.apidesign.html.context.spi.Contexts;
   102.7 -import org.apidesign.html.json.impl.WrapperObject;
   102.8 +import org.netbeans.html.json.impl.WrapperObject;
   102.9  import org.apidesign.html.json.spi.Technology;
  102.10  import org.apidesign.html.json.spi.Transfer;
  102.11  import org.testng.annotations.BeforeMethod;
   103.1 --- a/json/src/test/java/org/apidesign/html/json/impl/ConstructorTest.java	Mon Dec 16 15:48:09 2013 +0100
   103.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   103.3 @@ -1,80 +0,0 @@
   103.4 -/**
   103.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   103.6 - *
   103.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   103.8 - *
   103.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  103.10 - * Other names may be trademarks of their respective owners.
  103.11 - *
  103.12 - * The contents of this file are subject to the terms of either the GNU
  103.13 - * General Public License Version 2 only ("GPL") or the Common
  103.14 - * Development and Distribution License("CDDL") (collectively, the
  103.15 - * "License"). You may not use this file except in compliance with the
  103.16 - * License. You can obtain a copy of the License at
  103.17 - * http://www.netbeans.org/cddl-gplv2.html
  103.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  103.19 - * specific language governing permissions and limitations under the
  103.20 - * License.  When distributing the software, include this License Header
  103.21 - * Notice in each file and include the License file at
  103.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  103.23 - * particular file as subject to the "Classpath" exception as provided
  103.24 - * by Oracle in the GPL Version 2 section of the License file that
  103.25 - * accompanied this code. If applicable, add the following below the
  103.26 - * License Header, with the fields enclosed by brackets [] replaced by
  103.27 - * your own identifying information:
  103.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  103.29 - *
  103.30 - * Contributor(s):
  103.31 - *
  103.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  103.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  103.34 - *
  103.35 - * If you wish your version of this file to be governed by only the CDDL
  103.36 - * or only the GPL Version 2, indicate your decision by adding
  103.37 - * "[Contributor] elects to include this software in this distribution
  103.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  103.39 - * single choice of license, a recipient has the option to distribute
  103.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  103.41 - * to extend the choice of license to its licensees as provided above.
  103.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  103.43 - * Version 2 license, then the option applies only if the new code is
  103.44 - * made subject to such option by the copyright holder.
  103.45 - */
  103.46 -package org.apidesign.html.json.impl;
  103.47 -
  103.48 -import net.java.html.json.Model;
  103.49 -import net.java.html.json.Property;
  103.50 -import static org.testng.Assert.assertNotNull;
  103.51 -import static org.testng.Assert.assertEquals;
  103.52 -import org.testng.annotations.Test;
  103.53 -
  103.54 -/**
  103.55 - *
  103.56 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  103.57 - */
  103.58 -@Model(className="Man", properties={
  103.59 -    @Property(name = "name", type = String.class),
  103.60 -    @Property(name = "other", type = Address.class, array = true),
  103.61 -    @Property(name = "primary", type = Address.class),
  103.62 -    @Property(name = "childrenNames", type = String.class, array = true)
  103.63 -})
  103.64 -public class ConstructorTest {
  103.65 -    @Model(className = "Address", properties = {
  103.66 -        @Property(name = "place", type = String.class)
  103.67 -    })
  103.68 -    static final class AddressModel {
  103.69 -    }
  103.70 -    
  103.71 -    @Test public void initializedByDefault() {
  103.72 -        Man m = new Man();
  103.73 -        assertNotNull(m.getPrimary(), "Single subobjects are initialized");
  103.74 -    }
  103.75 -    
  103.76 -    @Test public void hasRichConstructor() {
  103.77 -        Man m = new Man("Jarda", new Address("home"), new Address("work"), new Address("hotel"));
  103.78 -        assertEquals(m.getName(), "Jarda");
  103.79 -        assertNotNull(m.getPrimary(), "Primary address specified");
  103.80 -        assertNotNull(m.getPrimary().getPlace(), "home");
  103.81 -        assertEquals(m.getOther().size(), 2, "Two other addresses");
  103.82 -    }
  103.83 -}
   104.1 --- a/json/src/test/java/org/apidesign/html/json/impl/EmployeeImpl.java	Mon Dec 16 15:48:09 2013 +0100
   104.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   104.3 @@ -1,63 +0,0 @@
   104.4 -/**
   104.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   104.6 - *
   104.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   104.8 - *
   104.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  104.10 - * Other names may be trademarks of their respective owners.
  104.11 - *
  104.12 - * The contents of this file are subject to the terms of either the GNU
  104.13 - * General Public License Version 2 only ("GPL") or the Common
  104.14 - * Development and Distribution License("CDDL") (collectively, the
  104.15 - * "License"). You may not use this file except in compliance with the
  104.16 - * License. You can obtain a copy of the License at
  104.17 - * http://www.netbeans.org/cddl-gplv2.html
  104.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  104.19 - * specific language governing permissions and limitations under the
  104.20 - * License.  When distributing the software, include this License Header
  104.21 - * Notice in each file and include the License file at
  104.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  104.23 - * particular file as subject to the "Classpath" exception as provided
  104.24 - * by Oracle in the GPL Version 2 section of the License file that
  104.25 - * accompanied this code. If applicable, add the following below the
  104.26 - * License Header, with the fields enclosed by brackets [] replaced by
  104.27 - * your own identifying information:
  104.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  104.29 - *
  104.30 - * Contributor(s):
  104.31 - *
  104.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  104.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  104.34 - *
  104.35 - * If you wish your version of this file to be governed by only the CDDL
  104.36 - * or only the GPL Version 2, indicate your decision by adding
  104.37 - * "[Contributor] elects to include this software in this distribution
  104.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  104.39 - * single choice of license, a recipient has the option to distribute
  104.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  104.41 - * to extend the choice of license to its licensees as provided above.
  104.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  104.43 - * Version 2 license, then the option applies only if the new code is
  104.44 - * made subject to such option by the copyright holder.
  104.45 - */
  104.46 -package org.apidesign.html.json.impl;
  104.47 -
  104.48 -import net.java.html.json.Model;
  104.49 -import net.java.html.json.OnReceive;
  104.50 -import net.java.html.json.Person;
  104.51 -import net.java.html.json.Property;
  104.52 -
  104.53 -/**
  104.54 - *
  104.55 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  104.56 - */
  104.57 -@Model(className = "Employee", properties = {
  104.58 -    @Property(name = "person", type = Person.class),
  104.59 -    @Property(name = "employer", type = Employer.class)
  104.60 -})
  104.61 -public class EmployeeImpl {
  104.62 -    @OnReceive(url = "some/url")
  104.63 -    static void changePersonality(Employee e, Person p) {
  104.64 -        e.setPerson(p);
  104.65 -    }
  104.66 -}
   105.1 --- a/json/src/test/java/org/apidesign/html/json/impl/EmployerTest.java	Mon Dec 16 15:48:09 2013 +0100
   105.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   105.3 @@ -1,65 +0,0 @@
   105.4 -/**
   105.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   105.6 - *
   105.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   105.8 - *
   105.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  105.10 - * Other names may be trademarks of their respective owners.
  105.11 - *
  105.12 - * The contents of this file are subject to the terms of either the GNU
  105.13 - * General Public License Version 2 only ("GPL") or the Common
  105.14 - * Development and Distribution License("CDDL") (collectively, the
  105.15 - * "License"). You may not use this file except in compliance with the
  105.16 - * License. You can obtain a copy of the License at
  105.17 - * http://www.netbeans.org/cddl-gplv2.html
  105.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  105.19 - * specific language governing permissions and limitations under the
  105.20 - * License.  When distributing the software, include this License Header
  105.21 - * Notice in each file and include the License file at
  105.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  105.23 - * particular file as subject to the "Classpath" exception as provided
  105.24 - * by Oracle in the GPL Version 2 section of the License file that
  105.25 - * accompanied this code. If applicable, add the following below the
  105.26 - * License Header, with the fields enclosed by brackets [] replaced by
  105.27 - * your own identifying information:
  105.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  105.29 - *
  105.30 - * Contributor(s):
  105.31 - *
  105.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  105.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  105.34 - *
  105.35 - * If you wish your version of this file to be governed by only the CDDL
  105.36 - * or only the GPL Version 2, indicate your decision by adding
  105.37 - * "[Contributor] elects to include this software in this distribution
  105.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  105.39 - * single choice of license, a recipient has the option to distribute
  105.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  105.41 - * to extend the choice of license to its licensees as provided above.
  105.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  105.43 - * Version 2 license, then the option applies only if the new code is
  105.44 - * made subject to such option by the copyright holder.
  105.45 - */
  105.46 -package org.apidesign.html.json.impl;
  105.47 -
  105.48 -import net.java.html.BrwsrCtx;
  105.49 -import net.java.html.json.Model;
  105.50 -import net.java.html.json.Models;
  105.51 -import net.java.html.json.Property;
  105.52 -import org.testng.Assert;
  105.53 -import org.testng.annotations.Test;
  105.54 -
  105.55 -/**
  105.56 - *
  105.57 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  105.58 - */
  105.59 -@Model(className = "Employer", properties = {
  105.60 -    @Property(name = "name", type = String.class)
  105.61 -})
  105.62 -public class EmployerTest {
  105.63 -    @Test public void preLoadsTheClass() {
  105.64 -        Employer em = Models.fromRaw(BrwsrCtx.EMPTY, Employer.class, this);
  105.65 -        Assert.assertNotNull(em, "Class loaded");
  105.66 -        em.applyBindings();
  105.67 -    }
  105.68 -}
   106.1 --- a/json/src/test/java/org/apidesign/html/json/impl/JSONListTest.java	Mon Dec 16 15:48:09 2013 +0100
   106.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   106.3 @@ -1,192 +0,0 @@
   106.4 -/**
   106.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   106.6 - *
   106.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   106.8 - *
   106.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  106.10 - * Other names may be trademarks of their respective owners.
  106.11 - *
  106.12 - * The contents of this file are subject to the terms of either the GNU
  106.13 - * General Public License Version 2 only ("GPL") or the Common
  106.14 - * Development and Distribution License("CDDL") (collectively, the
  106.15 - * "License"). You may not use this file except in compliance with the
  106.16 - * License. You can obtain a copy of the License at
  106.17 - * http://www.netbeans.org/cddl-gplv2.html
  106.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  106.19 - * specific language governing permissions and limitations under the
  106.20 - * License.  When distributing the software, include this License Header
  106.21 - * Notice in each file and include the License file at
  106.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  106.23 - * particular file as subject to the "Classpath" exception as provided
  106.24 - * by Oracle in the GPL Version 2 section of the License file that
  106.25 - * accompanied this code. If applicable, add the following below the
  106.26 - * License Header, with the fields enclosed by brackets [] replaced by
  106.27 - * your own identifying information:
  106.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  106.29 - *
  106.30 - * Contributor(s):
  106.31 - *
  106.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  106.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  106.34 - *
  106.35 - * If you wish your version of this file to be governed by only the CDDL
  106.36 - * or only the GPL Version 2, indicate your decision by adding
  106.37 - * "[Contributor] elects to include this software in this distribution
  106.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  106.39 - * single choice of license, a recipient has the option to distribute
  106.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  106.41 - * to extend the choice of license to its licensees as provided above.
  106.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  106.43 - * Version 2 license, then the option applies only if the new code is
  106.44 - * made subject to such option by the copyright holder.
  106.45 - */
  106.46 -package org.apidesign.html.json.impl;
  106.47 -
  106.48 -import java.util.HashMap;
  106.49 -import java.util.Map;
  106.50 -import net.java.html.BrwsrCtx;
  106.51 -import net.java.html.json.Models;
  106.52 -import net.java.html.json.People;
  106.53 -import net.java.html.json.Person;
  106.54 -import net.java.html.json.Sex;
  106.55 -import org.apidesign.html.context.spi.Contexts;
  106.56 -import org.apidesign.html.json.spi.FunctionBinding;
  106.57 -import org.apidesign.html.json.spi.PropertyBinding;
  106.58 -import org.apidesign.html.json.spi.Technology;
  106.59 -import static org.testng.Assert.*;
  106.60 -import org.testng.annotations.BeforeMethod;
  106.61 -import org.testng.annotations.Test;
  106.62 -
  106.63 -/**
  106.64 - *
  106.65 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  106.66 - */
  106.67 -public class JSONListTest implements Technology<Object> {
  106.68 -    private boolean replaceArray;
  106.69 -    private final Map<String,PropertyBinding> bindings = new HashMap<String,PropertyBinding>();
  106.70 -    
  106.71 -    public JSONListTest() {
  106.72 -    }
  106.73 -    
  106.74 -    @BeforeMethod public void clear() {
  106.75 -        replaceArray = false;
  106.76 -    }
  106.77 -
  106.78 -    @Test public void testConvertorOnAnObject() {
  106.79 -        BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
  106.80 -        
  106.81 -        Person p = Models.bind(new Person(), c);
  106.82 -        p.setFirstName("1");
  106.83 -        p.setLastName("2");
  106.84 -        p.setSex(Sex.MALE);
  106.85 -
  106.86 -        Object real = WrapperObject.find(p);
  106.87 -        assertEquals(this, real, "I am the right model");
  106.88 -    }
  106.89 -    
  106.90 -    @Test public void testConvertorOnAnArray() {
  106.91 -        BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
  106.92 -        
  106.93 -        Person p = Models.bind(new Person(), c);
  106.94 -        p.setFirstName("1");
  106.95 -        p.setLastName("2");
  106.96 -        p.setSex(Sex.MALE);
  106.97 -        
  106.98 -        People people = Models.bind(new People(p), c).applyBindings();
  106.99 -        assertEquals(people.getInfo().toString(), "[{\"firstName\":\"1\",\"lastName\":\"2\",\"sex\":\"MALE\"}]", "Converted to real JSON");
 106.100 -        
 106.101 -        PropertyBinding pb = bindings.get("info");
 106.102 -        assertNotNull(pb, "Binding for info found");
 106.103 -        
 106.104 -        Object real = pb.getValue();
 106.105 -        assertTrue(real instanceof Object[], "It is an array: " + real);
 106.106 -        Object[] arr = (Object[])real;
 106.107 -        assertEquals(arr.length, 1, "Size is one");
 106.108 -        assertEquals(this, arr[0], "I am the right model");
 106.109 -    }
 106.110 -    
 106.111 -    @Test public void testNicknames() {
 106.112 -        BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
 106.113 -        
 106.114 -        People people = Models.bind(new People(), c).applyBindings();
 106.115 -        people.getNicknames().add("One");
 106.116 -        people.getNicknames().add("Two");
 106.117 -        
 106.118 -        PropertyBinding pb = bindings.get("nicknames");
 106.119 -        assertNotNull(pb, "Binding for info found");
 106.120 -        
 106.121 -        Object real = pb.getValue();
 106.122 -        assertTrue(real instanceof Object[], "It is an array: " + real);
 106.123 -        Object[] arr = (Object[])real;
 106.124 -        assertEquals(arr.length, 2, "Length two");
 106.125 -        assertEquals(arr[0], "One", "Text should be in the model");
 106.126 -        assertEquals(arr[1], "Two", "2nd text in the model");
 106.127 -    }
 106.128 -    
 106.129 -    @Test public void testConvertorOnAnArrayWithWrapper() {
 106.130 -        this.replaceArray = true;
 106.131 -        BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
 106.132 -        
 106.133 -        Person p = Models.bind(new Person(), c);
 106.134 -        p.setFirstName("1");
 106.135 -        p.setLastName("2");
 106.136 -        p.setSex(Sex.MALE);
 106.137 -        
 106.138 -        People people = Models.bind(new People(), c).applyBindings();
 106.139 -        people.getInfo().add(p);
 106.140 -        
 106.141 -        Object real = WrapperObject.find(people.getInfo());
 106.142 -        assertEquals(real, this, "I am the model of the array");
 106.143 -    }
 106.144 -
 106.145 -    @Test public void bindingsOnArray() {
 106.146 -        this.replaceArray = true;
 106.147 -        BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
 106.148 -        
 106.149 -        People p = Models.bind(new People(), c).applyBindings();
 106.150 -        p.getAge().add(30);
 106.151 -        
 106.152 -        PropertyBinding pb = bindings.get("age");
 106.153 -        assertNotNull(pb, "There is a binding for age list");
 106.154 -        
 106.155 -        assertEquals(pb.getValue(), this, "I am the model of the array");
 106.156 -    }
 106.157 -
 106.158 -    @Override
 106.159 -    public Object wrapModel(Object model) {
 106.160 -        return this;
 106.161 -    }
 106.162 -
 106.163 -    @Override
 106.164 -    public void bind(PropertyBinding b, Object model, Object data) {
 106.165 -        bindings.put(b.getPropertyName(), b);
 106.166 -    }
 106.167 -
 106.168 -    @Override
 106.169 -    public void valueHasMutated(Object data, String propertyName) {
 106.170 -    }
 106.171 -
 106.172 -    @Override
 106.173 -    public void expose(FunctionBinding fb, Object model, Object d) {
 106.174 -    }
 106.175 -
 106.176 -    @Override
 106.177 -    public void applyBindings(Object data) {
 106.178 -    }
 106.179 -
 106.180 -    @Override
 106.181 -    public Object wrapArray(Object[] arr) {
 106.182 -        return replaceArray ? this : arr;
 106.183 -    }
 106.184 -
 106.185 -    @Override
 106.186 -    public <M> M toModel(Class<M> modelClass, Object data) {
 106.187 -        return modelClass.cast(data);
 106.188 -    }
 106.189 -
 106.190 -    @Override
 106.191 -    public void runSafe(Runnable r) {
 106.192 -        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
 106.193 -    }
 106.194 -
 106.195 -}
   107.1 --- a/json/src/test/java/org/apidesign/html/json/impl/JSONTest.java	Mon Dec 16 15:48:09 2013 +0100
   107.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   107.3 @@ -1,84 +0,0 @@
   107.4 -/**
   107.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   107.6 - *
   107.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   107.8 - *
   107.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  107.10 - * Other names may be trademarks of their respective owners.
  107.11 - *
  107.12 - * The contents of this file are subject to the terms of either the GNU
  107.13 - * General Public License Version 2 only ("GPL") or the Common
  107.14 - * Development and Distribution License("CDDL") (collectively, the
  107.15 - * "License"). You may not use this file except in compliance with the
  107.16 - * License. You can obtain a copy of the License at
  107.17 - * http://www.netbeans.org/cddl-gplv2.html
  107.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  107.19 - * specific language governing permissions and limitations under the
  107.20 - * License.  When distributing the software, include this License Header
  107.21 - * Notice in each file and include the License file at
  107.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  107.23 - * particular file as subject to the "Classpath" exception as provided
  107.24 - * by Oracle in the GPL Version 2 section of the License file that
  107.25 - * accompanied this code. If applicable, add the following below the
  107.26 - * License Header, with the fields enclosed by brackets [] replaced by
  107.27 - * your own identifying information:
  107.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  107.29 - *
  107.30 - * Contributor(s):
  107.31 - *
  107.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  107.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  107.34 - *
  107.35 - * If you wish your version of this file to be governed by only the CDDL
  107.36 - * or only the GPL Version 2, indicate your decision by adding
  107.37 - * "[Contributor] elects to include this software in this distribution
  107.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  107.39 - * single choice of license, a recipient has the option to distribute
  107.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  107.41 - * to extend the choice of license to its licensees as provided above.
  107.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  107.43 - * Version 2 license, then the option applies only if the new code is
  107.44 - * made subject to such option by the copyright holder.
  107.45 - */
  107.46 -package org.apidesign.html.json.impl;
  107.47 -
  107.48 -import static org.testng.Assert.*;
  107.49 -import org.testng.annotations.Test;
  107.50 -
  107.51 -/**
  107.52 - *
  107.53 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  107.54 - */
  107.55 -public class JSONTest {
  107.56 -    
  107.57 -    public JSONTest() {
  107.58 -    }
  107.59 -
  107.60 -    @Test public void longToStringValue() {
  107.61 -        assertEquals(JSON.stringValue(Long.valueOf(1)), "1");
  107.62 -    }
  107.63 -    
  107.64 -    @Test public void booleanIsSortOfNumber() {
  107.65 -        assertEquals(JSON.numberValue(Boolean.TRUE), Integer.valueOf(1));
  107.66 -        assertEquals(JSON.numberValue(Boolean.FALSE), Integer.valueOf(0));
  107.67 -    }
  107.68 -    
  107.69 -    @Test public void numberToChar() {
  107.70 -        assertEquals(JSON.charValue(65), Character.valueOf('A'));
  107.71 -    }
  107.72 -    @Test public void booleanToChar() {
  107.73 -        assertEquals(JSON.charValue(false), Character.valueOf((char)0));
  107.74 -        assertEquals(JSON.charValue(true), Character.valueOf((char)1));
  107.75 -    }
  107.76 -    @Test public void stringToChar() {
  107.77 -        assertEquals(JSON.charValue("Ahoj"), Character.valueOf('A'));
  107.78 -    }
  107.79 -    @Test public void stringToBoolean() {
  107.80 -        assertEquals(JSON.boolValue("false"), Boolean.FALSE);
  107.81 -        assertEquals(JSON.boolValue("True"), Boolean.TRUE);
  107.82 -    }
  107.83 -    @Test public void numberToBoolean() {
  107.84 -        assertEquals(JSON.boolValue(0), Boolean.FALSE);
  107.85 -        assertEquals(JSON.boolValue(1), Boolean.TRUE);
  107.86 -    }
  107.87 -}
   108.1 --- a/json/src/test/java/org/apidesign/html/json/impl/NoPropertiesTest.java	Mon Dec 16 15:48:09 2013 +0100
   108.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   108.3 @@ -1,55 +0,0 @@
   108.4 -/**
   108.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   108.6 - *
   108.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   108.8 - *
   108.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  108.10 - * Other names may be trademarks of their respective owners.
  108.11 - *
  108.12 - * The contents of this file are subject to the terms of either the GNU
  108.13 - * General Public License Version 2 only ("GPL") or the Common
  108.14 - * Development and Distribution License("CDDL") (collectively, the
  108.15 - * "License"). You may not use this file except in compliance with the
  108.16 - * License. You can obtain a copy of the License at
  108.17 - * http://www.netbeans.org/cddl-gplv2.html
  108.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  108.19 - * specific language governing permissions and limitations under the
  108.20 - * License.  When distributing the software, include this License Header
  108.21 - * Notice in each file and include the License file at
  108.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  108.23 - * particular file as subject to the "Classpath" exception as provided
  108.24 - * by Oracle in the GPL Version 2 section of the License file that
  108.25 - * accompanied this code. If applicable, add the following below the
  108.26 - * License Header, with the fields enclosed by brackets [] replaced by
  108.27 - * your own identifying information:
  108.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  108.29 - *
  108.30 - * Contributor(s):
  108.31 - *
  108.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  108.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  108.34 - *
  108.35 - * If you wish your version of this file to be governed by only the CDDL
  108.36 - * or only the GPL Version 2, indicate your decision by adding
  108.37 - * "[Contributor] elects to include this software in this distribution
  108.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  108.39 - * single choice of license, a recipient has the option to distribute
  108.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  108.41 - * to extend the choice of license to its licensees as provided above.
  108.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  108.43 - * Version 2 license, then the option applies only if the new code is
  108.44 - * made subject to such option by the copyright holder.
  108.45 - */
  108.46 -package org.apidesign.html.json.impl;
  108.47 -
  108.48 -import net.java.html.json.Model;
  108.49 -
  108.50 -/** Originally could not compile.
  108.51 - *
  108.52 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  108.53 - */
  108.54 -@Model(className="NoProperties", properties = {
  108.55 -})
  108.56 -public class NoPropertiesTest {
  108.57 -    
  108.58 -}
   109.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   109.2 +++ b/json/src/test/java/org/netbeans/html/json/impl/ConstructorTest.java	Mon Dec 16 16:59:43 2013 +0100
   109.3 @@ -0,0 +1,80 @@
   109.4 +/**
   109.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   109.6 + *
   109.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   109.8 + *
   109.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  109.10 + * Other names may be trademarks of their respective owners.
  109.11 + *
  109.12 + * The contents of this file are subject to the terms of either the GNU
  109.13 + * General Public License Version 2 only ("GPL") or the Common
  109.14 + * Development and Distribution License("CDDL") (collectively, the
  109.15 + * "License"). You may not use this file except in compliance with the
  109.16 + * License. You can obtain a copy of the License at
  109.17 + * http://www.netbeans.org/cddl-gplv2.html
  109.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  109.19 + * specific language governing permissions and limitations under the
  109.20 + * License.  When distributing the software, include this License Header
  109.21 + * Notice in each file and include the License file at
  109.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  109.23 + * particular file as subject to the "Classpath" exception as provided
  109.24 + * by Oracle in the GPL Version 2 section of the License file that
  109.25 + * accompanied this code. If applicable, add the following below the
  109.26 + * License Header, with the fields enclosed by brackets [] replaced by
  109.27 + * your own identifying information:
  109.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  109.29 + *
  109.30 + * Contributor(s):
  109.31 + *
  109.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  109.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  109.34 + *
  109.35 + * If you wish your version of this file to be governed by only the CDDL
  109.36 + * or only the GPL Version 2, indicate your decision by adding
  109.37 + * "[Contributor] elects to include this software in this distribution
  109.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  109.39 + * single choice of license, a recipient has the option to distribute
  109.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  109.41 + * to extend the choice of license to its licensees as provided above.
  109.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  109.43 + * Version 2 license, then the option applies only if the new code is
  109.44 + * made subject to such option by the copyright holder.
  109.45 + */
  109.46 +package org.netbeans.html.json.impl;
  109.47 +
  109.48 +import net.java.html.json.Model;
  109.49 +import net.java.html.json.Property;
  109.50 +import static org.testng.Assert.assertNotNull;
  109.51 +import static org.testng.Assert.assertEquals;
  109.52 +import org.testng.annotations.Test;
  109.53 +
  109.54 +/**
  109.55 + *
  109.56 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  109.57 + */
  109.58 +@Model(className="Man", properties={
  109.59 +    @Property(name = "name", type = String.class),
  109.60 +    @Property(name = "other", type = Address.class, array = true),
  109.61 +    @Property(name = "primary", type = Address.class),
  109.62 +    @Property(name = "childrenNames", type = String.class, array = true)
  109.63 +})
  109.64 +public class ConstructorTest {
  109.65 +    @Model(className = "Address", properties = {
  109.66 +        @Property(name = "place", type = String.class)
  109.67 +    })
  109.68 +    static final class AddressModel {
  109.69 +    }
  109.70 +    
  109.71 +    @Test public void initializedByDefault() {
  109.72 +        Man m = new Man();
  109.73 +        assertNotNull(m.getPrimary(), "Single subobjects are initialized");
  109.74 +    }
  109.75 +    
  109.76 +    @Test public void hasRichConstructor() {
  109.77 +        Man m = new Man("Jarda", new Address("home"), new Address("work"), new Address("hotel"));
  109.78 +        assertEquals(m.getName(), "Jarda");
  109.79 +        assertNotNull(m.getPrimary(), "Primary address specified");
  109.80 +        assertNotNull(m.getPrimary().getPlace(), "home");
  109.81 +        assertEquals(m.getOther().size(), 2, "Two other addresses");
  109.82 +    }
  109.83 +}
   110.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   110.2 +++ b/json/src/test/java/org/netbeans/html/json/impl/EmployeeImpl.java	Mon Dec 16 16:59:43 2013 +0100
   110.3 @@ -0,0 +1,63 @@
   110.4 +/**
   110.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   110.6 + *
   110.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   110.8 + *
   110.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  110.10 + * Other names may be trademarks of their respective owners.
  110.11 + *
  110.12 + * The contents of this file are subject to the terms of either the GNU
  110.13 + * General Public License Version 2 only ("GPL") or the Common
  110.14 + * Development and Distribution License("CDDL") (collectively, the
  110.15 + * "License"). You may not use this file except in compliance with the
  110.16 + * License. You can obtain a copy of the License at
  110.17 + * http://www.netbeans.org/cddl-gplv2.html
  110.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  110.19 + * specific language governing permissions and limitations under the
  110.20 + * License.  When distributing the software, include this License Header
  110.21 + * Notice in each file and include the License file at
  110.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  110.23 + * particular file as subject to the "Classpath" exception as provided
  110.24 + * by Oracle in the GPL Version 2 section of the License file that
  110.25 + * accompanied this code. If applicable, add the following below the
  110.26 + * License Header, with the fields enclosed by brackets [] replaced by
  110.27 + * your own identifying information:
  110.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  110.29 + *
  110.30 + * Contributor(s):
  110.31 + *
  110.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  110.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  110.34 + *
  110.35 + * If you wish your version of this file to be governed by only the CDDL
  110.36 + * or only the GPL Version 2, indicate your decision by adding
  110.37 + * "[Contributor] elects to include this software in this distribution
  110.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  110.39 + * single choice of license, a recipient has the option to distribute
  110.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  110.41 + * to extend the choice of license to its licensees as provided above.
  110.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  110.43 + * Version 2 license, then the option applies only if the new code is
  110.44 + * made subject to such option by the copyright holder.
  110.45 + */
  110.46 +package org.netbeans.html.json.impl;
  110.47 +
  110.48 +import net.java.html.json.Model;
  110.49 +import net.java.html.json.OnReceive;
  110.50 +import net.java.html.json.Person;
  110.51 +import net.java.html.json.Property;
  110.52 +
  110.53 +/**
  110.54 + *
  110.55 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  110.56 + */
  110.57 +@Model(className = "Employee", properties = {
  110.58 +    @Property(name = "person", type = Person.class),
  110.59 +    @Property(name = "employer", type = Employer.class)
  110.60 +})
  110.61 +public class EmployeeImpl {
  110.62 +    @OnReceive(url = "some/url")
  110.63 +    static void changePersonality(Employee e, Person p) {
  110.64 +        e.setPerson(p);
  110.65 +    }
  110.66 +}
   111.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   111.2 +++ b/json/src/test/java/org/netbeans/html/json/impl/EmployerTest.java	Mon Dec 16 16:59:43 2013 +0100
   111.3 @@ -0,0 +1,65 @@
   111.4 +/**
   111.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   111.6 + *
   111.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   111.8 + *
   111.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  111.10 + * Other names may be trademarks of their respective owners.
  111.11 + *
  111.12 + * The contents of this file are subject to the terms of either the GNU
  111.13 + * General Public License Version 2 only ("GPL") or the Common
  111.14 + * Development and Distribution License("CDDL") (collectively, the
  111.15 + * "License"). You may not use this file except in compliance with the
  111.16 + * License. You can obtain a copy of the License at
  111.17 + * http://www.netbeans.org/cddl-gplv2.html
  111.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  111.19 + * specific language governing permissions and limitations under the
  111.20 + * License.  When distributing the software, include this License Header
  111.21 + * Notice in each file and include the License file at
  111.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  111.23 + * particular file as subject to the "Classpath" exception as provided
  111.24 + * by Oracle in the GPL Version 2 section of the License file that
  111.25 + * accompanied this code. If applicable, add the following below the
  111.26 + * License Header, with the fields enclosed by brackets [] replaced by
  111.27 + * your own identifying information:
  111.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  111.29 + *
  111.30 + * Contributor(s):
  111.31 + *
  111.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  111.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  111.34 + *
  111.35 + * If you wish your version of this file to be governed by only the CDDL
  111.36 + * or only the GPL Version 2, indicate your decision by adding
  111.37 + * "[Contributor] elects to include this software in this distribution
  111.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  111.39 + * single choice of license, a recipient has the option to distribute
  111.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  111.41 + * to extend the choice of license to its licensees as provided above.
  111.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  111.43 + * Version 2 license, then the option applies only if the new code is
  111.44 + * made subject to such option by the copyright holder.
  111.45 + */
  111.46 +package org.netbeans.html.json.impl;
  111.47 +
  111.48 +import net.java.html.BrwsrCtx;
  111.49 +import net.java.html.json.Model;
  111.50 +import net.java.html.json.Models;
  111.51 +import net.java.html.json.Property;
  111.52 +import org.testng.Assert;
  111.53 +import org.testng.annotations.Test;
  111.54 +
  111.55 +/**
  111.56 + *
  111.57 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  111.58 + */
  111.59 +@Model(className = "Employer", properties = {
  111.60 +    @Property(name = "name", type = String.class)
  111.61 +})
  111.62 +public class EmployerTest {
  111.63 +    @Test public void preLoadsTheClass() {
  111.64 +        Employer em = Models.fromRaw(BrwsrCtx.EMPTY, Employer.class, this);
  111.65 +        Assert.assertNotNull(em, "Class loaded");
  111.66 +        em.applyBindings();
  111.67 +    }
  111.68 +}
   112.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   112.2 +++ b/json/src/test/java/org/netbeans/html/json/impl/JSONListTest.java	Mon Dec 16 16:59:43 2013 +0100
   112.3 @@ -0,0 +1,192 @@
   112.4 +/**
   112.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   112.6 + *
   112.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   112.8 + *
   112.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  112.10 + * Other names may be trademarks of their respective owners.
  112.11 + *
  112.12 + * The contents of this file are subject to the terms of either the GNU
  112.13 + * General Public License Version 2 only ("GPL") or the Common
  112.14 + * Development and Distribution License("CDDL") (collectively, the
  112.15 + * "License"). You may not use this file except in compliance with the
  112.16 + * License. You can obtain a copy of the License at
  112.17 + * http://www.netbeans.org/cddl-gplv2.html
  112.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  112.19 + * specific language governing permissions and limitations under the
  112.20 + * License.  When distributing the software, include this License Header
  112.21 + * Notice in each file and include the License file at
  112.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  112.23 + * particular file as subject to the "Classpath" exception as provided
  112.24 + * by Oracle in the GPL Version 2 section of the License file that
  112.25 + * accompanied this code. If applicable, add the following below the
  112.26 + * License Header, with the fields enclosed by brackets [] replaced by
  112.27 + * your own identifying information:
  112.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  112.29 + *
  112.30 + * Contributor(s):
  112.31 + *
  112.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  112.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  112.34 + *
  112.35 + * If you wish your version of this file to be governed by only the CDDL
  112.36 + * or only the GPL Version 2, indicate your decision by adding
  112.37 + * "[Contributor] elects to include this software in this distribution
  112.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  112.39 + * single choice of license, a recipient has the option to distribute
  112.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  112.41 + * to extend the choice of license to its licensees as provided above.
  112.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  112.43 + * Version 2 license, then the option applies only if the new code is
  112.44 + * made subject to such option by the copyright holder.
  112.45 + */
  112.46 +package org.netbeans.html.json.impl;
  112.47 +
  112.48 +import java.util.HashMap;
  112.49 +import java.util.Map;
  112.50 +import net.java.html.BrwsrCtx;
  112.51 +import net.java.html.json.Models;
  112.52 +import net.java.html.json.People;
  112.53 +import net.java.html.json.Person;
  112.54 +import net.java.html.json.Sex;
  112.55 +import org.apidesign.html.context.spi.Contexts;
  112.56 +import org.apidesign.html.json.spi.FunctionBinding;
  112.57 +import org.apidesign.html.json.spi.PropertyBinding;
  112.58 +import org.apidesign.html.json.spi.Technology;
  112.59 +import static org.testng.Assert.*;
  112.60 +import org.testng.annotations.BeforeMethod;
  112.61 +import org.testng.annotations.Test;
  112.62 +
  112.63 +/**
  112.64 + *
  112.65 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  112.66 + */
  112.67 +public class JSONListTest implements Technology<Object> {
  112.68 +    private boolean replaceArray;
  112.69 +    private final Map<String,PropertyBinding> bindings = new HashMap<String,PropertyBinding>();
  112.70 +    
  112.71 +    public JSONListTest() {
  112.72 +    }
  112.73 +    
  112.74 +    @BeforeMethod public void clear() {
  112.75 +        replaceArray = false;
  112.76 +    }
  112.77 +
  112.78 +    @Test public void testConvertorOnAnObject() {
  112.79 +        BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
  112.80 +        
  112.81 +        Person p = Models.bind(new Person(), c);
  112.82 +        p.setFirstName("1");
  112.83 +        p.setLastName("2");
  112.84 +        p.setSex(Sex.MALE);
  112.85 +
  112.86 +        Object real = WrapperObject.find(p);
  112.87 +        assertEquals(this, real, "I am the right model");
  112.88 +    }
  112.89 +    
  112.90 +    @Test public void testConvertorOnAnArray() {
  112.91 +        BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
  112.92 +        
  112.93 +        Person p = Models.bind(new Person(), c);
  112.94 +        p.setFirstName("1");
  112.95 +        p.setLastName("2");
  112.96 +        p.setSex(Sex.MALE);
  112.97 +        
  112.98 +        People people = Models.bind(new People(p), c).applyBindings();
  112.99 +        assertEquals(people.getInfo().toString(), "[{\"firstName\":\"1\",\"lastName\":\"2\",\"sex\":\"MALE\"}]", "Converted to real JSON");
 112.100 +        
 112.101 +        PropertyBinding pb = bindings.get("info");
 112.102 +        assertNotNull(pb, "Binding for info found");
 112.103 +        
 112.104 +        Object real = pb.getValue();
 112.105 +        assertTrue(real instanceof Object[], "It is an array: " + real);
 112.106 +        Object[] arr = (Object[])real;
 112.107 +        assertEquals(arr.length, 1, "Size is one");
 112.108 +        assertEquals(this, arr[0], "I am the right model");
 112.109 +    }
 112.110 +    
 112.111 +    @Test public void testNicknames() {
 112.112 +        BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
 112.113 +        
 112.114 +        People people = Models.bind(new People(), c).applyBindings();
 112.115 +        people.getNicknames().add("One");
 112.116 +        people.getNicknames().add("Two");
 112.117 +        
 112.118 +        PropertyBinding pb = bindings.get("nicknames");
 112.119 +        assertNotNull(pb, "Binding for info found");
 112.120 +        
 112.121 +        Object real = pb.getValue();
 112.122 +        assertTrue(real instanceof Object[], "It is an array: " + real);
 112.123 +        Object[] arr = (Object[])real;
 112.124 +        assertEquals(arr.length, 2, "Length two");
 112.125 +        assertEquals(arr[0], "One", "Text should be in the model");
 112.126 +        assertEquals(arr[1], "Two", "2nd text in the model");
 112.127 +    }
 112.128 +    
 112.129 +    @Test public void testConvertorOnAnArrayWithWrapper() {
 112.130 +        this.replaceArray = true;
 112.131 +        BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
 112.132 +        
 112.133 +        Person p = Models.bind(new Person(), c);
 112.134 +        p.setFirstName("1");
 112.135 +        p.setLastName("2");
 112.136 +        p.setSex(Sex.MALE);
 112.137 +        
 112.138 +        People people = Models.bind(new People(), c).applyBindings();
 112.139 +        people.getInfo().add(p);
 112.140 +        
 112.141 +        Object real = WrapperObject.find(people.getInfo());
 112.142 +        assertEquals(real, this, "I am the model of the array");
 112.143 +    }
 112.144 +
 112.145 +    @Test public void bindingsOnArray() {
 112.146 +        this.replaceArray = true;
 112.147 +        BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
 112.148 +        
 112.149 +        People p = Models.bind(new People(), c).applyBindings();
 112.150 +        p.getAge().add(30);
 112.151 +        
 112.152 +        PropertyBinding pb = bindings.get("age");
 112.153 +        assertNotNull(pb, "There is a binding for age list");
 112.154 +        
 112.155 +        assertEquals(pb.getValue(), this, "I am the model of the array");
 112.156 +    }
 112.157 +
 112.158 +    @Override
 112.159 +    public Object wrapModel(Object model) {
 112.160 +        return this;
 112.161 +    }
 112.162 +
 112.163 +    @Override
 112.164 +    public void bind(PropertyBinding b, Object model, Object data) {
 112.165 +        bindings.put(b.getPropertyName(), b);
 112.166 +    }
 112.167 +
 112.168 +    @Override
 112.169 +    public void valueHasMutated(Object data, String propertyName) {
 112.170 +    }
 112.171 +
 112.172 +    @Override
 112.173 +    public void expose(FunctionBinding fb, Object model, Object d) {
 112.174 +    }
 112.175 +
 112.176 +    @Override
 112.177 +    public void applyBindings(Object data) {
 112.178 +    }
 112.179 +
 112.180 +    @Override
 112.181 +    public Object wrapArray(Object[] arr) {
 112.182 +        return replaceArray ? this : arr;
 112.183 +    }
 112.184 +
 112.185 +    @Override
 112.186 +    public <M> M toModel(Class<M> modelClass, Object data) {
 112.187 +        return modelClass.cast(data);
 112.188 +    }
 112.189 +
 112.190 +    @Override
 112.191 +    public void runSafe(Runnable r) {
 112.192 +        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
 112.193 +    }
 112.194 +
 112.195 +}
   113.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   113.2 +++ b/json/src/test/java/org/netbeans/html/json/impl/JSONTest.java	Mon Dec 16 16:59:43 2013 +0100
   113.3 @@ -0,0 +1,85 @@
   113.4 +/**
   113.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   113.6 + *
   113.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   113.8 + *
   113.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  113.10 + * Other names may be trademarks of their respective owners.
  113.11 + *
  113.12 + * The contents of this file are subject to the terms of either the GNU
  113.13 + * General Public License Version 2 only ("GPL") or the Common
  113.14 + * Development and Distribution License("CDDL") (collectively, the
  113.15 + * "License"). You may not use this file except in compliance with the
  113.16 + * License. You can obtain a copy of the License at
  113.17 + * http://www.netbeans.org/cddl-gplv2.html
  113.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  113.19 + * specific language governing permissions and limitations under the
  113.20 + * License.  When distributing the software, include this License Header
  113.21 + * Notice in each file and include the License file at
  113.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  113.23 + * particular file as subject to the "Classpath" exception as provided
  113.24 + * by Oracle in the GPL Version 2 section of the License file that
  113.25 + * accompanied this code. If applicable, add the following below the
  113.26 + * License Header, with the fields enclosed by brackets [] replaced by
  113.27 + * your own identifying information:
  113.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  113.29 + *
  113.30 + * Contributor(s):
  113.31 + *
  113.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  113.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  113.34 + *
  113.35 + * If you wish your version of this file to be governed by only the CDDL
  113.36 + * or only the GPL Version 2, indicate your decision by adding
  113.37 + * "[Contributor] elects to include this software in this distribution
  113.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  113.39 + * single choice of license, a recipient has the option to distribute
  113.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  113.41 + * to extend the choice of license to its licensees as provided above.
  113.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  113.43 + * Version 2 license, then the option applies only if the new code is
  113.44 + * made subject to such option by the copyright holder.
  113.45 + */
  113.46 +package org.netbeans.html.json.impl;
  113.47 +
  113.48 +import org.netbeans.html.json.impl.JSON;
  113.49 +import static org.testng.Assert.*;
  113.50 +import org.testng.annotations.Test;
  113.51 +
  113.52 +/**
  113.53 + *
  113.54 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  113.55 + */
  113.56 +public class JSONTest {
  113.57 +    
  113.58 +    public JSONTest() {
  113.59 +    }
  113.60 +
  113.61 +    @Test public void longToStringValue() {
  113.62 +        assertEquals(JSON.stringValue(Long.valueOf(1)), "1");
  113.63 +    }
  113.64 +    
  113.65 +    @Test public void booleanIsSortOfNumber() {
  113.66 +        assertEquals(JSON.numberValue(Boolean.TRUE), Integer.valueOf(1));
  113.67 +        assertEquals(JSON.numberValue(Boolean.FALSE), Integer.valueOf(0));
  113.68 +    }
  113.69 +    
  113.70 +    @Test public void numberToChar() {
  113.71 +        assertEquals(JSON.charValue(65), Character.valueOf('A'));
  113.72 +    }
  113.73 +    @Test public void booleanToChar() {
  113.74 +        assertEquals(JSON.charValue(false), Character.valueOf((char)0));
  113.75 +        assertEquals(JSON.charValue(true), Character.valueOf((char)1));
  113.76 +    }
  113.77 +    @Test public void stringToChar() {
  113.78 +        assertEquals(JSON.charValue("Ahoj"), Character.valueOf('A'));
  113.79 +    }
  113.80 +    @Test public void stringToBoolean() {
  113.81 +        assertEquals(JSON.boolValue("false"), Boolean.FALSE);
  113.82 +        assertEquals(JSON.boolValue("True"), Boolean.TRUE);
  113.83 +    }
  113.84 +    @Test public void numberToBoolean() {
  113.85 +        assertEquals(JSON.boolValue(0), Boolean.FALSE);
  113.86 +        assertEquals(JSON.boolValue(1), Boolean.TRUE);
  113.87 +    }
  113.88 +}
   114.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   114.2 +++ b/json/src/test/java/org/netbeans/html/json/impl/NoPropertiesTest.java	Mon Dec 16 16:59:43 2013 +0100
   114.3 @@ -0,0 +1,55 @@
   114.4 +/**
   114.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   114.6 + *
   114.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   114.8 + *
   114.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  114.10 + * Other names may be trademarks of their respective owners.
  114.11 + *
  114.12 + * The contents of this file are subject to the terms of either the GNU
  114.13 + * General Public License Version 2 only ("GPL") or the Common
  114.14 + * Development and Distribution License("CDDL") (collectively, the
  114.15 + * "License"). You may not use this file except in compliance with the
  114.16 + * License. You can obtain a copy of the License at
  114.17 + * http://www.netbeans.org/cddl-gplv2.html
  114.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  114.19 + * specific language governing permissions and limitations under the
  114.20 + * License.  When distributing the software, include this License Header
  114.21 + * Notice in each file and include the License file at
  114.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  114.23 + * particular file as subject to the "Classpath" exception as provided
  114.24 + * by Oracle in the GPL Version 2 section of the License file that
  114.25 + * accompanied this code. If applicable, add the following below the
  114.26 + * License Header, with the fields enclosed by brackets [] replaced by
  114.27 + * your own identifying information:
  114.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  114.29 + *
  114.30 + * Contributor(s):
  114.31 + *
  114.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  114.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  114.34 + *
  114.35 + * If you wish your version of this file to be governed by only the CDDL
  114.36 + * or only the GPL Version 2, indicate your decision by adding
  114.37 + * "[Contributor] elects to include this software in this distribution
  114.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  114.39 + * single choice of license, a recipient has the option to distribute
  114.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  114.41 + * to extend the choice of license to its licensees as provided above.
  114.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  114.43 + * Version 2 license, then the option applies only if the new code is
  114.44 + * made subject to such option by the copyright holder.
  114.45 + */
  114.46 +package org.netbeans.html.json.impl;
  114.47 +
  114.48 +import net.java.html.json.Model;
  114.49 +
  114.50 +/** Originally could not compile.
  114.51 + *
  114.52 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  114.53 + */
  114.54 +@Model(className="NoProperties", properties = {
  114.55 +})
  114.56 +public class NoPropertiesTest {
  114.57 +    
  114.58 +}
   115.1 --- a/ko-archetype-test/src/test/java/org/apidesign/html/archetype/test/ArchetypeVersionTest.java	Mon Dec 16 15:48:09 2013 +0100
   115.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   115.3 @@ -1,128 +0,0 @@
   115.4 -/**
   115.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   115.6 - *
   115.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   115.8 - *
   115.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  115.10 - * Other names may be trademarks of their respective owners.
  115.11 - *
  115.12 - * The contents of this file are subject to the terms of either the GNU
  115.13 - * General Public License Version 2 only ("GPL") or the Common
  115.14 - * Development and Distribution License("CDDL") (collectively, the
  115.15 - * "License"). You may not use this file except in compliance with the
  115.16 - * License. You can obtain a copy of the License at
  115.17 - * http://www.netbeans.org/cddl-gplv2.html
  115.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  115.19 - * specific language governing permissions and limitations under the
  115.20 - * License.  When distributing the software, include this License Header
  115.21 - * Notice in each file and include the License file at
  115.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  115.23 - * particular file as subject to the "Classpath" exception as provided
  115.24 - * by Oracle in the GPL Version 2 section of the License file that
  115.25 - * accompanied this code. If applicable, add the following below the
  115.26 - * License Header, with the fields enclosed by brackets [] replaced by
  115.27 - * your own identifying information:
  115.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  115.29 - *
  115.30 - * Contributor(s):
  115.31 - *
  115.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  115.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  115.34 - *
  115.35 - * If you wish your version of this file to be governed by only the CDDL
  115.36 - * or only the GPL Version 2, indicate your decision by adding
  115.37 - * "[Contributor] elects to include this software in this distribution
  115.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  115.39 - * single choice of license, a recipient has the option to distribute
  115.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  115.41 - * to extend the choice of license to its licensees as provided above.
  115.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  115.43 - * Version 2 license, then the option applies only if the new code is
  115.44 - * made subject to such option by the copyright holder.
  115.45 - */
  115.46 -package org.apidesign.html.archetype.test;
  115.47 -
  115.48 -import java.io.IOException;
  115.49 -import java.net.URL;
  115.50 -import javax.xml.XMLConstants;
  115.51 -import javax.xml.parsers.DocumentBuilderFactory;
  115.52 -import javax.xml.parsers.ParserConfigurationException;
  115.53 -import javax.xml.xpath.XPathConstants;
  115.54 -import javax.xml.xpath.XPathExpression;
  115.55 -import javax.xml.xpath.XPathExpressionException;
  115.56 -import javax.xml.xpath.XPathFactory;
  115.57 -import javax.xml.xpath.XPathFactoryConfigurationException;
  115.58 -import org.testng.annotations.Test;
  115.59 -import static org.testng.Assert.*;
  115.60 -import org.testng.annotations.BeforeClass;
  115.61 -import org.w3c.dom.Document;
  115.62 -import org.w3c.dom.NodeList;
  115.63 -import org.xml.sax.SAXException;
  115.64 -
  115.65 -/**
  115.66 - *
  115.67 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  115.68 - */
  115.69 -public class ArchetypeVersionTest {
  115.70 -    private String version;
  115.71 -    
  115.72 -    public ArchetypeVersionTest() {
  115.73 -    }
  115.74 -    
  115.75 -    @BeforeClass public void readCurrentVersion() throws Exception {
  115.76 -        version = findCurrentVersion();
  115.77 -        assertFalse(version.isEmpty(), "There should be some version string");
  115.78 -    }
  115.79 -    
  115.80 -
  115.81 -    @Test public void testComparePomDepsVersions() throws Exception {
  115.82 -        final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
  115.83 -        URL r = l.getResource("archetype-resources/pom.xml");
  115.84 -        assertNotNull(r, "Archetype pom found");
  115.85 -        
  115.86 -        final XPathFactory fact = XPathFactory.newInstance();
  115.87 -        XPathExpression xp2 = fact.newXPath().compile(
  115.88 -            "//properties/net.java.html.version/text()"
  115.89 -        );
  115.90 -        
  115.91 -        Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream());
  115.92 -        String arch = (String) xp2.evaluate(dom, XPathConstants.STRING);
  115.93 -
  115.94 -        assertEquals(arch, version, "net.java.html.json dependency needs to be on latest version");
  115.95 -    }
  115.96 -    
  115.97 -    @Test public void testNbActions() throws Exception {
  115.98 -        final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
  115.99 -        URL r = l.getResource("archetype-resources/nbactions.xml");
 115.100 -        assertNotNull(r, "Archetype nb file found");
 115.101 -        
 115.102 -        final XPathFactory fact = XPathFactory.newInstance();
 115.103 -        XPathExpression xp2 = fact.newXPath().compile(
 115.104 -            "//goal/text()"
 115.105 -        );
 115.106 -        
 115.107 -        Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream());
 115.108 -        NodeList goals = (NodeList) xp2.evaluate(dom, XPathConstants.NODESET);
 115.109 -        
 115.110 -        for (int i = 0; i < goals.getLength(); i++) {
 115.111 -            String s = goals.item(i).getTextContent();
 115.112 -            if (s.contains("apidesign")) {
 115.113 -                assertFalse(s.matches(".*apidesign.*[0-9].*"), "No numbers: " + s);
 115.114 -            }
 115.115 -        }
 115.116 -    }
 115.117 -
 115.118 -    static String findCurrentVersion() throws XPathExpressionException, IOException, ParserConfigurationException, SAXException, XPathFactoryConfigurationException {
 115.119 -        final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
 115.120 -        URL u = l.getResource("META-INF/maven/org.netbeans.html/knockout4j-archetype/pom.xml");
 115.121 -        assertNotNull(u, "Own pom found: " + System.getProperty("java.class.path"));
 115.122 -
 115.123 -        final XPathFactory fact = XPathFactory.newInstance();
 115.124 -        fact.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
 115.125 -
 115.126 -        XPathExpression xp = fact.newXPath().compile("project/version/text()");
 115.127 -        
 115.128 -        Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(u.openStream());
 115.129 -        return xp.evaluate(dom);
 115.130 -    }
 115.131 -}
   116.1 --- a/ko-archetype-test/src/test/java/org/apidesign/html/archetype/test/VerifyArchetypeTest.java	Mon Dec 16 15:48:09 2013 +0100
   116.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   116.3 @@ -1,99 +0,0 @@
   116.4 -/**
   116.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   116.6 - *
   116.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   116.8 - *
   116.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  116.10 - * Other names may be trademarks of their respective owners.
  116.11 - *
  116.12 - * The contents of this file are subject to the terms of either the GNU
  116.13 - * General Public License Version 2 only ("GPL") or the Common
  116.14 - * Development and Distribution License("CDDL") (collectively, the
  116.15 - * "License"). You may not use this file except in compliance with the
  116.16 - * License. You can obtain a copy of the License at
  116.17 - * http://www.netbeans.org/cddl-gplv2.html
  116.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  116.19 - * specific language governing permissions and limitations under the
  116.20 - * License.  When distributing the software, include this License Header
  116.21 - * Notice in each file and include the License file at
  116.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  116.23 - * particular file as subject to the "Classpath" exception as provided
  116.24 - * by Oracle in the GPL Version 2 section of the License file that
  116.25 - * accompanied this code. If applicable, add the following below the
  116.26 - * License Header, with the fields enclosed by brackets [] replaced by
  116.27 - * your own identifying information:
  116.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  116.29 - *
  116.30 - * Contributor(s):
  116.31 - *
  116.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  116.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  116.34 - *
  116.35 - * If you wish your version of this file to be governed by only the CDDL
  116.36 - * or only the GPL Version 2, indicate your decision by adding
  116.37 - * "[Contributor] elects to include this software in this distribution
  116.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  116.39 - * single choice of license, a recipient has the option to distribute
  116.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  116.41 - * to extend the choice of license to its licensees as provided above.
  116.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  116.43 - * Version 2 license, then the option applies only if the new code is
  116.44 - * made subject to such option by the copyright holder.
  116.45 - */
  116.46 -package org.apidesign.html.archetype.test;
  116.47 -
  116.48 -import java.io.File;
  116.49 -import java.util.Properties;
  116.50 -import org.apache.maven.it.Verifier;
  116.51 -import org.testng.annotations.Test;
  116.52 -import static org.testng.Assert.*;
  116.53 -
  116.54 -/**
  116.55 - *
  116.56 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  116.57 - */
  116.58 -public class VerifyArchetypeTest {
  116.59 -    @Test public void projectCompiles() throws Exception {
  116.60 -        final File dir = new File("target/tests/fxcompile/").getAbsoluteFile();
  116.61 -        generateFromArchetype(dir);
  116.62 -        
  116.63 -        File created = new File(dir, "o-a-test");
  116.64 -        assertTrue(created.isDirectory(), "Project created");
  116.65 -        assertTrue(new File(created, "pom.xml").isFile(), "Pom file is in there");
  116.66 -        
  116.67 -        Verifier v = new Verifier(created.getAbsolutePath());
  116.68 -        v.executeGoal("verify");
  116.69 -        
  116.70 -        v.verifyErrorFreeLog();
  116.71 -        
  116.72 -        for (String l : v.loadFile(v.getBasedir(), v.getLogFileName(), false)) {
  116.73 -            if (l.contains("j2js")) {
  116.74 -                fail("No pre-compilaton:\n" + l);
  116.75 -            }
  116.76 -        }
  116.77 -        
  116.78 -        v.verifyTextInLog("fxcompile/o-a-test/target/o-a-test-1.0-SNAPSHOT-html.java.net.zip");
  116.79 -    }
  116.80 -    
  116.81 -    private Verifier generateFromArchetype(final File dir, String... params) throws Exception {
  116.82 -        Verifier v = new Verifier(dir.getAbsolutePath());
  116.83 -        v.setAutoclean(false);
  116.84 -        v.setLogFileName("generate.log");
  116.85 -        v.deleteDirectory("");
  116.86 -        dir.mkdirs();
  116.87 -        Properties sysProp = v.getSystemProperties();
  116.88 -        sysProp.put("groupId", "org.apidesign.test");
  116.89 -        sysProp.put("artifactId", "o-a-test");
  116.90 -        sysProp.put("package", "org.apidesign.test.oat");
  116.91 -        sysProp.put("archetypeGroupId", "org.apidesign.html");
  116.92 -        sysProp.put("archetypeArtifactId", "knockout4j-archetype");
  116.93 -        sysProp.put("archetypeVersion", ArchetypeVersionTest.findCurrentVersion());
  116.94 -        
  116.95 -        for (String p : params) {
  116.96 -            v.addCliOption(p);
  116.97 -        }
  116.98 -        v.executeGoal("archetype:generate");
  116.99 -        v.verifyErrorFreeLog();
 116.100 -        return v;
 116.101 -    }
 116.102 -}
   117.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   117.2 +++ b/ko-archetype-test/src/test/java/org/netbeans/html/archetype/test/ArchetypeVersionTest.java	Mon Dec 16 16:59:43 2013 +0100
   117.3 @@ -0,0 +1,128 @@
   117.4 +/**
   117.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   117.6 + *
   117.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   117.8 + *
   117.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  117.10 + * Other names may be trademarks of their respective owners.
  117.11 + *
  117.12 + * The contents of this file are subject to the terms of either the GNU
  117.13 + * General Public License Version 2 only ("GPL") or the Common
  117.14 + * Development and Distribution License("CDDL") (collectively, the
  117.15 + * "License"). You may not use this file except in compliance with the
  117.16 + * License. You can obtain a copy of the License at
  117.17 + * http://www.netbeans.org/cddl-gplv2.html
  117.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  117.19 + * specific language governing permissions and limitations under the
  117.20 + * License.  When distributing the software, include this License Header
  117.21 + * Notice in each file and include the License file at
  117.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  117.23 + * particular file as subject to the "Classpath" exception as provided
  117.24 + * by Oracle in the GPL Version 2 section of the License file that
  117.25 + * accompanied this code. If applicable, add the following below the
  117.26 + * License Header, with the fields enclosed by brackets [] replaced by
  117.27 + * your own identifying information:
  117.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  117.29 + *
  117.30 + * Contributor(s):
  117.31 + *
  117.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  117.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  117.34 + *
  117.35 + * If you wish your version of this file to be governed by only the CDDL
  117.36 + * or only the GPL Version 2, indicate your decision by adding
  117.37 + * "[Contributor] elects to include this software in this distribution
  117.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  117.39 + * single choice of license, a recipient has the option to distribute
  117.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  117.41 + * to extend the choice of license to its licensees as provided above.
  117.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  117.43 + * Version 2 license, then the option applies only if the new code is
  117.44 + * made subject to such option by the copyright holder.
  117.45 + */
  117.46 +package org.netbeans.html.archetype.test;
  117.47 +
  117.48 +import java.io.IOException;
  117.49 +import java.net.URL;
  117.50 +import javax.xml.XMLConstants;
  117.51 +import javax.xml.parsers.DocumentBuilderFactory;
  117.52 +import javax.xml.parsers.ParserConfigurationException;
  117.53 +import javax.xml.xpath.XPathConstants;
  117.54 +import javax.xml.xpath.XPathExpression;
  117.55 +import javax.xml.xpath.XPathExpressionException;
  117.56 +import javax.xml.xpath.XPathFactory;
  117.57 +import javax.xml.xpath.XPathFactoryConfigurationException;
  117.58 +import org.testng.annotations.Test;
  117.59 +import static org.testng.Assert.*;
  117.60 +import org.testng.annotations.BeforeClass;
  117.61 +import org.w3c.dom.Document;
  117.62 +import org.w3c.dom.NodeList;
  117.63 +import org.xml.sax.SAXException;
  117.64 +
  117.65 +/**
  117.66 + *
  117.67 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  117.68 + */
  117.69 +public class ArchetypeVersionTest {
  117.70 +    private String version;
  117.71 +    
  117.72 +    public ArchetypeVersionTest() {
  117.73 +    }
  117.74 +    
  117.75 +    @BeforeClass public void readCurrentVersion() throws Exception {
  117.76 +        version = findCurrentVersion();
  117.77 +        assertFalse(version.isEmpty(), "There should be some version string");
  117.78 +    }
  117.79 +    
  117.80 +
  117.81 +    @Test public void testComparePomDepsVersions() throws Exception {
  117.82 +        final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
  117.83 +        URL r = l.getResource("archetype-resources/pom.xml");
  117.84 +        assertNotNull(r, "Archetype pom found");
  117.85 +        
  117.86 +        final XPathFactory fact = XPathFactory.newInstance();
  117.87 +        XPathExpression xp2 = fact.newXPath().compile(
  117.88 +            "//properties/net.java.html.version/text()"
  117.89 +        );
  117.90 +        
  117.91 +        Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream());
  117.92 +        String arch = (String) xp2.evaluate(dom, XPathConstants.STRING);
  117.93 +
  117.94 +        assertEquals(arch, version, "net.java.html.json dependency needs to be on latest version");
  117.95 +    }
  117.96 +    
  117.97 +    @Test public void testNbActions() throws Exception {
  117.98 +        final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
  117.99 +        URL r = l.getResource("archetype-resources/nbactions.xml");
 117.100 +        assertNotNull(r, "Archetype nb file found");
 117.101 +        
 117.102 +        final XPathFactory fact = XPathFactory.newInstance();
 117.103 +        XPathExpression xp2 = fact.newXPath().compile(
 117.104 +            "//goal/text()"
 117.105 +        );
 117.106 +        
 117.107 +        Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream());
 117.108 +        NodeList goals = (NodeList) xp2.evaluate(dom, XPathConstants.NODESET);
 117.109 +        
 117.110 +        for (int i = 0; i < goals.getLength(); i++) {
 117.111 +            String s = goals.item(i).getTextContent();
 117.112 +            if (s.contains("apidesign")) {
 117.113 +                assertFalse(s.matches(".*apidesign.*[0-9].*"), "No numbers: " + s);
 117.114 +            }
 117.115 +        }
 117.116 +    }
 117.117 +
 117.118 +    static String findCurrentVersion() throws XPathExpressionException, IOException, ParserConfigurationException, SAXException, XPathFactoryConfigurationException {
 117.119 +        final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
 117.120 +        URL u = l.getResource("META-INF/maven/org.netbeans.html/knockout4j-archetype/pom.xml");
 117.121 +        assertNotNull(u, "Own pom found: " + System.getProperty("java.class.path"));
 117.122 +
 117.123 +        final XPathFactory fact = XPathFactory.newInstance();
 117.124 +        fact.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
 117.125 +
 117.126 +        XPathExpression xp = fact.newXPath().compile("project/version/text()");
 117.127 +        
 117.128 +        Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(u.openStream());
 117.129 +        return xp.evaluate(dom);
 117.130 +    }
 117.131 +}
   118.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   118.2 +++ b/ko-archetype-test/src/test/java/org/netbeans/html/archetype/test/VerifyArchetypeTest.java	Mon Dec 16 16:59:43 2013 +0100
   118.3 @@ -0,0 +1,99 @@
   118.4 +/**
   118.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   118.6 + *
   118.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   118.8 + *
   118.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  118.10 + * Other names may be trademarks of their respective owners.
  118.11 + *
  118.12 + * The contents of this file are subject to the terms of either the GNU
  118.13 + * General Public License Version 2 only ("GPL") or the Common
  118.14 + * Development and Distribution License("CDDL") (collectively, the
  118.15 + * "License"). You may not use this file except in compliance with the
  118.16 + * License. You can obtain a copy of the License at
  118.17 + * http://www.netbeans.org/cddl-gplv2.html
  118.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  118.19 + * specific language governing permissions and limitations under the
  118.20 + * License.  When distributing the software, include this License Header
  118.21 + * Notice in each file and include the License file at
  118.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  118.23 + * particular file as subject to the "Classpath" exception as provided
  118.24 + * by Oracle in the GPL Version 2 section of the License file that
  118.25 + * accompanied this code. If applicable, add the following below the
  118.26 + * License Header, with the fields enclosed by brackets [] replaced by
  118.27 + * your own identifying information:
  118.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  118.29 + *
  118.30 + * Contributor(s):
  118.31 + *
  118.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  118.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  118.34 + *
  118.35 + * If you wish your version of this file to be governed by only the CDDL
  118.36 + * or only the GPL Version 2, indicate your decision by adding
  118.37 + * "[Contributor] elects to include this software in this distribution
  118.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  118.39 + * single choice of license, a recipient has the option to distribute
  118.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  118.41 + * to extend the choice of license to its licensees as provided above.
  118.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  118.43 + * Version 2 license, then the option applies only if the new code is
  118.44 + * made subject to such option by the copyright holder.
  118.45 + */
  118.46 +package org.netbeans.html.archetype.test;
  118.47 +
  118.48 +import java.io.File;
  118.49 +import java.util.Properties;
  118.50 +import org.apache.maven.it.Verifier;
  118.51 +import org.testng.annotations.Test;
  118.52 +import static org.testng.Assert.*;
  118.53 +
  118.54 +/**
  118.55 + *
  118.56 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  118.57 + */
  118.58 +public class VerifyArchetypeTest {
  118.59 +    @Test public void projectCompiles() throws Exception {
  118.60 +        final File dir = new File("target/tests/fxcompile/").getAbsoluteFile();
  118.61 +        generateFromArchetype(dir);
  118.62 +        
  118.63 +        File created = new File(dir, "o-a-test");
  118.64 +        assertTrue(created.isDirectory(), "Project created");
  118.65 +        assertTrue(new File(created, "pom.xml").isFile(), "Pom file is in there");
  118.66 +        
  118.67 +        Verifier v = new Verifier(created.getAbsolutePath());
  118.68 +        v.executeGoal("verify");
  118.69 +        
  118.70 +        v.verifyErrorFreeLog();
  118.71 +        
  118.72 +        for (String l : v.loadFile(v.getBasedir(), v.getLogFileName(), false)) {
  118.73 +            if (l.contains("j2js")) {
  118.74 +                fail("No pre-compilaton:\n" + l);
  118.75 +            }
  118.76 +        }
  118.77 +        
  118.78 +        v.verifyTextInLog("fxcompile/o-a-test/target/o-a-test-1.0-SNAPSHOT-html.java.net.zip");
  118.79 +    }
  118.80 +    
  118.81 +    private Verifier generateFromArchetype(final File dir, String... params) throws Exception {
  118.82 +        Verifier v = new Verifier(dir.getAbsolutePath());
  118.83 +        v.setAutoclean(false);
  118.84 +        v.setLogFileName("generate.log");
  118.85 +        v.deleteDirectory("");
  118.86 +        dir.mkdirs();
  118.87 +        Properties sysProp = v.getSystemProperties();
  118.88 +        sysProp.put("groupId", "org.apidesign.test");
  118.89 +        sysProp.put("artifactId", "o-a-test");
  118.90 +        sysProp.put("package", "org.apidesign.test.oat");
  118.91 +        sysProp.put("archetypeGroupId", "org.apidesign.html");
  118.92 +        sysProp.put("archetypeArtifactId", "knockout4j-archetype");
  118.93 +        sysProp.put("archetypeVersion", ArchetypeVersionTest.findCurrentVersion());
  118.94 +        
  118.95 +        for (String p : params) {
  118.96 +            v.addCliOption(p);
  118.97 +        }
  118.98 +        v.executeGoal("archetype:generate");
  118.99 +        v.verifyErrorFreeLog();
 118.100 +        return v;
 118.101 +    }
 118.102 +}
   119.1 --- a/ko-archetype/src/main/java/org/apidesign/html/archetype/package-info.java	Mon Dec 16 15:48:09 2013 +0100
   119.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   119.3 @@ -1,43 +0,0 @@
   119.4 -/**
   119.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   119.6 - *
   119.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   119.8 - *
   119.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  119.10 - * Other names may be trademarks of their respective owners.
  119.11 - *
  119.12 - * The contents of this file are subject to the terms of either the GNU
  119.13 - * General Public License Version 2 only ("GPL") or the Common
  119.14 - * Development and Distribution License("CDDL") (collectively, the
  119.15 - * "License"). You may not use this file except in compliance with the
  119.16 - * License. You can obtain a copy of the License at
  119.17 - * http://www.netbeans.org/cddl-gplv2.html
  119.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  119.19 - * specific language governing permissions and limitations under the
  119.20 - * License.  When distributing the software, include this License Header
  119.21 - * Notice in each file and include the License file at
  119.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  119.23 - * particular file as subject to the "Classpath" exception as provided
  119.24 - * by Oracle in the GPL Version 2 section of the License file that
  119.25 - * accompanied this code. If applicable, add the following below the
  119.26 - * License Header, with the fields enclosed by brackets [] replaced by
  119.27 - * your own identifying information:
  119.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  119.29 - *
  119.30 - * Contributor(s):
  119.31 - *
  119.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  119.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  119.34 - *
  119.35 - * If you wish your version of this file to be governed by only the CDDL
  119.36 - * or only the GPL Version 2, indicate your decision by adding
  119.37 - * "[Contributor] elects to include this software in this distribution
  119.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  119.39 - * single choice of license, a recipient has the option to distribute
  119.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  119.41 - * to extend the choice of license to its licensees as provided above.
  119.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  119.43 - * Version 2 license, then the option applies only if the new code is
  119.44 - * made subject to such option by the copyright holder.
  119.45 - */
  119.46 -package org.apidesign.html.archetype;
   120.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   120.2 +++ b/ko-archetype/src/main/java/org/netbeans/html/archetype/package-info.java	Mon Dec 16 16:59:43 2013 +0100
   120.3 @@ -0,0 +1,43 @@
   120.4 +/**
   120.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   120.6 + *
   120.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   120.8 + *
   120.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  120.10 + * Other names may be trademarks of their respective owners.
  120.11 + *
  120.12 + * The contents of this file are subject to the terms of either the GNU
  120.13 + * General Public License Version 2 only ("GPL") or the Common
  120.14 + * Development and Distribution License("CDDL") (collectively, the
  120.15 + * "License"). You may not use this file except in compliance with the
  120.16 + * License. You can obtain a copy of the License at
  120.17 + * http://www.netbeans.org/cddl-gplv2.html
  120.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  120.19 + * specific language governing permissions and limitations under the
  120.20 + * License.  When distributing the software, include this License Header
  120.21 + * Notice in each file and include the License file at
  120.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  120.23 + * particular file as subject to the "Classpath" exception as provided
  120.24 + * by Oracle in the GPL Version 2 section of the License file that
  120.25 + * accompanied this code. If applicable, add the following below the
  120.26 + * License Header, with the fields enclosed by brackets [] replaced by
  120.27 + * your own identifying information:
  120.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  120.29 + *
  120.30 + * Contributor(s):
  120.31 + *
  120.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  120.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  120.34 + *
  120.35 + * If you wish your version of this file to be governed by only the CDDL
  120.36 + * or only the GPL Version 2, indicate your decision by adding
  120.37 + * "[Contributor] elects to include this software in this distribution
  120.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  120.39 + * single choice of license, a recipient has the option to distribute
  120.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  120.41 + * to extend the choice of license to its licensees as provided above.
  120.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  120.43 + * Version 2 license, then the option applies only if the new code is
  120.44 + * made subject to such option by the copyright holder.
  120.45 + */
  120.46 +package org.netbeans.html.archetype;
   121.1 --- a/ko-fx/src/main/java/org/apidesign/html/kofx/Console.java	Mon Dec 16 15:48:09 2013 +0100
   121.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   121.3 @@ -1,81 +0,0 @@
   121.4 -/**
   121.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   121.6 - *
   121.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   121.8 - *
   121.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  121.10 - * Other names may be trademarks of their respective owners.
  121.11 - *
  121.12 - * The contents of this file are subject to the terms of either the GNU
  121.13 - * General Public License Version 2 only ("GPL") or the Common
  121.14 - * Development and Distribution License("CDDL") (collectively, the
  121.15 - * "License"). You may not use this file except in compliance with the
  121.16 - * License. You can obtain a copy of the License at
  121.17 - * http://www.netbeans.org/cddl-gplv2.html
  121.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  121.19 - * specific language governing permissions and limitations under the
  121.20 - * License.  When distributing the software, include this License Header
  121.21 - * Notice in each file and include the License file at
  121.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  121.23 - * particular file as subject to the "Classpath" exception as provided
  121.24 - * by Oracle in the GPL Version 2 section of the License file that
  121.25 - * accompanied this code. If applicable, add the following below the
  121.26 - * License Header, with the fields enclosed by brackets [] replaced by
  121.27 - * your own identifying information:
  121.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  121.29 - *
  121.30 - * Contributor(s):
  121.31 - *
  121.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  121.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  121.34 - *
  121.35 - * If you wish your version of this file to be governed by only the CDDL
  121.36 - * or only the GPL Version 2, indicate your decision by adding
  121.37 - * "[Contributor] elects to include this software in this distribution
  121.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  121.39 - * single choice of license, a recipient has the option to distribute
  121.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  121.41 - * to extend the choice of license to its licensees as provided above.
  121.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  121.43 - * Version 2 license, then the option applies only if the new code is
  121.44 - * made subject to such option by the copyright holder.
  121.45 - */
  121.46 -package org.apidesign.html.kofx;
  121.47 -
  121.48 -import java.util.logging.Level;
  121.49 -import java.util.logging.Logger;
  121.50 -import net.java.html.js.JavaScriptBody;
  121.51 -
  121.52 -/** This is an implementation package - just
  121.53 - * include its JAR on classpath and use official {@link Context} API
  121.54 - * to access the functionality.
  121.55 - * <p>
  121.56 - * Redirects JavaScript's messages to Java's {@link Logger}.
  121.57 - *
  121.58 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  121.59 - */
  121.60 -final class Console {
  121.61 -    private static final Logger LOG = Logger.getLogger(Console.class.getName());
  121.62 -    
  121.63 -    private Console() {
  121.64 -    }
  121.65 -
  121.66 -    static void register() {
  121.67 -        registerImpl("log", Level.INFO);
  121.68 -        registerImpl("info", Level.INFO);
  121.69 -        registerImpl("warn", Level.WARNING);
  121.70 -        registerImpl("error", Level.SEVERE);
  121.71 -    }
  121.72 -    
  121.73 -    @JavaScriptBody(args = { "attr", "l" }, 
  121.74 -        javacall = true, body = 
  121.75 -        "  window.console[attr] = function(m) {\n"
  121.76 -      + "    @org.apidesign.html.kofx.Console::log(Ljava/util/logging/Level;Ljava/lang/String;)(l, m);\n"
  121.77 -      + "  };\n"
  121.78 -    )
  121.79 -    private static native void registerImpl(String attr, Level l);
  121.80 -    
  121.81 -    static void log(Level l, String msg) {
  121.82 -        LOG.log(l, msg);
  121.83 -    }
  121.84 -}
   122.1 --- a/ko-fx/src/main/java/org/apidesign/html/kofx/FXContext.java	Mon Dec 16 15:48:09 2013 +0100
   122.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   122.3 @@ -1,222 +0,0 @@
   122.4 -/**
   122.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   122.6 - *
   122.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   122.8 - *
   122.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  122.10 - * Other names may be trademarks of their respective owners.
  122.11 - *
  122.12 - * The contents of this file are subject to the terms of either the GNU
  122.13 - * General Public License Version 2 only ("GPL") or the Common
  122.14 - * Development and Distribution License("CDDL") (collectively, the
  122.15 - * "License"). You may not use this file except in compliance with the
  122.16 - * License. You can obtain a copy of the License at
  122.17 - * http://www.netbeans.org/cddl-gplv2.html
  122.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  122.19 - * specific language governing permissions and limitations under the
  122.20 - * License.  When distributing the software, include this License Header
  122.21 - * Notice in each file and include the License file at
  122.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  122.23 - * particular file as subject to the "Classpath" exception as provided
  122.24 - * by Oracle in the GPL Version 2 section of the License file that
  122.25 - * accompanied this code. If applicable, add the following below the
  122.26 - * License Header, with the fields enclosed by brackets [] replaced by
  122.27 - * your own identifying information:
  122.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  122.29 - *
  122.30 - * Contributor(s):
  122.31 - *
  122.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  122.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  122.34 - *
  122.35 - * If you wish your version of this file to be governed by only the CDDL
  122.36 - * or only the GPL Version 2, indicate your decision by adding
  122.37 - * "[Contributor] elects to include this software in this distribution
  122.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  122.39 - * single choice of license, a recipient has the option to distribute
  122.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  122.41 - * to extend the choice of license to its licensees as provided above.
  122.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  122.43 - * Version 2 license, then the option applies only if the new code is
  122.44 - * made subject to such option by the copyright holder.
  122.45 - */
  122.46 -package org.apidesign.html.kofx;
  122.47 -
  122.48 -import java.io.Closeable;
  122.49 -import java.io.IOException;
  122.50 -import java.io.InputStream;
  122.51 -import java.util.ServiceLoader;
  122.52 -import java.util.logging.Logger;
  122.53 -import javafx.application.Platform;
  122.54 -import net.java.html.js.JavaScriptBody;
  122.55 -import netscape.javascript.JSObject;
  122.56 -import org.apidesign.html.boot.spi.Fn;
  122.57 -import org.apidesign.html.context.spi.Contexts;
  122.58 -import org.apidesign.html.json.spi.FunctionBinding;
  122.59 -import org.apidesign.html.json.spi.JSONCall;
  122.60 -import org.apidesign.html.json.spi.PropertyBinding;
  122.61 -import org.apidesign.html.json.spi.Technology;
  122.62 -import org.apidesign.html.json.spi.Transfer;
  122.63 -import org.apidesign.html.json.spi.WSTransfer;
  122.64 -import org.openide.util.lookup.ServiceProvider;
  122.65 -
  122.66 -/** This is an implementation package - just
  122.67 - * include its JAR on classpath and use official {@link Context} API
  122.68 - * to access the functionality.
  122.69 - * <p>
  122.70 - * Registers {@link ContextProvider}, so {@link ServiceLoader} can find it.
  122.71 - *
  122.72 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  122.73 - */
  122.74 -public final class FXContext
  122.75 -implements Technology.BatchInit<JSObject>, Transfer, WSTransfer<LoadWS> {
  122.76 -    static final Logger LOG = Logger.getLogger(FXContext.class.getName());
  122.77 -    private static Boolean javaScriptEnabled;
  122.78 -    private final Fn.Presenter browserContext;
  122.79 -
  122.80 -    public FXContext(Fn.Presenter browserContext) {
  122.81 -        this.browserContext = browserContext;
  122.82 -    }
  122.83 -    
  122.84 -    @JavaScriptBody(args = {}, body = "return true;")
  122.85 -    private static boolean isJavaScriptEnabledJs() {
  122.86 -        return false;
  122.87 -    }
  122.88 -    
  122.89 -    static boolean isJavaScriptEnabled() {
  122.90 -        if (javaScriptEnabled != null) {
  122.91 -            return javaScriptEnabled;
  122.92 -        }
  122.93 -        return javaScriptEnabled = isJavaScriptEnabledJs();
  122.94 -    }
  122.95 -
  122.96 -    final boolean areWebSocketsSupported() {
  122.97 -        return LoadWS.isSupported();
  122.98 -    }
  122.99 -
 122.100 -
 122.101 -    @Override
 122.102 -    public JSObject wrapModel(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
 122.103 -        String[] propNames = new String[propArr.length];
 122.104 -        boolean[] propReadOnly = new boolean[propArr.length];
 122.105 -        Object[] propValues = new Object[propArr.length];
 122.106 -        for (int i = 0; i < propNames.length; i++) {
 122.107 -            propNames[i] = propArr[i].getPropertyName();
 122.108 -            propReadOnly[i] = propArr[i].isReadOnly();
 122.109 -            propValues[i] = propArr[i].getValue();
 122.110 -        }
 122.111 -        String[] funcNames = new String[funcArr.length];
 122.112 -        for (int i = 0; i < funcNames.length; i++) {
 122.113 -            funcNames[i] = funcArr[i].getFunctionName();
 122.114 -        }
 122.115 -        
 122.116 -        return Knockout.wrapModel(model, 
 122.117 -            propNames, propReadOnly, Knockout.toArray(propValues), propArr, 
 122.118 -            funcNames, funcArr
 122.119 -        );
 122.120 -    }
 122.121 -    
 122.122 -    @Override
 122.123 -    public JSObject wrapModel(Object model) {
 122.124 -        throw new UnsupportedOperationException();
 122.125 -    }
 122.126 -
 122.127 -    @Override
 122.128 -    public void bind(PropertyBinding b, Object model, JSObject data) {
 122.129 -        throw new UnsupportedOperationException();
 122.130 -    }
 122.131 -
 122.132 -    @Override
 122.133 -    public void valueHasMutated(JSObject data, String propertyName) {
 122.134 -        Knockout.valueHasMutated(data, propertyName);
 122.135 -    }
 122.136 -
 122.137 -    @Override
 122.138 -    public void expose(FunctionBinding fb, Object model, JSObject d) {
 122.139 -        throw new UnsupportedOperationException();
 122.140 -    }
 122.141 -
 122.142 -    @Override
 122.143 -    public void applyBindings(JSObject data) {
 122.144 -        Knockout.applyBindings(data);
 122.145 -    }
 122.146 -
 122.147 -    @Override
 122.148 -    public Object wrapArray(Object[] arr) {
 122.149 -        return Knockout.toArray(arr);
 122.150 -    }
 122.151 -
 122.152 -    @Override
 122.153 -    public void extract(Object obj, String[] props, Object[] values) {
 122.154 -        LoadJSON.extractJSON(obj, props, values);
 122.155 -    }
 122.156 -
 122.157 -    @Override
 122.158 -    public void loadJSON(final JSONCall call) {
 122.159 -        LoadJSON.loadJSON(call);
 122.160 -    }
 122.161 -
 122.162 -    @Override
 122.163 -    public <M> M toModel(Class<M> modelClass, Object data) {
 122.164 -        if (data instanceof JSObject) {
 122.165 -            data = ((JSObject)data).getMember("ko-fx.model"); // NOI18N
 122.166 -        }
 122.167 -        return modelClass.cast(data);
 122.168 -    }
 122.169 -
 122.170 -    @Override
 122.171 -    public Object toJSON(InputStream is) throws IOException {
 122.172 -        return LoadJSON.parse(is);
 122.173 -    }
 122.174 -
 122.175 -    @Override
 122.176 -    public void runSafe(final Runnable r) {
 122.177 -        class Wrap implements Runnable {
 122.178 -            @Override public void run() {
 122.179 -                try (Closeable c = Fn.activate(browserContext)) {
 122.180 -                    r.run();
 122.181 -                } catch (IOException ex) {
 122.182 -                    // cannot be thrown
 122.183 -                }
 122.184 -            }
 122.185 -        }
 122.186 -        Wrap w = new Wrap();
 122.187 -        
 122.188 -        if (Platform.isFxApplicationThread()) {
 122.189 -            w.run();
 122.190 -        } else {
 122.191 -            Platform.runLater(w);
 122.192 -        }
 122.193 -    }
 122.194 -
 122.195 -    @Override
 122.196 -    public LoadWS open(String url, JSONCall onReply) {
 122.197 -        return new LoadWS(onReply, url);
 122.198 -    }
 122.199 -
 122.200 -    @Override
 122.201 -    public void send(LoadWS socket, JSONCall data) {
 122.202 -        socket.send(data);
 122.203 -    }
 122.204 -
 122.205 -    @Override
 122.206 -    public void close(LoadWS socket) {
 122.207 -        socket.close();
 122.208 -    }
 122.209 -    
 122.210 -    @ServiceProvider(service = Contexts.Provider.class)
 122.211 -    public static final class Prvdr implements Contexts.Provider {
 122.212 -        @Override
 122.213 -        public void fillContext(Contexts.Builder context, Class<?> requestor) {
 122.214 -            if (isJavaScriptEnabled()) {
 122.215 -                FXContext c = new FXContext(Fn.activePresenter());
 122.216 -                
 122.217 -                context.register(Technology.class, c, 100);
 122.218 -                context.register(Transfer.class, c, 100);
 122.219 -                if (c.areWebSocketsSupported()) {
 122.220 -                    context.register(WSTransfer.class, c, 100);
 122.221 -                }
 122.222 -            }
 122.223 -        }
 122.224 -    }
 122.225 -}
   123.1 --- a/ko-fx/src/main/java/org/apidesign/html/kofx/Knockout.java	Mon Dec 16 15:48:09 2013 +0100
   123.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   123.3 @@ -1,145 +0,0 @@
   123.4 -/**
   123.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   123.6 - *
   123.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   123.8 - *
   123.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  123.10 - * Other names may be trademarks of their respective owners.
  123.11 - *
  123.12 - * The contents of this file are subject to the terms of either the GNU
  123.13 - * General Public License Version 2 only ("GPL") or the Common
  123.14 - * Development and Distribution License("CDDL") (collectively, the
  123.15 - * "License"). You may not use this file except in compliance with the
  123.16 - * License. You can obtain a copy of the License at
  123.17 - * http://www.netbeans.org/cddl-gplv2.html
  123.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  123.19 - * specific language governing permissions and limitations under the
  123.20 - * License.  When distributing the software, include this License Header
  123.21 - * Notice in each file and include the License file at
  123.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  123.23 - * particular file as subject to the "Classpath" exception as provided
  123.24 - * by Oracle in the GPL Version 2 section of the License file that
  123.25 - * accompanied this code. If applicable, add the following below the
  123.26 - * License Header, with the fields enclosed by brackets [] replaced by
  123.27 - * your own identifying information:
  123.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  123.29 - *
  123.30 - * Contributor(s):
  123.31 - *
  123.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  123.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  123.34 - *
  123.35 - * If you wish your version of this file to be governed by only the CDDL
  123.36 - * or only the GPL Version 2, indicate your decision by adding
  123.37 - * "[Contributor] elects to include this software in this distribution
  123.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  123.39 - * single choice of license, a recipient has the option to distribute
  123.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  123.41 - * to extend the choice of license to its licensees as provided above.
  123.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  123.43 - * Version 2 license, then the option applies only if the new code is
  123.44 - * made subject to such option by the copyright holder.
  123.45 - */
  123.46 -package org.apidesign.html.kofx;
  123.47 -
  123.48 -import net.java.html.js.JavaScriptBody;
  123.49 -import net.java.html.js.JavaScriptResource;
  123.50 -import net.java.html.json.Model;
  123.51 -import netscape.javascript.JSObject;
  123.52 -import org.apidesign.html.json.spi.FunctionBinding;
  123.53 -import org.apidesign.html.json.spi.PropertyBinding;
  123.54 -
  123.55 -/** This is an implementation package - just
  123.56 - * include its JAR on classpath and use official {@link Context} API
  123.57 - * to access the functionality.
  123.58 - * <p>
  123.59 - * Provides binding between {@link Model models} and knockout.js running
  123.60 - * inside a JavaFX WebView. 
  123.61 - *
  123.62 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  123.63 - */
  123.64 -@JavaScriptResource("knockout-2.2.1.js")
  123.65 -final class Knockout {
  123.66 -    static final JSObject KObject;
  123.67 -    static {
  123.68 -        Console.register();
  123.69 -        KObject = (JSObject) kObj();
  123.70 -    }
  123.71 -
  123.72 -    static Object toArray(Object[] arr) {
  123.73 -        return KObject.call("array", arr);
  123.74 -    }
  123.75 -    
  123.76 -    @JavaScriptBody(args = { "model", "prop" }, body =
  123.77 -          "if (model) {\n"
  123.78 -        + "  var koProp = model[prop];\n"
  123.79 -        + "  if (koProp && koProp['valueHasMutated']) {\n"
  123.80 -        + "    koProp['valueHasMutated']();\n"
  123.81 -        + "  }\n"
  123.82 -        + "}\n"
  123.83 -    )
  123.84 -    public native static void valueHasMutated(JSObject model, String prop);
  123.85 -
  123.86 -    @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);")
  123.87 -    native static void applyBindings(Object bindings);
  123.88 -    
  123.89 -    @JavaScriptBody(args = {}, body =
  123.90 -              "  var k = {};"
  123.91 -            + "  k.array= function() {"
  123.92 -            + "    return Array.prototype.slice.call(arguments);"
  123.93 -            + "  };"
  123.94 -            + "  return k;"
  123.95 -    )
  123.96 -    private static native Object kObj();
  123.97 -        
  123.98 -        
  123.99 -    @JavaScriptBody(
 123.100 -        javacall = true,
 123.101 -        args = {"model", "propNames", "propReadOnly", "propValues", "propArr", "funcNames", "funcArr"},
 123.102 -        body
 123.103 -        = "var ret = {};\n"
 123.104 -        + "ret['ko-fx.model'] = model;\n"
 123.105 -        + "function koComputed(name, readOnly, value, prop) {\n"
 123.106 -        + "  function realGetter() {\n"
 123.107 -        + "    try {"
 123.108 -        + "      var v = prop.@org.apidesign.html.json.spi.PropertyBinding::getValue()();"
 123.109 -        + "      return v;"
 123.110 -        + "    } catch (e) {"
 123.111 -        + "      alert(\"Cannot call getValue on \" + model + \" prop: \" + name + \" error: \" + e);"
 123.112 -        + "    }"
 123.113 -        + "  }\n"
 123.114 -        + "  var activeGetter = function() { return value; };\n"
 123.115 -        + "  var bnd = {"
 123.116 -        + "    read: function() {"
 123.117 -        + "      var r = activeGetter();"
 123.118 -        + "      activeGetter = realGetter;"
 123.119 -        + "      return r;"
 123.120 -        + "    },"
 123.121 -        + "    owner: ret\n"
 123.122 -        + "  };\n"
 123.123 -        + "  if (!readOnly) {\n"
 123.124 -        + "    bnd.write = function(val) {\n"
 123.125 -        + "      prop.@org.apidesign.html.json.spi.PropertyBinding::setValue(Ljava/lang/Object;)(val);\n"
 123.126 -        + "    };"
 123.127 -        + "  };"
 123.128 -        + "  ret[name] = ko.computed(bnd);"
 123.129 -        + "}\n"
 123.130 -        + "for (var i = 0; i < propNames.length; i++) {\n"
 123.131 -        + "  koComputed(propNames[i], propReadOnly[i], propValues[i], propArr[i]);\n"
 123.132 -        + "}\n"
 123.133 -        + "function koExpose(name, func) {\n"
 123.134 -        + "  ret[name] = function(data, ev) {\n"
 123.135 -        + "    func.@org.apidesign.html.json.spi.FunctionBinding::call(Ljava/lang/Object;Ljava/lang/Object;)(data, ev);\n"
 123.136 -        + "  };\n"
 123.137 -        + "}\n"
 123.138 -        + "for (var i = 0; i < funcNames.length; i++) {\n"
 123.139 -        + "  koExpose(funcNames[i], funcArr[i]);\n"
 123.140 -        + "}\n"
 123.141 -        + "return ret;\n"
 123.142 -        )
 123.143 -    static native JSObject wrapModel(
 123.144 -        Object model,
 123.145 -        String[] propNames, boolean[] propReadOnly, Object propValues, PropertyBinding[] propArr,
 123.146 -        String[] funcNames, FunctionBinding[] funcArr
 123.147 -    );
 123.148 -}
   124.1 --- a/ko-fx/src/main/java/org/apidesign/html/kofx/LoadJSON.java	Mon Dec 16 15:48:09 2013 +0100
   124.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   124.3 @@ -1,267 +0,0 @@
   124.4 -/**
   124.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   124.6 - *
   124.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   124.8 - *
   124.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  124.10 - * Other names may be trademarks of their respective owners.
  124.11 - *
  124.12 - * The contents of this file are subject to the terms of either the GNU
  124.13 - * General Public License Version 2 only ("GPL") or the Common
  124.14 - * Development and Distribution License("CDDL") (collectively, the
  124.15 - * "License"). You may not use this file except in compliance with the
  124.16 - * License. You can obtain a copy of the License at
  124.17 - * http://www.netbeans.org/cddl-gplv2.html
  124.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  124.19 - * specific language governing permissions and limitations under the
  124.20 - * License.  When distributing the software, include this License Header
  124.21 - * Notice in each file and include the License file at
  124.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  124.23 - * particular file as subject to the "Classpath" exception as provided
  124.24 - * by Oracle in the GPL Version 2 section of the License file that
  124.25 - * accompanied this code. If applicable, add the following below the
  124.26 - * License Header, with the fields enclosed by brackets [] replaced by
  124.27 - * your own identifying information:
  124.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  124.29 - *
  124.30 - * Contributor(s):
  124.31 - *
  124.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  124.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  124.34 - *
  124.35 - * If you wish your version of this file to be governed by only the CDDL
  124.36 - * or only the GPL Version 2, indicate your decision by adding
  124.37 - * "[Contributor] elects to include this software in this distribution
  124.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  124.39 - * single choice of license, a recipient has the option to distribute
  124.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  124.41 - * to extend the choice of license to its licensees as provided above.
  124.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  124.43 - * Version 2 license, then the option applies only if the new code is
  124.44 - * made subject to such option by the copyright holder.
  124.45 - */
  124.46 -package org.apidesign.html.kofx;
  124.47 -
  124.48 -import java.io.IOException;
  124.49 -import java.io.InputStream;
  124.50 -import java.io.InputStreamReader;
  124.51 -import java.io.OutputStream;
  124.52 -import java.io.PushbackInputStream;
  124.53 -import java.io.Reader;
  124.54 -import java.net.HttpURLConnection;
  124.55 -import java.net.MalformedURLException;
  124.56 -import java.net.URL;
  124.57 -import java.net.URLConnection;
  124.58 -import java.util.Iterator;
  124.59 -import java.util.concurrent.Executor;
  124.60 -import java.util.concurrent.Executors;
  124.61 -import java.util.concurrent.ThreadFactory;
  124.62 -import java.util.logging.Level;
  124.63 -import java.util.logging.Logger;
  124.64 -import javafx.application.Platform;
  124.65 -import net.java.html.js.JavaScriptBody;
  124.66 -import netscape.javascript.JSObject;
  124.67 -import org.apidesign.html.json.spi.JSONCall;
  124.68 -import org.json.JSONArray;
  124.69 -import org.json.JSONException;
  124.70 -import org.json.JSONObject;
  124.71 -import org.json.JSONTokener;
  124.72 -
  124.73 -/** This is an implementation package - just
  124.74 - * include its JAR on classpath and use official {@link Context} API
  124.75 - * to access the functionality.
  124.76 - *
  124.77 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  124.78 - */
  124.79 -final class LoadJSON implements Runnable {
  124.80 -    private static final Logger LOG = FXContext.LOG;
  124.81 -    private static final Executor REQ = Executors.newCachedThreadPool(new ThreadFactory() {
  124.82 -        @Override
  124.83 -        public Thread newThread(Runnable runnable) {
  124.84 -            Thread thread = Executors.defaultThreadFactory().newThread(runnable);
  124.85 -            thread.setDaemon(true);
  124.86 -            return thread;
  124.87 -        }
  124.88 -    });
  124.89 -
  124.90 -    private final JSONCall call;
  124.91 -    private final URL base;
  124.92 -    private Throwable error;
  124.93 -    private Object json;
  124.94 -
  124.95 -
  124.96 -    private LoadJSON(JSONCall call) {
  124.97 -        this.call = call;
  124.98 -        URL b;
  124.99 -        try {
 124.100 -            b = new URL(findBaseURL());
 124.101 -        } catch (MalformedURLException ex) {
 124.102 -            LOG.log(Level.SEVERE, "Can't find base url for " + call.composeURL("dummy"), ex);
 124.103 -            b = null;
 124.104 -        }
 124.105 -        this.base = b;
 124.106 -    }
 124.107 -
 124.108 -    public static void loadJSON(JSONCall call) {
 124.109 -        assert !"WebSocket".equals(call.getMethod());
 124.110 -        REQ.execute(new LoadJSON((call)));
 124.111 -    }
 124.112 -
 124.113 -    @Override
 124.114 -    public void run() {
 124.115 -        if (Platform.isFxApplicationThread()) {
 124.116 -            if (error != null) {
 124.117 -                call.notifyError(error);
 124.118 -            } else {
 124.119 -                call.notifySuccess(json);
 124.120 -            }
 124.121 -            return;
 124.122 -        }
 124.123 -        final String url;
 124.124 -        if (call.isJSONP()) {
 124.125 -            url = call.composeURL("dummy");
 124.126 -        } else {
 124.127 -            url = call.composeURL(null);
 124.128 -        }
 124.129 -        try {
 124.130 -            final URL u = new URL(base, url.replace(" ", "%20"));
 124.131 -            URLConnection conn = u.openConnection();
 124.132 -            if (conn instanceof HttpURLConnection) {
 124.133 -                HttpURLConnection huc = (HttpURLConnection) conn;
 124.134 -                if (call.getMethod() != null) {
 124.135 -                    huc.setRequestMethod(call.getMethod());
 124.136 -                }
 124.137 -                if (call.isDoOutput()) {
 124.138 -                    huc.setDoOutput(true);
 124.139 -                    final OutputStream os = huc.getOutputStream();
 124.140 -                    call.writeData(os);
 124.141 -                    os.flush();
 124.142 -                }
 124.143 -            }
 124.144 -            final PushbackInputStream is = new PushbackInputStream(
 124.145 -                conn.getInputStream(), 1
 124.146 -            );
 124.147 -            boolean array = false;
 124.148 -            boolean string = false;
 124.149 -            if (call.isJSONP()) {
 124.150 -                for (;;) {
 124.151 -                    int ch = is.read();
 124.152 -                    if (ch == -1) {
 124.153 -                        break;
 124.154 -                    }
 124.155 -                    if (ch == '[') {
 124.156 -                        is.unread(ch);
 124.157 -                        array = true;
 124.158 -                        break;
 124.159 -                    }
 124.160 -                    if (ch == '{') {
 124.161 -                        is.unread(ch);
 124.162 -                        break;
 124.163 -                    }
 124.164 -                }
 124.165 -            } else {
 124.166 -                int ch = is.read();
 124.167 -                if (ch == -1) {
 124.168 -                    string = true;
 124.169 -                } else {
 124.170 -                    array = ch == '[';
 124.171 -                    is.unread(ch);
 124.172 -                    if (!array && ch != '{') {
 124.173 -                        string = true;
 124.174 -                    }
 124.175 -                }
 124.176 -            }
 124.177 -            try {
 124.178 -                if (string) {
 124.179 -                    throw new JSONException("");
 124.180 -                }
 124.181 -                Reader r = new InputStreamReader(is, "UTF-8");
 124.182 -
 124.183 -                JSONTokener tok = new JSONTokener(r);
 124.184 -                Object obj;
 124.185 -                obj = array ? new JSONArray(tok) : new JSONObject(tok);
 124.186 -                json = convertToArray(obj);
 124.187 -            } catch (JSONException ex) {
 124.188 -                Reader r = new InputStreamReader(is, "UTF-8");
 124.189 -                StringBuilder sb = new StringBuilder();
 124.190 -                for (;;) {
 124.191 -                    int ch = r.read();
 124.192 -                    if (ch == -1) {
 124.193 -                        break;
 124.194 -                    }
 124.195 -                    sb.append((char)ch);
 124.196 -                }
 124.197 -                json = sb.toString();
 124.198 -            }
 124.199 -        } catch (IOException ex) {
 124.200 -            error = ex;
 124.201 -        } finally {
 124.202 -            Platform.runLater(this);
 124.203 -        }
 124.204 -    }
 124.205 -
 124.206 -    static Object convertToArray(Object o) throws JSONException {
 124.207 -        if (o instanceof JSONArray) {
 124.208 -            JSONArray ja = (JSONArray)o;
 124.209 -            Object[] arr = new Object[ja.length()];
 124.210 -            for (int i = 0; i < arr.length; i++) {
 124.211 -                arr[i] = convertToArray(ja.get(i));
 124.212 -            }
 124.213 -            return arr;
 124.214 -        } else if (o instanceof JSONObject) {
 124.215 -            JSONObject obj = (JSONObject)o;
 124.216 -            Iterator it = obj.keys();
 124.217 -            while (it.hasNext()) {
 124.218 -                String key = (String)it.next();
 124.219 -                obj.put(key, convertToArray(obj.get(key)));
 124.220 -            }
 124.221 -            return obj;
 124.222 -        } else {
 124.223 -            return o;
 124.224 -        }
 124.225 -    }
 124.226 -    
 124.227 -    public static void extractJSON(Object jsonObject, String[] props, Object[] values) {
 124.228 -        if (jsonObject instanceof JSONObject) {
 124.229 -            JSONObject obj = (JSONObject)jsonObject;
 124.230 -            for (int i = 0; i < props.length; i++) {
 124.231 -                try {
 124.232 -                    values[i] = obj.has(props[i]) ? obj.get(props[i]) : null;
 124.233 -                } catch (JSONException ex) {
 124.234 -                    LoadJSON.LOG.log(Level.SEVERE, "Can't read " + props[i] + " from " + jsonObject, ex);
 124.235 -                }
 124.236 -            }
 124.237 -        }
 124.238 -        if (jsonObject instanceof JSObject) {
 124.239 -            JSObject obj = (JSObject)jsonObject;
 124.240 -            for (int i = 0; i < props.length; i++) {
 124.241 -                Object val = obj.getMember(props[i]);
 124.242 -                values[i] = isDefined(val) ? val : null;
 124.243 -            }
 124.244 -        }
 124.245 -    }
 124.246 -    
 124.247 -    public static Object parse(InputStream is) throws IOException {
 124.248 -        try {
 124.249 -            InputStreamReader r = new InputStreamReader(is, "UTF-8");
 124.250 -            JSONTokener t = new JSONTokener(r);
 124.251 -            return new JSONObject(t);
 124.252 -        } catch (JSONException ex) {
 124.253 -            throw new IOException(ex);
 124.254 -        }
 124.255 -    }
 124.256 -
 124.257 -    @JavaScriptBody(args = {  }, body = 
 124.258 -          "var h;"
 124.259 -        + "if (!!window && !!window.location && !!window.location.href)\n"
 124.260 -        + "  h = window.location.href;\n"
 124.261 -        + "else "
 124.262 -        + "  h = null;"
 124.263 -        + "return h;\n"
 124.264 -    )
 124.265 -    private static native String findBaseURL();
 124.266 -    
 124.267 -    private static boolean isDefined(Object val) {
 124.268 -        return !"undefined".equals(val);
 124.269 -    }
 124.270 -}
   125.1 --- a/ko-fx/src/main/java/org/apidesign/html/kofx/LoadWS.java	Mon Dec 16 15:48:09 2013 +0100
   125.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   125.3 @@ -1,149 +0,0 @@
   125.4 -/**
   125.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   125.6 - *
   125.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   125.8 - *
   125.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  125.10 - * Other names may be trademarks of their respective owners.
  125.11 - *
  125.12 - * The contents of this file are subject to the terms of either the GNU
  125.13 - * General Public License Version 2 only ("GPL") or the Common
  125.14 - * Development and Distribution License("CDDL") (collectively, the
  125.15 - * "License"). You may not use this file except in compliance with the
  125.16 - * License. You can obtain a copy of the License at
  125.17 - * http://www.netbeans.org/cddl-gplv2.html
  125.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  125.19 - * specific language governing permissions and limitations under the
  125.20 - * License.  When distributing the software, include this License Header
  125.21 - * Notice in each file and include the License file at
  125.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  125.23 - * particular file as subject to the "Classpath" exception as provided
  125.24 - * by Oracle in the GPL Version 2 section of the License file that
  125.25 - * accompanied this code. If applicable, add the following below the
  125.26 - * License Header, with the fields enclosed by brackets [] replaced by
  125.27 - * your own identifying information:
  125.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  125.29 - *
  125.30 - * Contributor(s):
  125.31 - *
  125.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  125.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  125.34 - *
  125.35 - * If you wish your version of this file to be governed by only the CDDL
  125.36 - * or only the GPL Version 2, indicate your decision by adding
  125.37 - * "[Contributor] elects to include this software in this distribution
  125.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  125.39 - * single choice of license, a recipient has the option to distribute
  125.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  125.41 - * to extend the choice of license to its licensees as provided above.
  125.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  125.43 - * Version 2 license, then the option applies only if the new code is
  125.44 - * made subject to such option by the copyright holder.
  125.45 - */
  125.46 -package org.apidesign.html.kofx;
  125.47 -
  125.48 -import net.java.html.js.JavaScriptBody;
  125.49 -import org.apidesign.html.json.spi.JSONCall;
  125.50 -import org.json.JSONArray;
  125.51 -import org.json.JSONException;
  125.52 -import org.json.JSONObject;
  125.53 -import org.json.JSONTokener;
  125.54 -
  125.55 -/** Communication with WebSockets for WebView 1.8.
  125.56 - *
  125.57 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  125.58 - */
  125.59 -final class LoadWS {
  125.60 -    private static final boolean SUPPORTED = isWebSocket();
  125.61 -    private final Object ws;
  125.62 -    private final JSONCall call;
  125.63 -
  125.64 -    LoadWS(JSONCall first, String url) {
  125.65 -        call = first;
  125.66 -        ws = initWebSocket(this, url);
  125.67 -        if (ws == null) {
  125.68 -            first.notifyError(new IllegalArgumentException("Wrong URL: " + url));
  125.69 -        }
  125.70 -    }
  125.71 -    
  125.72 -    static boolean isSupported() {
  125.73 -        return SUPPORTED;
  125.74 -    }
  125.75 -    
  125.76 -    void send(JSONCall call) {
  125.77 -        push(call);
  125.78 -    }
  125.79 -    
  125.80 -    private synchronized void push(JSONCall call) {
  125.81 -        send(ws, call.getMessage());
  125.82 -    }
  125.83 -
  125.84 -    void onOpen(Object ev) {
  125.85 -        if (!call.isDoOutput()) {
  125.86 -            call.notifySuccess(null);
  125.87 -        }
  125.88 -    }
  125.89 -    
  125.90 -    void onMessage(Object ev, String data) {
  125.91 -        Object json;
  125.92 -        try {
  125.93 -            data = data.trim();
  125.94 -            
  125.95 -            JSONTokener tok = new JSONTokener(data);
  125.96 -            Object obj;
  125.97 -            obj = data.startsWith("[") ? new JSONArray(tok) : new JSONObject(tok);
  125.98 -            json = LoadJSON.convertToArray(obj);
  125.99 -        } catch (JSONException ex) {
 125.100 -            json = data;
 125.101 -        }
 125.102 -        call.notifySuccess(json);
 125.103 -    }
 125.104 -    
 125.105 -    void onError(Object ev) {
 125.106 -        call.notifyError(new Exception(ev.toString()));
 125.107 -    }
 125.108 -
 125.109 -    void onClose(boolean wasClean, int code, String reason) {
 125.110 -        call.notifyError(null);
 125.111 -    }
 125.112 -    
 125.113 -    @JavaScriptBody(args = {}, body = "if (window.WebSocket) return true; else return false;")
 125.114 -    private static boolean isWebSocket() {
 125.115 -        return false;
 125.116 -    }
 125.117 -
 125.118 -    @JavaScriptBody(args = { "back", "url" }, javacall = true, body = ""
 125.119 -        + "if (window.WebSocket) {"
 125.120 -        + "  try {"
 125.121 -        + "    var ws = new window.WebSocket(url);"
 125.122 -        + "    ws.onopen = function(ev) { back.@org.apidesign.html.kofx.LoadWS::onOpen(Ljava/lang/Object;)(ev); };"
 125.123 -        + "    ws.onmessage = function(ev) { back.@org.apidesign.html.kofx.LoadWS::onMessage(Ljava/lang/Object;Ljava/lang/String;)(ev, ev.data); };"
 125.124 -        + "    ws.onerror = function(ev) { back.@org.apidesign.html.kofx.LoadWS::onError(Ljava/lang/Object;)(ev); };"
 125.125 -        + "    ws.onclose = function(ev) { back.@org.apidesign.html.kofx.LoadWS::onClose(ZILjava/lang/String;)(ev.wasClean, ev.code, ev.reason); };"
 125.126 -        + "    return ws;"
 125.127 -        + "  } catch (ex) {"
 125.128 -        + "    return null;"
 125.129 -        + "  }"
 125.130 -        + "} else {"
 125.131 -        + "  return null;"
 125.132 -        + "}"
 125.133 -    )
 125.134 -    private static Object initWebSocket(Object back, String url) {
 125.135 -        return null;
 125.136 -    }
 125.137 -    
 125.138 -
 125.139 -    @JavaScriptBody(args = { "ws", "msg" }, body = ""
 125.140 -        + "ws.send(msg);"
 125.141 -    )
 125.142 -    private void send(Object ws, String msg) {
 125.143 -    }
 125.144 -
 125.145 -    @JavaScriptBody(args = { "ws" }, body = "ws.close();")
 125.146 -    private static void close(Object ws) {
 125.147 -    }
 125.148 -
 125.149 -    void close() {
 125.150 -        close(ws);
 125.151 -    }
 125.152 -}
   126.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   126.2 +++ b/ko-fx/src/main/java/org/netbeans/html/kofx/Console.java	Mon Dec 16 16:59:43 2013 +0100
   126.3 @@ -0,0 +1,81 @@
   126.4 +/**
   126.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   126.6 + *
   126.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   126.8 + *
   126.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  126.10 + * Other names may be trademarks of their respective owners.
  126.11 + *
  126.12 + * The contents of this file are subject to the terms of either the GNU
  126.13 + * General Public License Version 2 only ("GPL") or the Common
  126.14 + * Development and Distribution License("CDDL") (collectively, the
  126.15 + * "License"). You may not use this file except in compliance with the
  126.16 + * License. You can obtain a copy of the License at
  126.17 + * http://www.netbeans.org/cddl-gplv2.html
  126.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  126.19 + * specific language governing permissions and limitations under the
  126.20 + * License.  When distributing the software, include this License Header
  126.21 + * Notice in each file and include the License file at
  126.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  126.23 + * particular file as subject to the "Classpath" exception as provided
  126.24 + * by Oracle in the GPL Version 2 section of the License file that
  126.25 + * accompanied this code. If applicable, add the following below the
  126.26 + * License Header, with the fields enclosed by brackets [] replaced by
  126.27 + * your own identifying information:
  126.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  126.29 + *
  126.30 + * Contributor(s):
  126.31 + *
  126.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  126.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  126.34 + *
  126.35 + * If you wish your version of this file to be governed by only the CDDL
  126.36 + * or only the GPL Version 2, indicate your decision by adding
  126.37 + * "[Contributor] elects to include this software in this distribution
  126.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  126.39 + * single choice of license, a recipient has the option to distribute
  126.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  126.41 + * to extend the choice of license to its licensees as provided above.
  126.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  126.43 + * Version 2 license, then the option applies only if the new code is
  126.44 + * made subject to such option by the copyright holder.
  126.45 + */
  126.46 +package org.netbeans.html.kofx;
  126.47 +
  126.48 +import java.util.logging.Level;
  126.49 +import java.util.logging.Logger;
  126.50 +import net.java.html.js.JavaScriptBody;
  126.51 +
  126.52 +/** This is an implementation package - just
  126.53 + * include its JAR on classpath and use official {@link Context} API
  126.54 + * to access the functionality.
  126.55 + * <p>
  126.56 + * Redirects JavaScript's messages to Java's {@link Logger}.
  126.57 + *
  126.58 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  126.59 + */
  126.60 +final class Console {
  126.61 +    private static final Logger LOG = Logger.getLogger(Console.class.getName());
  126.62 +    
  126.63 +    private Console() {
  126.64 +    }
  126.65 +
  126.66 +    static void register() {
  126.67 +        registerImpl("log", Level.INFO);
  126.68 +        registerImpl("info", Level.INFO);
  126.69 +        registerImpl("warn", Level.WARNING);
  126.70 +        registerImpl("error", Level.SEVERE);
  126.71 +    }
  126.72 +    
  126.73 +    @JavaScriptBody(args = { "attr", "l" }, 
  126.74 +        javacall = true, body = 
  126.75 +        "  window.console[attr] = function(m) {\n"
  126.76 +      + "    @org.netbeans.html.kofx.Console::log(Ljava/util/logging/Level;Ljava/lang/String;)(l, m);\n"
  126.77 +      + "  };\n"
  126.78 +    )
  126.79 +    private static native void registerImpl(String attr, Level l);
  126.80 +    
  126.81 +    static void log(Level l, String msg) {
  126.82 +        LOG.log(l, msg);
  126.83 +    }
  126.84 +}
   127.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   127.2 +++ b/ko-fx/src/main/java/org/netbeans/html/kofx/FXContext.java	Mon Dec 16 16:59:43 2013 +0100
   127.3 @@ -0,0 +1,222 @@
   127.4 +/**
   127.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   127.6 + *
   127.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   127.8 + *
   127.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  127.10 + * Other names may be trademarks of their respective owners.
  127.11 + *
  127.12 + * The contents of this file are subject to the terms of either the GNU
  127.13 + * General Public License Version 2 only ("GPL") or the Common
  127.14 + * Development and Distribution License("CDDL") (collectively, the
  127.15 + * "License"). You may not use this file except in compliance with the
  127.16 + * License. You can obtain a copy of the License at
  127.17 + * http://www.netbeans.org/cddl-gplv2.html
  127.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  127.19 + * specific language governing permissions and limitations under the
  127.20 + * License.  When distributing the software, include this License Header
  127.21 + * Notice in each file and include the License file at
  127.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  127.23 + * particular file as subject to the "Classpath" exception as provided
  127.24 + * by Oracle in the GPL Version 2 section of the License file that
  127.25 + * accompanied this code. If applicable, add the following below the
  127.26 + * License Header, with the fields enclosed by brackets [] replaced by
  127.27 + * your own identifying information:
  127.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  127.29 + *
  127.30 + * Contributor(s):
  127.31 + *
  127.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  127.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  127.34 + *
  127.35 + * If you wish your version of this file to be governed by only the CDDL
  127.36 + * or only the GPL Version 2, indicate your decision by adding
  127.37 + * "[Contributor] elects to include this software in this distribution
  127.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  127.39 + * single choice of license, a recipient has the option to distribute
  127.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  127.41 + * to extend the choice of license to its licensees as provided above.
  127.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  127.43 + * Version 2 license, then the option applies only if the new code is
  127.44 + * made subject to such option by the copyright holder.
  127.45 + */
  127.46 +package org.netbeans.html.kofx;
  127.47 +
  127.48 +import java.io.Closeable;
  127.49 +import java.io.IOException;
  127.50 +import java.io.InputStream;
  127.51 +import java.util.ServiceLoader;
  127.52 +import java.util.logging.Logger;
  127.53 +import javafx.application.Platform;
  127.54 +import net.java.html.js.JavaScriptBody;
  127.55 +import netscape.javascript.JSObject;
  127.56 +import org.apidesign.html.boot.spi.Fn;
  127.57 +import org.apidesign.html.context.spi.Contexts;
  127.58 +import org.apidesign.html.json.spi.FunctionBinding;
  127.59 +import org.apidesign.html.json.spi.JSONCall;
  127.60 +import org.apidesign.html.json.spi.PropertyBinding;
  127.61 +import org.apidesign.html.json.spi.Technology;
  127.62 +import org.apidesign.html.json.spi.Transfer;
  127.63 +import org.apidesign.html.json.spi.WSTransfer;
  127.64 +import org.openide.util.lookup.ServiceProvider;
  127.65 +
  127.66 +/** This is an implementation package - just
  127.67 + * include its JAR on classpath and use official {@link Context} API
  127.68 + * to access the functionality.
  127.69 + * <p>
  127.70 + * Registers {@link ContextProvider}, so {@link ServiceLoader} can find it.
  127.71 + *
  127.72 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  127.73 + */
  127.74 +public final class FXContext
  127.75 +implements Technology.BatchInit<JSObject>, Transfer, WSTransfer<LoadWS> {
  127.76 +    static final Logger LOG = Logger.getLogger(FXContext.class.getName());
  127.77 +    private static Boolean javaScriptEnabled;
  127.78 +    private final Fn.Presenter browserContext;
  127.79 +
  127.80 +    public FXContext(Fn.Presenter browserContext) {
  127.81 +        this.browserContext = browserContext;
  127.82 +    }
  127.83 +    
  127.84 +    @JavaScriptBody(args = {}, body = "return true;")
  127.85 +    private static boolean isJavaScriptEnabledJs() {
  127.86 +        return false;
  127.87 +    }
  127.88 +    
  127.89 +    static boolean isJavaScriptEnabled() {
  127.90 +        if (javaScriptEnabled != null) {
  127.91 +            return javaScriptEnabled;
  127.92 +        }
  127.93 +        return javaScriptEnabled = isJavaScriptEnabledJs();
  127.94 +    }
  127.95 +
  127.96 +    final boolean areWebSocketsSupported() {
  127.97 +        return LoadWS.isSupported();
  127.98 +    }
  127.99 +
 127.100 +
 127.101 +    @Override
 127.102 +    public JSObject wrapModel(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
 127.103 +        String[] propNames = new String[propArr.length];
 127.104 +        boolean[] propReadOnly = new boolean[propArr.length];
 127.105 +        Object[] propValues = new Object[propArr.length];
 127.106 +        for (int i = 0; i < propNames.length; i++) {
 127.107 +            propNames[i] = propArr[i].getPropertyName();
 127.108 +            propReadOnly[i] = propArr[i].isReadOnly();
 127.109 +            propValues[i] = propArr[i].getValue();
 127.110 +        }
 127.111 +        String[] funcNames = new String[funcArr.length];
 127.112 +        for (int i = 0; i < funcNames.length; i++) {
 127.113 +            funcNames[i] = funcArr[i].getFunctionName();
 127.114 +        }
 127.115 +        
 127.116 +        return Knockout.wrapModel(model, 
 127.117 +            propNames, propReadOnly, Knockout.toArray(propValues), propArr, 
 127.118 +            funcNames, funcArr
 127.119 +        );
 127.120 +    }
 127.121 +    
 127.122 +    @Override
 127.123 +    public JSObject wrapModel(Object model) {
 127.124 +        throw new UnsupportedOperationException();
 127.125 +    }
 127.126 +
 127.127 +    @Override
 127.128 +    public void bind(PropertyBinding b, Object model, JSObject data) {
 127.129 +        throw new UnsupportedOperationException();
 127.130 +    }
 127.131 +
 127.132 +    @Override
 127.133 +    public void valueHasMutated(JSObject data, String propertyName) {
 127.134 +        Knockout.valueHasMutated(data, propertyName);
 127.135 +    }
 127.136 +
 127.137 +    @Override
 127.138 +    public void expose(FunctionBinding fb, Object model, JSObject d) {
 127.139 +        throw new UnsupportedOperationException();
 127.140 +    }
 127.141 +
 127.142 +    @Override
 127.143 +    public void applyBindings(JSObject data) {
 127.144 +        Knockout.applyBindings(data);
 127.145 +    }
 127.146 +
 127.147 +    @Override
 127.148 +    public Object wrapArray(Object[] arr) {
 127.149 +        return Knockout.toArray(arr);
 127.150 +    }
 127.151 +
 127.152 +    @Override
 127.153 +    public void extract(Object obj, String[] props, Object[] values) {
 127.154 +        LoadJSON.extractJSON(obj, props, values);
 127.155 +    }
 127.156 +
 127.157 +    @Override
 127.158 +    public void loadJSON(final JSONCall call) {
 127.159 +        LoadJSON.loadJSON(call);
 127.160 +    }
 127.161 +
 127.162 +    @Override
 127.163 +    public <M> M toModel(Class<M> modelClass, Object data) {
 127.164 +        if (data instanceof JSObject) {
 127.165 +            data = ((JSObject)data).getMember("ko-fx.model"); // NOI18N
 127.166 +        }
 127.167 +        return modelClass.cast(data);
 127.168 +    }
 127.169 +
 127.170 +    @Override
 127.171 +    public Object toJSON(InputStream is) throws IOException {
 127.172 +        return LoadJSON.parse(is);
 127.173 +    }
 127.174 +
 127.175 +    @Override
 127.176 +    public void runSafe(final Runnable r) {
 127.177 +        class Wrap implements Runnable {
 127.178 +            @Override public void run() {
 127.179 +                try (Closeable c = Fn.activate(browserContext)) {
 127.180 +                    r.run();
 127.181 +                } catch (IOException ex) {
 127.182 +                    // cannot be thrown
 127.183 +                }
 127.184 +            }
 127.185 +        }
 127.186 +        Wrap w = new Wrap();
 127.187 +        
 127.188 +        if (Platform.isFxApplicationThread()) {
 127.189 +            w.run();
 127.190 +        } else {
 127.191 +            Platform.runLater(w);
 127.192 +        }
 127.193 +    }
 127.194 +
 127.195 +    @Override
 127.196 +    public LoadWS open(String url, JSONCall onReply) {
 127.197 +        return new LoadWS(onReply, url);
 127.198 +    }
 127.199 +
 127.200 +    @Override
 127.201 +    public void send(LoadWS socket, JSONCall data) {
 127.202 +        socket.send(data);
 127.203 +    }
 127.204 +
 127.205 +    @Override
 127.206 +    public void close(LoadWS socket) {
 127.207 +        socket.close();
 127.208 +    }
 127.209 +    
 127.210 +    @ServiceProvider(service = Contexts.Provider.class)
 127.211 +    public static final class Prvdr implements Contexts.Provider {
 127.212 +        @Override
 127.213 +        public void fillContext(Contexts.Builder context, Class<?> requestor) {
 127.214 +            if (isJavaScriptEnabled()) {
 127.215 +                FXContext c = new FXContext(Fn.activePresenter());
 127.216 +                
 127.217 +                context.register(Technology.class, c, 100);
 127.218 +                context.register(Transfer.class, c, 100);
 127.219 +                if (c.areWebSocketsSupported()) {
 127.220 +                    context.register(WSTransfer.class, c, 100);
 127.221 +                }
 127.222 +            }
 127.223 +        }
 127.224 +    }
 127.225 +}
   128.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   128.2 +++ b/ko-fx/src/main/java/org/netbeans/html/kofx/Knockout.java	Mon Dec 16 16:59:43 2013 +0100
   128.3 @@ -0,0 +1,145 @@
   128.4 +/**
   128.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   128.6 + *
   128.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   128.8 + *
   128.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  128.10 + * Other names may be trademarks of their respective owners.
  128.11 + *
  128.12 + * The contents of this file are subject to the terms of either the GNU
  128.13 + * General Public License Version 2 only ("GPL") or the Common
  128.14 + * Development and Distribution License("CDDL") (collectively, the
  128.15 + * "License"). You may not use this file except in compliance with the
  128.16 + * License. You can obtain a copy of the License at
  128.17 + * http://www.netbeans.org/cddl-gplv2.html
  128.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  128.19 + * specific language governing permissions and limitations under the
  128.20 + * License.  When distributing the software, include this License Header
  128.21 + * Notice in each file and include the License file at
  128.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  128.23 + * particular file as subject to the "Classpath" exception as provided
  128.24 + * by Oracle in the GPL Version 2 section of the License file that
  128.25 + * accompanied this code. If applicable, add the following below the
  128.26 + * License Header, with the fields enclosed by brackets [] replaced by
  128.27 + * your own identifying information:
  128.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  128.29 + *
  128.30 + * Contributor(s):
  128.31 + *
  128.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  128.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  128.34 + *
  128.35 + * If you wish your version of this file to be governed by only the CDDL
  128.36 + * or only the GPL Version 2, indicate your decision by adding
  128.37 + * "[Contributor] elects to include this software in this distribution
  128.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  128.39 + * single choice of license, a recipient has the option to distribute
  128.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  128.41 + * to extend the choice of license to its licensees as provided above.
  128.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  128.43 + * Version 2 license, then the option applies only if the new code is
  128.44 + * made subject to such option by the copyright holder.
  128.45 + */
  128.46 +package org.netbeans.html.kofx;
  128.47 +
  128.48 +import net.java.html.js.JavaScriptBody;
  128.49 +import net.java.html.js.JavaScriptResource;
  128.50 +import net.java.html.json.Model;
  128.51 +import netscape.javascript.JSObject;
  128.52 +import org.apidesign.html.json.spi.FunctionBinding;
  128.53 +import org.apidesign.html.json.spi.PropertyBinding;
  128.54 +
  128.55 +/** This is an implementation package - just
  128.56 + * include its JAR on classpath and use official {@link Context} API
  128.57 + * to access the functionality.
  128.58 + * <p>
  128.59 + * Provides binding between {@link Model models} and knockout.js running
  128.60 + * inside a JavaFX WebView. 
  128.61 + *
  128.62 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  128.63 + */
  128.64 +@JavaScriptResource("knockout-2.2.1.js")
  128.65 +final class Knockout {
  128.66 +    static final JSObject KObject;
  128.67 +    static {
  128.68 +        Console.register();
  128.69 +        KObject = (JSObject) kObj();
  128.70 +    }
  128.71 +
  128.72 +    static Object toArray(Object[] arr) {
  128.73 +        return KObject.call("array", arr);
  128.74 +    }
  128.75 +    
  128.76 +    @JavaScriptBody(args = { "model", "prop" }, body =
  128.77 +          "if (model) {\n"
  128.78 +        + "  var koProp = model[prop];\n"
  128.79 +        + "  if (koProp && koProp['valueHasMutated']) {\n"
  128.80 +        + "    koProp['valueHasMutated']();\n"
  128.81 +        + "  }\n"
  128.82 +        + "}\n"
  128.83 +    )
  128.84 +    public native static void valueHasMutated(JSObject model, String prop);
  128.85 +
  128.86 +    @JavaScriptBody(args = { "bindings" }, body = "ko.applyBindings(bindings);")
  128.87 +    native static void applyBindings(Object bindings);
  128.88 +    
  128.89 +    @JavaScriptBody(args = {}, body =
  128.90 +              "  var k = {};"
  128.91 +            + "  k.array= function() {"
  128.92 +            + "    return Array.prototype.slice.call(arguments);"
  128.93 +            + "  };"
  128.94 +            + "  return k;"
  128.95 +    )
  128.96 +    private static native Object kObj();
  128.97 +        
  128.98 +        
  128.99 +    @JavaScriptBody(
 128.100 +        javacall = true,
 128.101 +        args = {"model", "propNames", "propReadOnly", "propValues", "propArr", "funcNames", "funcArr"},
 128.102 +        body
 128.103 +        = "var ret = {};\n"
 128.104 +        + "ret['ko-fx.model'] = model;\n"
 128.105 +        + "function koComputed(name, readOnly, value, prop) {\n"
 128.106 +        + "  function realGetter() {\n"
 128.107 +        + "    try {"
 128.108 +        + "      var v = prop.@org.apidesign.html.json.spi.PropertyBinding::getValue()();"
 128.109 +        + "      return v;"
 128.110 +        + "    } catch (e) {"
 128.111 +        + "      alert(\"Cannot call getValue on \" + model + \" prop: \" + name + \" error: \" + e);"
 128.112 +        + "    }"
 128.113 +        + "  }\n"
 128.114 +        + "  var activeGetter = function() { return value; };\n"
 128.115 +        + "  var bnd = {"
 128.116 +        + "    read: function() {"
 128.117 +        + "      var r = activeGetter();"
 128.118 +        + "      activeGetter = realGetter;"
 128.119 +        + "      return r;"
 128.120 +        + "    },"
 128.121 +        + "    owner: ret\n"
 128.122 +        + "  };\n"
 128.123 +        + "  if (!readOnly) {\n"
 128.124 +        + "    bnd.write = function(val) {\n"
 128.125 +        + "      prop.@org.apidesign.html.json.spi.PropertyBinding::setValue(Ljava/lang/Object;)(val);\n"
 128.126 +        + "    };"
 128.127 +        + "  };"
 128.128 +        + "  ret[name] = ko.computed(bnd);"
 128.129 +        + "}\n"
 128.130 +        + "for (var i = 0; i < propNames.length; i++) {\n"
 128.131 +        + "  koComputed(propNames[i], propReadOnly[i], propValues[i], propArr[i]);\n"
 128.132 +        + "}\n"
 128.133 +        + "function koExpose(name, func) {\n"
 128.134 +        + "  ret[name] = function(data, ev) {\n"
 128.135 +        + "    func.@org.apidesign.html.json.spi.FunctionBinding::call(Ljava/lang/Object;Ljava/lang/Object;)(data, ev);\n"
 128.136 +        + "  };\n"
 128.137 +        + "}\n"
 128.138 +        + "for (var i = 0; i < funcNames.length; i++) {\n"
 128.139 +        + "  koExpose(funcNames[i], funcArr[i]);\n"
 128.140 +        + "}\n"
 128.141 +        + "return ret;\n"
 128.142 +        )
 128.143 +    static native JSObject wrapModel(
 128.144 +        Object model,
 128.145 +        String[] propNames, boolean[] propReadOnly, Object propValues, PropertyBinding[] propArr,
 128.146 +        String[] funcNames, FunctionBinding[] funcArr
 128.147 +    );
 128.148 +}
   129.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   129.2 +++ b/ko-fx/src/main/java/org/netbeans/html/kofx/LoadJSON.java	Mon Dec 16 16:59:43 2013 +0100
   129.3 @@ -0,0 +1,267 @@
   129.4 +/**
   129.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   129.6 + *
   129.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   129.8 + *
   129.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  129.10 + * Other names may be trademarks of their respective owners.
  129.11 + *
  129.12 + * The contents of this file are subject to the terms of either the GNU
  129.13 + * General Public License Version 2 only ("GPL") or the Common
  129.14 + * Development and Distribution License("CDDL") (collectively, the
  129.15 + * "License"). You may not use this file except in compliance with the
  129.16 + * License. You can obtain a copy of the License at
  129.17 + * http://www.netbeans.org/cddl-gplv2.html
  129.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  129.19 + * specific language governing permissions and limitations under the
  129.20 + * License.  When distributing the software, include this License Header
  129.21 + * Notice in each file and include the License file at
  129.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  129.23 + * particular file as subject to the "Classpath" exception as provided
  129.24 + * by Oracle in the GPL Version 2 section of the License file that
  129.25 + * accompanied this code. If applicable, add the following below the
  129.26 + * License Header, with the fields enclosed by brackets [] replaced by
  129.27 + * your own identifying information:
  129.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  129.29 + *
  129.30 + * Contributor(s):
  129.31 + *
  129.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  129.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  129.34 + *
  129.35 + * If you wish your version of this file to be governed by only the CDDL
  129.36 + * or only the GPL Version 2, indicate your decision by adding
  129.37 + * "[Contributor] elects to include this software in this distribution
  129.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  129.39 + * single choice of license, a recipient has the option to distribute
  129.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  129.41 + * to extend the choice of license to its licensees as provided above.
  129.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  129.43 + * Version 2 license, then the option applies only if the new code is
  129.44 + * made subject to such option by the copyright holder.
  129.45 + */
  129.46 +package org.netbeans.html.kofx;
  129.47 +
  129.48 +import java.io.IOException;
  129.49 +import java.io.InputStream;
  129.50 +import java.io.InputStreamReader;
  129.51 +import java.io.OutputStream;
  129.52 +import java.io.PushbackInputStream;
  129.53 +import java.io.Reader;
  129.54 +import java.net.HttpURLConnection;
  129.55 +import java.net.MalformedURLException;
  129.56 +import java.net.URL;
  129.57 +import java.net.URLConnection;
  129.58 +import java.util.Iterator;
  129.59 +import java.util.concurrent.Executor;
  129.60 +import java.util.concurrent.Executors;
  129.61 +import java.util.concurrent.ThreadFactory;
  129.62 +import java.util.logging.Level;
  129.63 +import java.util.logging.Logger;
  129.64 +import javafx.application.Platform;
  129.65 +import net.java.html.js.JavaScriptBody;
  129.66 +import netscape.javascript.JSObject;
  129.67 +import org.apidesign.html.json.spi.JSONCall;
  129.68 +import org.json.JSONArray;
  129.69 +import org.json.JSONException;
  129.70 +import org.json.JSONObject;
  129.71 +import org.json.JSONTokener;
  129.72 +
  129.73 +/** This is an implementation package - just
  129.74 + * include its JAR on classpath and use official {@link Context} API
  129.75 + * to access the functionality.
  129.76 + *
  129.77 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  129.78 + */
  129.79 +final class LoadJSON implements Runnable {
  129.80 +    private static final Logger LOG = FXContext.LOG;
  129.81 +    private static final Executor REQ = Executors.newCachedThreadPool(new ThreadFactory() {
  129.82 +        @Override
  129.83 +        public Thread newThread(Runnable runnable) {
  129.84 +            Thread thread = Executors.defaultThreadFactory().newThread(runnable);
  129.85 +            thread.setDaemon(true);
  129.86 +            return thread;
  129.87 +        }
  129.88 +    });
  129.89 +
  129.90 +    private final JSONCall call;
  129.91 +    private final URL base;
  129.92 +    private Throwable error;
  129.93 +    private Object json;
  129.94 +
  129.95 +
  129.96 +    private LoadJSON(JSONCall call) {
  129.97 +        this.call = call;
  129.98 +        URL b;
  129.99 +        try {
 129.100 +            b = new URL(findBaseURL());
 129.101 +        } catch (MalformedURLException ex) {
 129.102 +            LOG.log(Level.SEVERE, "Can't find base url for " + call.composeURL("dummy"), ex);
 129.103 +            b = null;
 129.104 +        }
 129.105 +        this.base = b;
 129.106 +    }
 129.107 +
 129.108 +    public static void loadJSON(JSONCall call) {
 129.109 +        assert !"WebSocket".equals(call.getMethod());
 129.110 +        REQ.execute(new LoadJSON((call)));
 129.111 +    }
 129.112 +
 129.113 +    @Override
 129.114 +    public void run() {
 129.115 +        if (Platform.isFxApplicationThread()) {
 129.116 +            if (error != null) {
 129.117 +                call.notifyError(error);
 129.118 +            } else {
 129.119 +                call.notifySuccess(json);
 129.120 +            }
 129.121 +            return;
 129.122 +        }
 129.123 +        final String url;
 129.124 +        if (call.isJSONP()) {
 129.125 +            url = call.composeURL("dummy");
 129.126 +        } else {
 129.127 +            url = call.composeURL(null);
 129.128 +        }
 129.129 +        try {
 129.130 +            final URL u = new URL(base, url.replace(" ", "%20"));
 129.131 +            URLConnection conn = u.openConnection();
 129.132 +            if (conn instanceof HttpURLConnection) {
 129.133 +                HttpURLConnection huc = (HttpURLConnection) conn;
 129.134 +                if (call.getMethod() != null) {
 129.135 +                    huc.setRequestMethod(call.getMethod());
 129.136 +                }
 129.137 +                if (call.isDoOutput()) {
 129.138 +                    huc.setDoOutput(true);
 129.139 +                    final OutputStream os = huc.getOutputStream();
 129.140 +                    call.writeData(os);
 129.141 +                    os.flush();
 129.142 +                }
 129.143 +            }
 129.144 +            final PushbackInputStream is = new PushbackInputStream(
 129.145 +                conn.getInputStream(), 1
 129.146 +            );
 129.147 +            boolean array = false;
 129.148 +            boolean string = false;
 129.149 +            if (call.isJSONP()) {
 129.150 +                for (;;) {
 129.151 +                    int ch = is.read();
 129.152 +                    if (ch == -1) {
 129.153 +                        break;
 129.154 +                    }
 129.155 +                    if (ch == '[') {
 129.156 +                        is.unread(ch);
 129.157 +                        array = true;
 129.158 +                        break;
 129.159 +                    }
 129.160 +                    if (ch == '{') {
 129.161 +                        is.unread(ch);
 129.162 +                        break;
 129.163 +                    }
 129.164 +                }
 129.165 +            } else {
 129.166 +                int ch = is.read();
 129.167 +                if (ch == -1) {
 129.168 +                    string = true;
 129.169 +                } else {
 129.170 +                    array = ch == '[';
 129.171 +                    is.unread(ch);
 129.172 +                    if (!array && ch != '{') {
 129.173 +                        string = true;
 129.174 +                    }
 129.175 +                }
 129.176 +            }
 129.177 +            try {
 129.178 +                if (string) {
 129.179 +                    throw new JSONException("");
 129.180 +                }
 129.181 +                Reader r = new InputStreamReader(is, "UTF-8");
 129.182 +
 129.183 +                JSONTokener tok = new JSONTokener(r);
 129.184 +                Object obj;
 129.185 +                obj = array ? new JSONArray(tok) : new JSONObject(tok);
 129.186 +                json = convertToArray(obj);
 129.187 +            } catch (JSONException ex) {
 129.188 +                Reader r = new InputStreamReader(is, "UTF-8");
 129.189 +                StringBuilder sb = new StringBuilder();
 129.190 +                for (;;) {
 129.191 +                    int ch = r.read();
 129.192 +                    if (ch == -1) {
 129.193 +                        break;
 129.194 +                    }
 129.195 +                    sb.append((char)ch);
 129.196 +                }
 129.197 +                json = sb.toString();
 129.198 +            }
 129.199 +        } catch (IOException ex) {
 129.200 +            error = ex;
 129.201 +        } finally {
 129.202 +            Platform.runLater(this);
 129.203 +        }
 129.204 +    }
 129.205 +
 129.206 +    static Object convertToArray(Object o) throws JSONException {
 129.207 +        if (o instanceof JSONArray) {
 129.208 +            JSONArray ja = (JSONArray)o;
 129.209 +            Object[] arr = new Object[ja.length()];
 129.210 +            for (int i = 0; i < arr.length; i++) {
 129.211 +                arr[i] = convertToArray(ja.get(i));
 129.212 +            }
 129.213 +            return arr;
 129.214 +        } else if (o instanceof JSONObject) {
 129.215 +            JSONObject obj = (JSONObject)o;
 129.216 +            Iterator it = obj.keys();
 129.217 +            while (it.hasNext()) {
 129.218 +                String key = (String)it.next();
 129.219 +                obj.put(key, convertToArray(obj.get(key)));
 129.220 +            }
 129.221 +            return obj;
 129.222 +        } else {
 129.223 +            return o;
 129.224 +        }
 129.225 +    }
 129.226 +    
 129.227 +    public static void extractJSON(Object jsonObject, String[] props, Object[] values) {
 129.228 +        if (jsonObject instanceof JSONObject) {
 129.229 +            JSONObject obj = (JSONObject)jsonObject;
 129.230 +            for (int i = 0; i < props.length; i++) {
 129.231 +                try {
 129.232 +                    values[i] = obj.has(props[i]) ? obj.get(props[i]) : null;
 129.233 +                } catch (JSONException ex) {
 129.234 +                    LoadJSON.LOG.log(Level.SEVERE, "Can't read " + props[i] + " from " + jsonObject, ex);
 129.235 +                }
 129.236 +            }
 129.237 +        }
 129.238 +        if (jsonObject instanceof JSObject) {
 129.239 +            JSObject obj = (JSObject)jsonObject;
 129.240 +            for (int i = 0; i < props.length; i++) {
 129.241 +                Object val = obj.getMember(props[i]);
 129.242 +                values[i] = isDefined(val) ? val : null;
 129.243 +            }
 129.244 +        }
 129.245 +    }
 129.246 +    
 129.247 +    public static Object parse(InputStream is) throws IOException {
 129.248 +        try {
 129.249 +            InputStreamReader r = new InputStreamReader(is, "UTF-8");
 129.250 +            JSONTokener t = new JSONTokener(r);
 129.251 +            return new JSONObject(t);
 129.252 +        } catch (JSONException ex) {
 129.253 +            throw new IOException(ex);
 129.254 +        }
 129.255 +    }
 129.256 +
 129.257 +    @JavaScriptBody(args = {  }, body = 
 129.258 +          "var h;"
 129.259 +        + "if (!!window && !!window.location && !!window.location.href)\n"
 129.260 +        + "  h = window.location.href;\n"
 129.261 +        + "else "
 129.262 +        + "  h = null;"
 129.263 +        + "return h;\n"
 129.264 +    )
 129.265 +    private static native String findBaseURL();
 129.266 +    
 129.267 +    private static boolean isDefined(Object val) {
 129.268 +        return !"undefined".equals(val);
 129.269 +    }
 129.270 +}
   130.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   130.2 +++ b/ko-fx/src/main/java/org/netbeans/html/kofx/LoadWS.java	Mon Dec 16 16:59:43 2013 +0100
   130.3 @@ -0,0 +1,149 @@
   130.4 +/**
   130.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   130.6 + *
   130.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   130.8 + *
   130.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  130.10 + * Other names may be trademarks of their respective owners.
  130.11 + *
  130.12 + * The contents of this file are subject to the terms of either the GNU
  130.13 + * General Public License Version 2 only ("GPL") or the Common
  130.14 + * Development and Distribution License("CDDL") (collectively, the
  130.15 + * "License"). You may not use this file except in compliance with the
  130.16 + * License. You can obtain a copy of the License at
  130.17 + * http://www.netbeans.org/cddl-gplv2.html
  130.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  130.19 + * specific language governing permissions and limitations under the
  130.20 + * License.  When distributing the software, include this License Header
  130.21 + * Notice in each file and include the License file at
  130.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  130.23 + * particular file as subject to the "Classpath" exception as provided
  130.24 + * by Oracle in the GPL Version 2 section of the License file that
  130.25 + * accompanied this code. If applicable, add the following below the
  130.26 + * License Header, with the fields enclosed by brackets [] replaced by
  130.27 + * your own identifying information:
  130.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  130.29 + *
  130.30 + * Contributor(s):
  130.31 + *
  130.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  130.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  130.34 + *
  130.35 + * If you wish your version of this file to be governed by only the CDDL
  130.36 + * or only the GPL Version 2, indicate your decision by adding
  130.37 + * "[Contributor] elects to include this software in this distribution
  130.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  130.39 + * single choice of license, a recipient has the option to distribute
  130.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  130.41 + * to extend the choice of license to its licensees as provided above.
  130.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  130.43 + * Version 2 license, then the option applies only if the new code is
  130.44 + * made subject to such option by the copyright holder.
  130.45 + */
  130.46 +package org.netbeans.html.kofx;
  130.47 +
  130.48 +import net.java.html.js.JavaScriptBody;
  130.49 +import org.apidesign.html.json.spi.JSONCall;
  130.50 +import org.json.JSONArray;
  130.51 +import org.json.JSONException;
  130.52 +import org.json.JSONObject;
  130.53 +import org.json.JSONTokener;
  130.54 +
  130.55 +/** Communication with WebSockets for WebView 1.8.
  130.56 + *
  130.57 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  130.58 + */
  130.59 +final class LoadWS {
  130.60 +    private static final boolean SUPPORTED = isWebSocket();
  130.61 +    private final Object ws;
  130.62 +    private final JSONCall call;
  130.63 +
  130.64 +    LoadWS(JSONCall first, String url) {
  130.65 +        call = first;
  130.66 +        ws = initWebSocket(this, url);
  130.67 +        if (ws == null) {
  130.68 +            first.notifyError(new IllegalArgumentException("Wrong URL: " + url));
  130.69 +        }
  130.70 +    }
  130.71 +    
  130.72 +    static boolean isSupported() {
  130.73 +        return SUPPORTED;
  130.74 +    }
  130.75 +    
  130.76 +    void send(JSONCall call) {
  130.77 +        push(call);
  130.78 +    }
  130.79 +    
  130.80 +    private synchronized void push(JSONCall call) {
  130.81 +        send(ws, call.getMessage());
  130.82 +    }
  130.83 +
  130.84 +    void onOpen(Object ev) {
  130.85 +        if (!call.isDoOutput()) {
  130.86 +            call.notifySuccess(null);
  130.87 +        }
  130.88 +    }
  130.89 +    
  130.90 +    void onMessage(Object ev, String data) {
  130.91 +        Object json;
  130.92 +        try {
  130.93 +            data = data.trim();
  130.94 +            
  130.95 +            JSONTokener tok = new JSONTokener(data);
  130.96 +            Object obj;
  130.97 +            obj = data.startsWith("[") ? new JSONArray(tok) : new JSONObject(tok);
  130.98 +            json = LoadJSON.convertToArray(obj);
  130.99 +        } catch (JSONException ex) {
 130.100 +            json = data;
 130.101 +        }
 130.102 +        call.notifySuccess(json);
 130.103 +    }
 130.104 +    
 130.105 +    void onError(Object ev) {
 130.106 +        call.notifyError(new Exception(ev.toString()));
 130.107 +    }
 130.108 +
 130.109 +    void onClose(boolean wasClean, int code, String reason) {
 130.110 +        call.notifyError(null);
 130.111 +    }
 130.112 +    
 130.113 +    @JavaScriptBody(args = {}, body = "if (window.WebSocket) return true; else return false;")
 130.114 +    private static boolean isWebSocket() {
 130.115 +        return false;
 130.116 +    }
 130.117 +
 130.118 +    @JavaScriptBody(args = { "back", "url" }, javacall = true, body = ""
 130.119 +        + "if (window.WebSocket) {"
 130.120 +        + "  try {"
 130.121 +        + "    var ws = new window.WebSocket(url);"
 130.122 +        + "    ws.onopen = function(ev) { back.@org.netbeans.html.kofx.LoadWS::onOpen(Ljava/lang/Object;)(ev); };"
 130.123 +        + "    ws.onmessage = function(ev) { back.@org.netbeans.html.kofx.LoadWS::onMessage(Ljava/lang/Object;Ljava/lang/String;)(ev, ev.data); };"
 130.124 +        + "    ws.onerror = function(ev) { back.@org.netbeans.html.kofx.LoadWS::onError(Ljava/lang/Object;)(ev); };"
 130.125 +        + "    ws.onclose = function(ev) { back.@org.netbeans.html.kofx.LoadWS::onClose(ZILjava/lang/String;)(ev.wasClean, ev.code, ev.reason); };"
 130.126 +        + "    return ws;"
 130.127 +        + "  } catch (ex) {"
 130.128 +        + "    return null;"
 130.129 +        + "  }"
 130.130 +        + "} else {"
 130.131 +        + "  return null;"
 130.132 +        + "}"
 130.133 +    )
 130.134 +    private static Object initWebSocket(Object back, String url) {
 130.135 +        return null;
 130.136 +    }
 130.137 +    
 130.138 +
 130.139 +    @JavaScriptBody(args = { "ws", "msg" }, body = ""
 130.140 +        + "ws.send(msg);"
 130.141 +    )
 130.142 +    private void send(Object ws, String msg) {
 130.143 +    }
 130.144 +
 130.145 +    @JavaScriptBody(args = { "ws" }, body = "ws.close();")
 130.146 +    private static void close(Object ws) {
 130.147 +    }
 130.148 +
 130.149 +    void close() {
 130.150 +        close(ws);
 130.151 +    }
 130.152 +}
   131.1 --- a/ko-fx/src/main/resources/org/apidesign/html/kofx/knockout-2.2.1.js	Mon Dec 16 15:48:09 2013 +0100
   131.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   131.3 @@ -1,3594 +0,0 @@
   131.4 -// Knockout JavaScript library v2.2.1
   131.5 -// (c) Steven Sanderson - http://knockoutjs.com/
   131.6 -// License: MIT (http://www.opensource.org/licenses/mit-license.php)
   131.7 -
   131.8 -(function(){
   131.9 -var DEBUG=true;
  131.10 -(function(window,document,navigator,jQuery,undefined){
  131.11 -!function(factory) {
  131.12 -    // Support three module loading scenarios
  131.13 -    if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
  131.14 -        // [1] CommonJS/Node.js
  131.15 -        var target = module['exports'] || exports; // module.exports is for Node.js
  131.16 -        factory(target);
  131.17 -    } else if (typeof define === 'function' && define['amd']) {
  131.18 -        // [2] AMD anonymous module
  131.19 -        define(['exports'], factory);
  131.20 -    } else {
  131.21 -        // [3] No module loader (plain <script> tag) - put directly in global namespace
  131.22 -        factory(window['ko'] = {});
  131.23 -    }
  131.24 -}(function(koExports){
  131.25 -// Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).
  131.26 -// In the future, the following "ko" variable may be made distinct from "koExports" so that private objects are not externally reachable.
  131.27 -var ko = typeof koExports !== 'undefined' ? koExports : {};
  131.28 -// Google Closure Compiler helpers (used only to make the minified file smaller)
  131.29 -ko.exportSymbol = function(koPath, object) {
  131.30 -	var tokens = koPath.split(".");
  131.31 -
  131.32 -	// In the future, "ko" may become distinct from "koExports" (so that non-exported objects are not reachable)
  131.33 -	// At that point, "target" would be set to: (typeof koExports !== "undefined" ? koExports : ko)
  131.34 -	var target = ko;
  131.35 -
  131.36 -	for (var i = 0; i < tokens.length - 1; i++)
  131.37 -		target = target[tokens[i]];
  131.38 -	target[tokens[tokens.length - 1]] = object;
  131.39 -};
  131.40 -ko.exportProperty = function(owner, publicName, object) {
  131.41 -  owner[publicName] = object;
  131.42 -};
  131.43 -ko.version = "2.2.1";
  131.44 -
  131.45 -ko.exportSymbol('version', ko.version);
  131.46 -ko.utils = new (function () {
  131.47 -    var stringTrimRegex = /^(\s|\u00A0)+|(\s|\u00A0)+$/g;
  131.48 -
  131.49 -    // Represent the known event types in a compact way, then at runtime transform it into a hash with event name as key (for fast lookup)
  131.50 -    var knownEvents = {}, knownEventTypesByEventName = {};
  131.51 -    var keyEventTypeName = /Firefox\/2/i.test(navigator.userAgent) ? 'KeyboardEvent' : 'UIEvents';
  131.52 -    knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];
  131.53 -    knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];
  131.54 -    for (var eventType in knownEvents) {
  131.55 -        var knownEventsForType = knownEvents[eventType];
  131.56 -        if (knownEventsForType.length) {
  131.57 -            for (var i = 0, j = knownEventsForType.length; i < j; i++)
  131.58 -                knownEventTypesByEventName[knownEventsForType[i]] = eventType;
  131.59 -        }
  131.60 -    }
  131.61 -    var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406
  131.62 -
  131.63 -    // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)
  131.64 -    // Note that, since IE 10 does not support conditional comments, the following logic only detects IE < 10.
  131.65 -    // Currently this is by design, since IE 10+ behaves correctly when treated as a standard browser.
  131.66 -    // If there is a future need to detect specific versions of IE10+, we will amend this.
  131.67 -    var ieVersion = (function() {
  131.68 -        var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');
  131.69 -
  131.70 -        // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment
  131.71 -        while (
  131.72 -            div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',
  131.73 -            iElems[0]
  131.74 -        );
  131.75 -        return version > 4 ? version : undefined;
  131.76 -    }());
  131.77 -    var isIe6 = ieVersion === 6,
  131.78 -        isIe7 = ieVersion === 7;
  131.79 -
  131.80 -    function isClickOnCheckableElement(element, eventType) {
  131.81 -        if ((ko.utils.tagNameLower(element) !== "input") || !element.type) return false;
  131.82 -        if (eventType.toLowerCase() != "click") return false;
  131.83 -        var inputType = element.type;
  131.84 -        return (inputType == "checkbox") || (inputType == "radio");
  131.85 -    }
  131.86 -
  131.87 -    return {
  131.88 -        fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
  131.89 -
  131.90 -        arrayForEach: function (array, action) {
  131.91 -            for (var i = 0, j = array.length; i < j; i++)
  131.92 -                action(array[i]);
  131.93 -        },
  131.94 -
  131.95 -        arrayIndexOf: function (array, item) {
  131.96 -            if (typeof Array.prototype.indexOf == "function")
  131.97 -                return Array.prototype.indexOf.call(array, item);
  131.98 -            for (var i = 0, j = array.length; i < j; i++)
  131.99 -                if (array[i] === item)
 131.100 -                    return i;
 131.101 -            return -1;
 131.102 -        },
 131.103 -
 131.104 -        arrayFirst: function (array, predicate, predicateOwner) {
 131.105 -            for (var i = 0, j = array.length; i < j; i++)
 131.106 -                if (predicate.call(predicateOwner, array[i]))
 131.107 -                    return array[i];
 131.108 -            return null;
 131.109 -        },
 131.110 -
 131.111 -        arrayRemoveItem: function (array, itemToRemove) {
 131.112 -            var index = ko.utils.arrayIndexOf(array, itemToRemove);
 131.113 -            if (index >= 0)
 131.114 -                array.splice(index, 1);
 131.115 -        },
 131.116 -
 131.117 -        arrayGetDistinctValues: function (array) {
 131.118 -            array = array || [];
 131.119 -            var result = [];
 131.120 -            for (var i = 0, j = array.length; i < j; i++) {
 131.121 -                if (ko.utils.arrayIndexOf(result, array[i]) < 0)
 131.122 -                    result.push(array[i]);
 131.123 -            }
 131.124 -            return result;
 131.125 -        },
 131.126 -
 131.127 -        arrayMap: function (array, mapping) {
 131.128 -            array = array || [];
 131.129 -            var result = [];
 131.130 -            for (var i = 0, j = array.length; i < j; i++)
 131.131 -                result.push(mapping(array[i]));
 131.132 -            return result;
 131.133 -        },
 131.134 -
 131.135 -        arrayFilter: function (array, predicate) {
 131.136 -            array = array || [];
 131.137 -            var result = [];
 131.138 -            for (var i = 0, j = array.length; i < j; i++)
 131.139 -                if (predicate(array[i]))
 131.140 -                    result.push(array[i]);
 131.141 -            return result;
 131.142 -        },
 131.143 -
 131.144 -        arrayPushAll: function (array, valuesToPush) {
 131.145 -            if (valuesToPush instanceof Array)
 131.146 -                array.push.apply(array, valuesToPush);
 131.147 -            else
 131.148 -                for (var i = 0, j = valuesToPush.length; i < j; i++)
 131.149 -                    array.push(valuesToPush[i]);
 131.150 -            return array;
 131.151 -        },
 131.152 -
 131.153 -        extend: function (target, source) {
 131.154 -            if (source) {
 131.155 -                for(var prop in source) {
 131.156 -                    if(source.hasOwnProperty(prop)) {
 131.157 -                        target[prop] = source[prop];
 131.158 -                    }
 131.159 -                }
 131.160 -            }
 131.161 -            return target;
 131.162 -        },
 131.163 -
 131.164 -        emptyDomNode: function (domNode) {
 131.165 -            while (domNode.firstChild) {
 131.166 -                ko.removeNode(domNode.firstChild);
 131.167 -            }
 131.168 -        },
 131.169 -
 131.170 -        moveCleanedNodesToContainerElement: function(nodes) {
 131.171 -            // Ensure it's a real array, as we're about to reparent the nodes and
 131.172 -            // we don't want the underlying collection to change while we're doing that.
 131.173 -            var nodesArray = ko.utils.makeArray(nodes);
 131.174 -
 131.175 -            var container = document.createElement('div');
 131.176 -            for (var i = 0, j = nodesArray.length; i < j; i++) {
 131.177 -                container.appendChild(ko.cleanNode(nodesArray[i]));
 131.178 -            }
 131.179 -            return container;
 131.180 -        },
 131.181 -
 131.182 -        cloneNodes: function (nodesArray, shouldCleanNodes) {
 131.183 -            for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {
 131.184 -                var clonedNode = nodesArray[i].cloneNode(true);
 131.185 -                newNodesArray.push(shouldCleanNodes ? ko.cleanNode(clonedNode) : clonedNode);
 131.186 -            }
 131.187 -            return newNodesArray;
 131.188 -        },
 131.189 -
 131.190 -        setDomNodeChildren: function (domNode, childNodes) {
 131.191 -            ko.utils.emptyDomNode(domNode);
 131.192 -            if (childNodes) {
 131.193 -                for (var i = 0, j = childNodes.length; i < j; i++)
 131.194 -                    domNode.appendChild(childNodes[i]);
 131.195 -            }
 131.196 -        },
 131.197 -
 131.198 -        replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {
 131.199 -            var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;
 131.200 -            if (nodesToReplaceArray.length > 0) {
 131.201 -                var insertionPoint = nodesToReplaceArray[0];
 131.202 -                var parent = insertionPoint.parentNode;
 131.203 -                for (var i = 0, j = newNodesArray.length; i < j; i++)
 131.204 -                    parent.insertBefore(newNodesArray[i], insertionPoint);
 131.205 -                for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {
 131.206 -                    ko.removeNode(nodesToReplaceArray[i]);
 131.207 -                }
 131.208 -            }
 131.209 -        },
 131.210 -
 131.211 -        setOptionNodeSelectionState: function (optionNode, isSelected) {
 131.212 -            // IE6 sometimes throws "unknown error" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.
 131.213 -            if (ieVersion < 7)
 131.214 -                optionNode.setAttribute("selected", isSelected);
 131.215 -            else
 131.216 -                optionNode.selected = isSelected;
 131.217 -        },
 131.218 -
 131.219 -        stringTrim: function (string) {
 131.220 -            return (string || "").replace(stringTrimRegex, "");
 131.221 -        },
 131.222 -
 131.223 -        stringTokenize: function (string, delimiter) {
 131.224 -            var result = [];
 131.225 -            var tokens = (string || "").split(delimiter);
 131.226 -            for (var i = 0, j = tokens.length; i < j; i++) {
 131.227 -                var trimmed = ko.utils.stringTrim(tokens[i]);
 131.228 -                if (trimmed !== "")
 131.229 -                    result.push(trimmed);
 131.230 -            }
 131.231 -            return result;
 131.232 -        },
 131.233 -
 131.234 -        stringStartsWith: function (string, startsWith) {
 131.235 -            string = string || "";
 131.236 -            if (startsWith.length > string.length)
 131.237 -                return false;
 131.238 -            return string.substring(0, startsWith.length) === startsWith;
 131.239 -        },
 131.240 -
 131.241 -        domNodeIsContainedBy: function (node, containedByNode) {
 131.242 -            if (containedByNode.compareDocumentPosition)
 131.243 -                return (containedByNode.compareDocumentPosition(node) & 16) == 16;
 131.244 -            while (node != null) {
 131.245 -                if (node == containedByNode)
 131.246 -                    return true;
 131.247 -                node = node.parentNode;
 131.248 -            }
 131.249 -            return false;
 131.250 -        },
 131.251 -
 131.252 -        domNodeIsAttachedToDocument: function (node) {
 131.253 -            return ko.utils.domNodeIsContainedBy(node, node.ownerDocument);
 131.254 -        },
 131.255 -
 131.256 -        tagNameLower: function(element) {
 131.257 -            // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
 131.258 -            // Possible future optimization: If we know it's an element from an XHTML document (not HTML),
 131.259 -            // we don't need to do the .toLowerCase() as it will always be lower case anyway.
 131.260 -            return element && element.tagName && element.tagName.toLowerCase();
 131.261 -        },
 131.262 -
 131.263 -        registerEventHandler: function (element, eventType, handler) {
 131.264 -            var mustUseAttachEvent = ieVersion && eventsThatMustBeRegisteredUsingAttachEvent[eventType];
 131.265 -            if (!mustUseAttachEvent && typeof jQuery != "undefined") {
 131.266 -                if (isClickOnCheckableElement(element, eventType)) {
 131.267 -                    // For click events on checkboxes, jQuery interferes with the event handling in an awkward way:
 131.268 -                    // it toggles the element checked state *after* the click event handlers run, whereas native
 131.269 -                    // click events toggle the checked state *before* the event handler.
 131.270 -                    // Fix this by intecepting the handler and applying the correct checkedness before it runs.
 131.271 -                    var originalHandler = handler;
 131.272 -                    handler = function(event, eventData) {
 131.273 -                        var jQuerySuppliedCheckedState = this.checked;
 131.274 -                        if (eventData)
 131.275 -                            this.checked = eventData.checkedStateBeforeEvent !== true;
 131.276 -                        originalHandler.call(this, event);
 131.277 -                        this.checked = jQuerySuppliedCheckedState; // Restore the state jQuery applied
 131.278 -                    };
 131.279 -                }
 131.280 -                jQuery(element)['bind'](eventType, handler);
 131.281 -            } else if (!mustUseAttachEvent && typeof element.addEventListener == "function")
 131.282 -                element.addEventListener(eventType, handler, false);
 131.283 -            else if (typeof element.attachEvent != "undefined")
 131.284 -                element.attachEvent("on" + eventType, function (event) {
 131.285 -                    handler.call(element, event);
 131.286 -                });
 131.287 -            else
 131.288 -                throw new Error("Browser doesn't support addEventListener or attachEvent");
 131.289 -        },
 131.290 -
 131.291 -        triggerEvent: function (element, eventType) {
 131.292 -            if (!(element && element.nodeType))
 131.293 -                throw new Error("element must be a DOM node when calling triggerEvent");
 131.294 -
 131.295 -            if (typeof jQuery != "undefined") {
 131.296 -                var eventData = [];
 131.297 -                if (isClickOnCheckableElement(element, eventType)) {
 131.298 -                    // Work around the jQuery "click events on checkboxes" issue described above by storing the original checked state before triggering the handler
 131.299 -                    eventData.push({ checkedStateBeforeEvent: element.checked });
 131.300 -                }
 131.301 -                jQuery(element)['trigger'](eventType, eventData);
 131.302 -            } else if (typeof document.createEvent == "function") {
 131.303 -                if (typeof element.dispatchEvent == "function") {
 131.304 -                    var eventCategory = knownEventTypesByEventName[eventType] || "HTMLEvents";
 131.305 -                    var event = document.createEvent(eventCategory);
 131.306 -                    event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);
 131.307 -                    element.dispatchEvent(event);
 131.308 -                }
 131.309 -                else
 131.310 -                    throw new Error("The supplied element doesn't support dispatchEvent");
 131.311 -            } else if (typeof element.fireEvent != "undefined") {
 131.312 -                // Unlike other browsers, IE doesn't change the checked state of checkboxes/radiobuttons when you trigger their "click" event
 131.313 -                // so to make it consistent, we'll do it manually here
 131.314 -                if (isClickOnCheckableElement(element, eventType))
 131.315 -                    element.checked = element.checked !== true;
 131.316 -                element.fireEvent("on" + eventType);
 131.317 -            }
 131.318 -            else
 131.319 -                throw new Error("Browser doesn't support triggering events");
 131.320 -        },
 131.321 -
 131.322 -        unwrapObservable: function (value) {
 131.323 -            return ko.isObservable(value) ? value() : value;
 131.324 -        },
 131.325 -
 131.326 -        peekObservable: function (value) {
 131.327 -            return ko.isObservable(value) ? value.peek() : value;
 131.328 -        },
 131.329 -
 131.330 -        toggleDomNodeCssClass: function (node, classNames, shouldHaveClass) {
 131.331 -            if (classNames) {
 131.332 -                var cssClassNameRegex = /[\w-]+/g,
 131.333 -                    currentClassNames = node.className.match(cssClassNameRegex) || [];
 131.334 -                ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
 131.335 -                    var indexOfClass = ko.utils.arrayIndexOf(currentClassNames, className);
 131.336 -                    if (indexOfClass >= 0) {
 131.337 -                        if (!shouldHaveClass)
 131.338 -                            currentClassNames.splice(indexOfClass, 1);
 131.339 -                    } else {
 131.340 -                        if (shouldHaveClass)
 131.341 -                            currentClassNames.push(className);
 131.342 -                    }
 131.343 -                });
 131.344 -                node.className = currentClassNames.join(" ");
 131.345 -            }
 131.346 -        },
 131.347 -
 131.348 -        setTextContent: function(element, textContent) {
 131.349 -            var value = ko.utils.unwrapObservable(textContent);
 131.350 -            if ((value === null) || (value === undefined))
 131.351 -                value = "";
 131.352 -
 131.353 -            if (element.nodeType === 3) {
 131.354 -                element.data = value;
 131.355 -            } else {
 131.356 -                // We need there to be exactly one child: a text node.
 131.357 -                // If there are no children, more than one, or if it's not a text node,
 131.358 -                // we'll clear everything and create a single text node.
 131.359 -                var innerTextNode = ko.virtualElements.firstChild(element);
 131.360 -                if (!innerTextNode || innerTextNode.nodeType != 3 || ko.virtualElements.nextSibling(innerTextNode)) {
 131.361 -                    ko.virtualElements.setDomNodeChildren(element, [document.createTextNode(value)]);
 131.362 -                } else {
 131.363 -                    innerTextNode.data = value;
 131.364 -                }
 131.365 -
 131.366 -                ko.utils.forceRefresh(element);
 131.367 -            }
 131.368 -        },
 131.369 -
 131.370 -        setElementName: function(element, name) {
 131.371 -            element.name = name;
 131.372 -
 131.373 -            // Workaround IE 6/7 issue
 131.374 -            // - https://github.com/SteveSanderson/knockout/issues/197
 131.375 -            // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/
 131.376 -            if (ieVersion <= 7) {
 131.377 -                try {
 131.378 -                    element.mergeAttributes(document.createElement("<input name='" + element.name + "'/>"), false);
 131.379 -                }
 131.380 -                catch(e) {} // For IE9 with doc mode "IE9 Standards" and browser mode "IE9 Compatibility View"
 131.381 -            }
 131.382 -        },
 131.383 -
 131.384 -        forceRefresh: function(node) {
 131.385 -            // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209
 131.386 -            if (ieVersion >= 9) {
 131.387 -                // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container
 131.388 -                var elem = node.nodeType == 1 ? node : node.parentNode;
 131.389 -                if (elem.style)
 131.390 -                    elem.style.zoom = elem.style.zoom;
 131.391 -            }
 131.392 -        },
 131.393 -
 131.394 -        ensureSelectElementIsRenderedCorrectly: function(selectElement) {
 131.395 -            // Workaround for IE9 rendering bug - it doesn't reliably display all the text in dynamically-added select boxes unless you force it to re-render by updating the width.
 131.396 -            // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)
 131.397 -            if (ieVersion >= 9) {
 131.398 -                var originalWidth = selectElement.style.width;
 131.399 -                selectElement.style.width = 0;
 131.400 -                selectElement.style.width = originalWidth;
 131.401 -            }
 131.402 -        },
 131.403 -
 131.404 -        range: function (min, max) {
 131.405 -            min = ko.utils.unwrapObservable(min);
 131.406 -            max = ko.utils.unwrapObservable(max);
 131.407 -            var result = [];
 131.408 -            for (var i = min; i <= max; i++)
 131.409 -                result.push(i);
 131.410 -            return result;
 131.411 -        },
 131.412 -
 131.413 -        makeArray: function(arrayLikeObject) {
 131.414 -            var result = [];
 131.415 -            for (var i = 0, j = arrayLikeObject.length; i < j; i++) {
 131.416 -                result.push(arrayLikeObject[i]);
 131.417 -            };
 131.418 -            return result;
 131.419 -        },
 131.420 -
 131.421 -        isIe6 : isIe6,
 131.422 -        isIe7 : isIe7,
 131.423 -        ieVersion : ieVersion,
 131.424 -
 131.425 -        getFormFields: function(form, fieldName) {
 131.426 -            var fields = ko.utils.makeArray(form.getElementsByTagName("input")).concat(ko.utils.makeArray(form.getElementsByTagName("textarea")));
 131.427 -            var isMatchingField = (typeof fieldName == 'string')
 131.428 -                ? function(field) { return field.name === fieldName }
 131.429 -                : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate
 131.430 -            var matches = [];
 131.431 -            for (var i = fields.length - 1; i >= 0; i--) {
 131.432 -                if (isMatchingField(fields[i]))
 131.433 -                    matches.push(fields[i]);
 131.434 -            };
 131.435 -            return matches;
 131.436 -        },
 131.437 -
 131.438 -        parseJson: function (jsonString) {
 131.439 -            if (typeof jsonString == "string") {
 131.440 -                jsonString = ko.utils.stringTrim(jsonString);
 131.441 -                if (jsonString) {
 131.442 -                    if (window.JSON && window.JSON.parse) // Use native parsing where available
 131.443 -                        return window.JSON.parse(jsonString);
 131.444 -                    return (new Function("return " + jsonString))(); // Fallback on less safe parsing for older browsers
 131.445 -                }
 131.446 -            }
 131.447 -            return null;
 131.448 -        },
 131.449 -
 131.450 -        stringifyJson: function (data, replacer, space) {   // replacer and space are optional
 131.451 -            if ((typeof JSON == "undefined") || (typeof JSON.stringify == "undefined"))
 131.452 -                throw new Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
 131.453 -            return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);
 131.454 -        },
 131.455 -
 131.456 -        postJson: function (urlOrForm, data, options) {
 131.457 -            options = options || {};
 131.458 -            var params = options['params'] || {};
 131.459 -            var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;
 131.460 -            var url = urlOrForm;
 131.461 -
 131.462 -            // If we were given a form, use its 'action' URL and pick out any requested field values
 131.463 -            if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === "form")) {
 131.464 -                var originalForm = urlOrForm;
 131.465 -                url = originalForm.action;
 131.466 -                for (var i = includeFields.length - 1; i >= 0; i--) {
 131.467 -                    var fields = ko.utils.getFormFields(originalForm, includeFields[i]);
 131.468 -                    for (var j = fields.length - 1; j >= 0; j--)
 131.469 -                        params[fields[j].name] = fields[j].value;
 131.470 -                }
 131.471 -            }
 131.472 -
 131.473 -            data = ko.utils.unwrapObservable(data);
 131.474 -            var form = document.createElement("form");
 131.475 -            form.style.display = "none";
 131.476 -            form.action = url;
 131.477 -            form.method = "post";
 131.478 -            for (var key in data) {
 131.479 -                var input = document.createElement("input");
 131.480 -                input.name = key;
 131.481 -                input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));
 131.482 -                form.appendChild(input);
 131.483 -            }
 131.484 -            for (var key in params) {
 131.485 -                var input = document.createElement("input");
 131.486 -                input.name = key;
 131.487 -                input.value = params[key];
 131.488 -                form.appendChild(input);
 131.489 -            }
 131.490 -            document.body.appendChild(form);
 131.491 -            options['submitter'] ? options['submitter'](form) : form.submit();
 131.492 -            setTimeout(function () { form.parentNode.removeChild(form); }, 0);
 131.493 -        }
 131.494 -    }
 131.495 -})();
 131.496 -
 131.497 -ko.exportSymbol('utils', ko.utils);
 131.498 -ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);
 131.499 -ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);
 131.500 -ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);
 131.501 -ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);
 131.502 -ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);
 131.503 -ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);
 131.504 -ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);
 131.505 -ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);
 131.506 -ko.exportSymbol('utils.extend', ko.utils.extend);
 131.507 -ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);
 131.508 -ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);
 131.509 -ko.exportSymbol('utils.peekObservable', ko.utils.peekObservable);
 131.510 -ko.exportSymbol('utils.postJson', ko.utils.postJson);
 131.511 -ko.exportSymbol('utils.parseJson', ko.utils.parseJson);
 131.512 -ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);
 131.513 -ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);
 131.514 -ko.exportSymbol('utils.range', ko.utils.range);
 131.515 -ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);
 131.516 -ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);
 131.517 -ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);
 131.518 -
 131.519 -if (!Function.prototype['bind']) {
 131.520 -    // Function.prototype.bind is a standard part of ECMAScript 5th Edition (December 2009, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf)
 131.521 -    // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js
 131.522 -    Function.prototype['bind'] = function (object) {
 131.523 -        var originalFunction = this, args = Array.prototype.slice.call(arguments), object = args.shift();
 131.524 -        return function () {
 131.525 -            return originalFunction.apply(object, args.concat(Array.prototype.slice.call(arguments)));
 131.526 -        };
 131.527 -    };
 131.528 -}
 131.529 -
 131.530 -ko.utils.domData = new (function () {
 131.531 -    var uniqueId = 0;
 131.532 -    var dataStoreKeyExpandoPropertyName = "__ko__" + (new Date).getTime();
 131.533 -    var dataStore = {};
 131.534 -    return {
 131.535 -        get: function (node, key) {
 131.536 -            var allDataForNode = ko.utils.domData.getAll(node, false);
 131.537 -            return allDataForNode === undefined ? undefined : allDataForNode[key];
 131.538 -        },
 131.539 -        set: function (node, key, value) {
 131.540 -            if (value === undefined) {
 131.541 -                // Make sure we don't actually create a new domData key if we are actually deleting a value
 131.542 -                if (ko.utils.domData.getAll(node, false) === undefined)
 131.543 -                    return;
 131.544 -            }
 131.545 -            var allDataForNode = ko.utils.domData.getAll(node, true);
 131.546 -            allDataForNode[key] = value;
 131.547 -        },
 131.548 -        getAll: function (node, createIfNotFound) {
 131.549 -            var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
 131.550 -            var hasExistingDataStore = dataStoreKey && (dataStoreKey !== "null") && dataStore[dataStoreKey];
 131.551 -            if (!hasExistingDataStore) {
 131.552 -                if (!createIfNotFound)
 131.553 -                    return undefined;
 131.554 -                dataStoreKey = node[dataStoreKeyExpandoPropertyName] = "ko" + uniqueId++;
 131.555 -                dataStore[dataStoreKey] = {};
 131.556 -            }
 131.557 -            return dataStore[dataStoreKey];
 131.558 -        },
 131.559 -        clear: function (node) {
 131.560 -            var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
 131.561 -            if (dataStoreKey) {
 131.562 -                delete dataStore[dataStoreKey];
 131.563 -                node[dataStoreKeyExpandoPropertyName] = null;
 131.564 -                return true; // Exposing "did clean" flag purely so specs can infer whether things have been cleaned up as intended
 131.565 -            }
 131.566 -            return false;
 131.567 -        }
 131.568 -    }
 131.569 -})();
 131.570 -
 131.571 -ko.exportSymbol('utils.domData', ko.utils.domData);
 131.572 -ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully
 131.573 -
 131.574 -ko.utils.domNodeDisposal = new (function () {
 131.575 -    var domDataKey = "__ko_domNodeDisposal__" + (new Date).getTime();
 131.576 -    var cleanableNodeTypes = { 1: true, 8: true, 9: true };       // Element, Comment, Document
 131.577 -    var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document
 131.578 -
 131.579 -    function getDisposeCallbacksCollection(node, createIfNotFound) {
 131.580 -        var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);
 131.581 -        if ((allDisposeCallbacks === undefined) && createIfNotFound) {
 131.582 -            allDisposeCallbacks = [];
 131.583 -            ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);
 131.584 -        }
 131.585 -        return allDisposeCallbacks;
 131.586 -    }
 131.587 -    function destroyCallbacksCollection(node) {
 131.588 -        ko.utils.domData.set(node, domDataKey, undefined);
 131.589 -    }
 131.590 -
 131.591 -    function cleanSingleNode(node) {
 131.592 -        // Run all the dispose callbacks
 131.593 -        var callbacks = getDisposeCallbacksCollection(node, false);
 131.594 -        if (callbacks) {
 131.595 -            callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)
 131.596 -            for (var i = 0; i < callbacks.length; i++)
 131.597 -                callbacks[i](node);
 131.598 -        }
 131.599 -
 131.600 -        // Also erase the DOM data
 131.601 -        ko.utils.domData.clear(node);
 131.602 -
 131.603 -        // Special support for jQuery here because it's so commonly used.
 131.604 -        // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData
 131.605 -        // so notify it to tear down any resources associated with the node & descendants here.
 131.606 -        if ((typeof jQuery == "function") && (typeof jQuery['cleanData'] == "function"))
 131.607 -            jQuery['cleanData']([node]);
 131.608 -
 131.609 -        // Also clear any immediate-child comment nodes, as these wouldn't have been found by
 131.610 -        // node.getElementsByTagName("*") in cleanNode() (comment nodes aren't elements)
 131.611 -        if (cleanableNodeTypesWithDescendants[node.nodeType])
 131.612 -            cleanImmediateCommentTypeChildren(node);
 131.613 -    }
 131.614 -
 131.615 -    function cleanImmediateCommentTypeChildren(nodeWithChildren) {
 131.616 -        var child, nextChild = nodeWithChildren.firstChild;
 131.617 -        while (child = nextChild) {
 131.618 -            nextChild = child.nextSibling;
 131.619 -            if (child.nodeType === 8)
 131.620 -                cleanSingleNode(child);
 131.621 -        }
 131.622 -    }
 131.623 -
 131.624 -    return {
 131.625 -        addDisposeCallback : function(node, callback) {
 131.626 -            if (typeof callback != "function")
 131.627 -                throw new Error("Callback must be a function");
 131.628 -            getDisposeCallbacksCollection(node, true).push(callback);
 131.629 -        },
 131.630 -
 131.631 -        removeDisposeCallback : function(node, callback) {
 131.632 -            var callbacksCollection = getDisposeCallbacksCollection(node, false);
 131.633 -            if (callbacksCollection) {
 131.634 -                ko.utils.arrayRemoveItem(callbacksCollection, callback);
 131.635 -                if (callbacksCollection.length == 0)
 131.636 -                    destroyCallbacksCollection(node);
 131.637 -            }
 131.638 -        },
 131.639 -
 131.640 -        cleanNode : function(node) {
 131.641 -            // First clean this node, where applicable
 131.642 -            if (cleanableNodeTypes[node.nodeType]) {
 131.643 -                cleanSingleNode(node);
 131.644 -
 131.645 -                // ... then its descendants, where applicable
 131.646 -                if (cleanableNodeTypesWithDescendants[node.nodeType]) {
 131.647 -                    // Clone the descendants list in case it changes during iteration
 131.648 -                    var descendants = [];
 131.649 -                    ko.utils.arrayPushAll(descendants, node.getElementsByTagName("*"));
 131.650 -                    for (var i = 0, j = descendants.length; i < j; i++)
 131.651 -                        cleanSingleNode(descendants[i]);
 131.652 -                }
 131.653 -            }
 131.654 -            return node;
 131.655 -        },
 131.656 -
 131.657 -        removeNode : function(node) {
 131.658 -            ko.cleanNode(node);
 131.659 -            if (node.parentNode)
 131.660 -                node.parentNode.removeChild(node);
 131.661 -        }
 131.662 -    }
 131.663 -})();
 131.664 -ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience
 131.665 -ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience
 131.666 -ko.exportSymbol('cleanNode', ko.cleanNode);
 131.667 -ko.exportSymbol('removeNode', ko.removeNode);
 131.668 -ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);
 131.669 -ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);
 131.670 -ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);
 131.671 -(function () {
 131.672 -    var leadingCommentRegex = /^(\s*)<!--(.*?)-->/;
 131.673 -
 131.674 -    function simpleHtmlParse(html) {
 131.675 -        // Based on jQuery's "clean" function, but only accounting for table-related elements.
 131.676 -        // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's "clean" function directly
 131.677 -
 131.678 -        // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of
 131.679 -        // a descendant node. For example: "<div><!-- mycomment -->abc</div>" will get parsed as "<div>abc</div>"
 131.680 -        // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node
 131.681 -        // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.
 131.682 -
 131.683 -        // Trim whitespace, otherwise indexOf won't work as expected
 131.684 -        var tags = ko.utils.stringTrim(html).toLowerCase(), div = document.createElement("div");
 131.685 -
 131.686 -        // Finds the first match from the left column, and returns the corresponding "wrap" data from the right column
 131.687 -        var wrap = tags.match(/^<(thead|tbody|tfoot)/)              && [1, "<table>", "</table>"] ||
 131.688 -                   !tags.indexOf("<tr")                             && [2, "<table><tbody>", "</tbody></table>"] ||
 131.689 -                   (!tags.indexOf("<td") || !tags.indexOf("<th"))   && [3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
 131.690 -                   /* anything else */                                 [0, "", ""];
 131.691 -
 131.692 -        // Go to html and back, then peel off extra wrappers
 131.693 -        // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
 131.694 -        var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
 131.695 -        if (typeof window['innerShiv'] == "function") {
 131.696 -            div.appendChild(window['innerShiv'](markup));
 131.697 -        } else {
 131.698 -            div.innerHTML = markup;
 131.699 -        }
 131.700 -
 131.701 -        // Move to the right depth
 131.702 -        while (wrap[0]--)
 131.703 -            div = div.lastChild;
 131.704 -
 131.705 -        return ko.utils.makeArray(div.lastChild.childNodes);
 131.706 -    }
 131.707 -
 131.708 -    function jQueryHtmlParse(html) {
 131.709 -        // jQuery's "parseHTML" function was introduced in jQuery 1.8.0 and is a documented public API.
 131.710 -        if (jQuery['parseHTML']) {
 131.711 -            return jQuery['parseHTML'](html);
 131.712 -        } else {
 131.713 -            // For jQuery < 1.8.0, we fall back on the undocumented internal "clean" function.
 131.714 -            var elems = jQuery['clean']([html]);
 131.715 -
 131.716 -            // As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment.
 131.717 -            // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.
 131.718 -            // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.
 131.719 -            if (elems && elems[0]) {
 131.720 -                // Find the top-most parent element that's a direct child of a document fragment
 131.721 -                var elem = elems[0];
 131.722 -                while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)
 131.723 -                    elem = elem.parentNode;
 131.724 -                // ... then detach it
 131.725 -                if (elem.parentNode)
 131.726 -                    elem.parentNode.removeChild(elem);
 131.727 -            }
 131.728 -
 131.729 -            return elems;
 131.730 -        }
 131.731 -    }
 131.732 -
 131.733 -    ko.utils.parseHtmlFragment = function(html) {
 131.734 -        return typeof jQuery != 'undefined' ? jQueryHtmlParse(html)   // As below, benefit from jQuery's optimisations where possible
 131.735 -                                            : simpleHtmlParse(html);  // ... otherwise, this simple logic will do in most common cases.
 131.736 -    };
 131.737 -
 131.738 -    ko.utils.setHtml = function(node, html) {
 131.739 -        ko.utils.emptyDomNode(node);
 131.740 -
 131.741 -        // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it
 131.742 -        html = ko.utils.unwrapObservable(html);
 131.743 -
 131.744 -        if ((html !== null) && (html !== undefined)) {
 131.745 -            if (typeof html != 'string')
 131.746 -                html = html.toString();
 131.747 -
 131.748 -            // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,
 131.749 -            // for example <tr> elements which are not normally allowed to exist on their own.
 131.750 -            // If you've referenced jQuery we'll use that rather than duplicating its code.
 131.751 -            if (typeof jQuery != 'undefined') {
 131.752 -                jQuery(node)['html'](html);
 131.753 -            } else {
 131.754 -                // ... otherwise, use KO's own parsing logic.
 131.755 -                var parsedNodes = ko.utils.parseHtmlFragment(html);
 131.756 -                for (var i = 0; i < parsedNodes.length; i++)
 131.757 -                    node.appendChild(parsedNodes[i]);
 131.758 -            }
 131.759 -        }
 131.760 -    };
 131.761 -})();
 131.762 -
 131.763 -ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);
 131.764 -ko.exportSymbol('utils.setHtml', ko.utils.setHtml);
 131.765 -
 131.766 -ko.memoization = (function () {
 131.767 -    var memos = {};
 131.768 -
 131.769 -    function randomMax8HexChars() {
 131.770 -        return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
 131.771 -    }
 131.772 -    function generateRandomId() {
 131.773 -        return randomMax8HexChars() + randomMax8HexChars();
 131.774 -    }
 131.775 -    function findMemoNodes(rootNode, appendToArray) {
 131.776 -        if (!rootNode)
 131.777 -            return;
 131.778 -        if (rootNode.nodeType == 8) {
 131.779 -            var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);
 131.780 -            if (memoId != null)
 131.781 -                appendToArray.push({ domNode: rootNode, memoId: memoId });
 131.782 -        } else if (rootNode.nodeType == 1) {
 131.783 -            for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)
 131.784 -                findMemoNodes(childNodes[i], appendToArray);
 131.785 -        }
 131.786 -    }
 131.787 -
 131.788 -    return {
 131.789 -        memoize: function (callback) {
 131.790 -            if (typeof callback != "function")
 131.791 -                throw new Error("You can only pass a function to ko.memoization.memoize()");
 131.792 -            var memoId = generateRandomId();
 131.793 -            memos[memoId] = callback;
 131.794 -            return "<!--[ko_memo:" + memoId + "]-->";
 131.795 -        },
 131.796 -
 131.797 -        unmemoize: function (memoId, callbackParams) {
 131.798 -            var callback = memos[memoId];
 131.799 -            if (callback === undefined)
 131.800 -                throw new Error("Couldn't find any memo with ID " + memoId + ". Perhaps it's already been unmemoized.");
 131.801 -            try {
 131.802 -                callback.apply(null, callbackParams || []);
 131.803 -                return true;
 131.804 -            }
 131.805 -            finally { delete memos[memoId]; }
 131.806 -        },
 131.807 -
 131.808 -        unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {
 131.809 -            var memos = [];
 131.810 -            findMemoNodes(domNode, memos);
 131.811 -            for (var i = 0, j = memos.length; i < j; i++) {
 131.812 -                var node = memos[i].domNode;
 131.813 -                var combinedParams = [node];
 131.814 -                if (extraCallbackParamsArray)
 131.815 -                    ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);
 131.816 -                ko.memoization.unmemoize(memos[i].memoId, combinedParams);
 131.817 -                node.nodeValue = ""; // Neuter this node so we don't try to unmemoize it again
 131.818 -                if (node.parentNode)
 131.819 -                    node.parentNode.removeChild(node); // If possible, erase it totally (not always possible - someone else might just hold a reference to it then call unmemoizeDomNodeAndDescendants again)
 131.820 -            }
 131.821 -        },
 131.822 -
 131.823 -        parseMemoText: function (memoText) {
 131.824 -            var match = memoText.match(/^\[ko_memo\:(.*?)\]$/);
 131.825 -            return match ? match[1] : null;
 131.826 -        }
 131.827 -    };
 131.828 -})();
 131.829 -
 131.830 -ko.exportSymbol('memoization', ko.memoization);
 131.831 -ko.exportSymbol('memoization.memoize', ko.memoization.memoize);
 131.832 -ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);
 131.833 -ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);
 131.834 -ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);
 131.835 -ko.extenders = {
 131.836 -    'throttle': function(target, timeout) {
 131.837 -        // Throttling means two things:
 131.838 -
 131.839 -        // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
 131.840 -        //     notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
 131.841 -        target['throttleEvaluation'] = timeout;
 131.842 -
 131.843 -        // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
 131.844 -        //     so the target cannot change value synchronously or faster than a certain rate
 131.845 -        var writeTimeoutInstance = null;
 131.846 -        return ko.dependentObservable({
 131.847 -            'read': target,
 131.848 -            'write': function(value) {
 131.849 -                clearTimeout(writeTimeoutInstance);
 131.850 -                writeTimeoutInstance = setTimeout(function() {
 131.851 -                    target(value);
 131.852 -                }, timeout);
 131.853 -            }
 131.854 -        });
 131.855 -    },
 131.856 -
 131.857 -    'notify': function(target, notifyWhen) {
 131.858 -        target["equalityComparer"] = notifyWhen == "always"
 131.859 -            ? function() { return false } // Treat all values as not equal
 131.860 -            : ko.observable["fn"]["equalityComparer"];
 131.861 -        return target;
 131.862 -    }
 131.863 -};
 131.864 -
 131.865 -function applyExtenders(requestedExtenders) {
 131.866 -    var target = this;
 131.867 -    if (requestedExtenders) {
 131.868 -        for (var key in requestedExtenders) {
 131.869 -            var extenderHandler = ko.extenders[key];
 131.870 -            if (typeof extenderHandler == 'function') {
 131.871 -                target = extenderHandler(target, requestedExtenders[key]);
 131.872 -            }
 131.873 -        }
 131.874 -    }
 131.875 -    return target;
 131.876 -}
 131.877 -
 131.878 -ko.exportSymbol('extenders', ko.extenders);
 131.879 -
 131.880 -ko.subscription = function (target, callback, disposeCallback) {
 131.881 -    this.target = target;
 131.882 -    this.callback = callback;
 131.883 -    this.disposeCallback = disposeCallback;
 131.884 -    ko.exportProperty(this, 'dispose', this.dispose);
 131.885 -};
 131.886 -ko.subscription.prototype.dispose = function () {
 131.887 -    this.isDisposed = true;
 131.888 -    this.disposeCallback();
 131.889 -};
 131.890 -
 131.891 -ko.subscribable = function () {
 131.892 -    this._subscriptions = {};
 131.893 -
 131.894 -    ko.utils.extend(this, ko.subscribable['fn']);
 131.895 -    ko.exportProperty(this, 'subscribe', this.subscribe);
 131.896 -    ko.exportProperty(this, 'extend', this.extend);
 131.897 -    ko.exportProperty(this, 'getSubscriptionsCount', this.getSubscriptionsCount);
 131.898 -}
 131.899 -
 131.900 -var defaultEvent = "change";
 131.901 -
 131.902 -ko.subscribable['fn'] = {
 131.903 -    subscribe: function (callback, callbackTarget, event) {
 131.904 -        event = event || defaultEvent;
 131.905 -        var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;
 131.906 -
 131.907 -        var subscription = new ko.subscription(this, boundCallback, function () {
 131.908 -            ko.utils.arrayRemoveItem(this._subscriptions[event], subscription);
 131.909 -        }.bind(this));
 131.910 -
 131.911 -        if (!this._subscriptions[event])
 131.912 -            this._subscriptions[event] = [];
 131.913 -        this._subscriptions[event].push(subscription);
 131.914 -        return subscription;
 131.915 -    },
 131.916 -
 131.917 -    "notifySubscribers": function (valueToNotify, event) {
 131.918 -        event = event || defaultEvent;
 131.919 -        if (this._subscriptions[event]) {
 131.920 -            ko.dependencyDetection.ignore(function() {
 131.921 -                ko.utils.arrayForEach(this._subscriptions[event].slice(0), function (subscription) {
 131.922 -                    // In case a subscription was disposed during the arrayForEach cycle, check
 131.923 -                    // for isDisposed on each subscription before invoking its callback
 131.924 -                    if (subscription && (subscription.isDisposed !== true))
 131.925 -                        subscription.callback(valueToNotify);
 131.926 -                });
 131.927 -            }, this);
 131.928 -        }
 131.929 -    },
 131.930 -
 131.931 -    getSubscriptionsCount: function () {
 131.932 -        var total = 0;
 131.933 -        for (var eventName in this._subscriptions) {
 131.934 -            if (this._subscriptions.hasOwnProperty(eventName))
 131.935 -                total += this._subscriptions[eventName].length;
 131.936 -        }
 131.937 -        return total;
 131.938 -    },
 131.939 -
 131.940 -    extend: applyExtenders
 131.941 -};
 131.942 -
 131.943 -
 131.944 -ko.isSubscribable = function (instance) {
 131.945 -    return typeof instance.subscribe == "function" && typeof instance["notifySubscribers"] == "function";
 131.946 -};
 131.947 -
 131.948 -ko.exportSymbol('subscribable', ko.subscribable);
 131.949 -ko.exportSymbol('isSubscribable', ko.isSubscribable);
 131.950 -
 131.951 -ko.dependencyDetection = (function () {
 131.952 -    var _frames = [];
 131.953 -
 131.954 -    return {
 131.955 -        begin: function (callback) {
 131.956 -            _frames.push({ callback: callback, distinctDependencies:[] });
 131.957 -        },
 131.958 -
 131.959 -        end: function () {
 131.960 -            _frames.pop();
 131.961 -        },
 131.962 -
 131.963 -        registerDependency: function (subscribable) {
 131.964 -            if (!ko.isSubscribable(subscribable))
 131.965 -                throw new Error("Only subscribable things can act as dependencies");
 131.966 -            if (_frames.length > 0) {
 131.967 -                var topFrame = _frames[_frames.length - 1];
 131.968 -                if (!topFrame || ko.utils.arrayIndexOf(topFrame.distinctDependencies, subscribable) >= 0)
 131.969 -                    return;
 131.970 -                topFrame.distinctDependencies.push(subscribable);
 131.971 -                topFrame.callback(subscribable);
 131.972 -            }
 131.973 -        },
 131.974 -
 131.975 -        ignore: function(callback, callbackTarget, callbackArgs) {
 131.976 -            try {
 131.977 -                _frames.push(null);
 131.978 -                return callback.apply(callbackTarget, callbackArgs || []);
 131.979 -            } finally {
 131.980 -                _frames.pop();
 131.981 -            }
 131.982 -        }
 131.983 -    };
 131.984 -})();
 131.985 -var primitiveTypes = { 'undefined':true, 'boolean':true, 'number':true, 'string':true };
 131.986 -
 131.987 -ko.observable = function (initialValue) {
 131.988 -    var _latestValue = initialValue;
 131.989 -
 131.990 -    function observable() {
 131.991 -        if (arguments.length > 0) {
 131.992 -            // Write
 131.993 -
 131.994 -            // Ignore writes if the value hasn't changed
 131.995 -            if ((!observable['equalityComparer']) || !observable['equalityComparer'](_latestValue, arguments[0])) {
 131.996 -                observable.valueWillMutate();
 131.997 -                _latestValue = arguments[0];
 131.998 -                if (DEBUG) observable._latestValue = _latestValue;
 131.999 -                observable.valueHasMutated();
131.1000 -            }
131.1001 -            return this; // Permits chained assignments
131.1002 -        }
131.1003 -        else {
131.1004 -            // Read
131.1005 -            ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
131.1006 -            return _latestValue;
131.1007 -        }
131.1008 -    }
131.1009 -    if (DEBUG) observable._latestValue = _latestValue;
131.1010 -    ko.subscribable.call(observable);
131.1011 -    observable.peek = function() { return _latestValue };
131.1012 -    observable.valueHasMutated = function () { observable["notifySubscribers"](_latestValue); }
131.1013 -    observable.valueWillMutate = function () { observable["notifySubscribers"](_latestValue, "beforeChange"); }
131.1014 -    ko.utils.extend(observable, ko.observable['fn']);
131.1015 -
131.1016 -    ko.exportProperty(observable, 'peek', observable.peek);
131.1017 -    ko.exportProperty(observable, "valueHasMutated", observable.valueHasMutated);
131.1018 -    ko.exportProperty(observable, "valueWillMutate", observable.valueWillMutate);
131.1019 -
131.1020 -    return observable;
131.1021 -}
131.1022 -
131.1023 -ko.observable['fn'] = {
131.1024 -    "equalityComparer": function valuesArePrimitiveAndEqual(a, b) {
131.1025 -        var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);
131.1026 -        return oldValueIsPrimitive ? (a === b) : false;
131.1027 -    }
131.1028 -};
131.1029 -
131.1030 -var protoProperty = ko.observable.protoProperty = "__ko_proto__";
131.1031 -ko.observable['fn'][protoProperty] = ko.observable;
131.1032 -
131.1033 -ko.hasPrototype = function(instance, prototype) {
131.1034 -    if ((instance === null) || (instance === undefined) || (instance[protoProperty] === undefined)) return false;
131.1035 -    if (instance[protoProperty] === prototype) return true;
131.1036 -    return ko.hasPrototype(instance[protoProperty], prototype); // Walk the prototype chain
131.1037 -};
131.1038 -
131.1039 -ko.isObservable = function (instance) {
131.1040 -    return ko.hasPrototype(instance, ko.observable);
131.1041 -}
131.1042 -ko.isWriteableObservable = function (instance) {
131.1043 -    // Observable
131.1044 -    if ((typeof instance == "function") && instance[protoProperty] === ko.observable)
131.1045 -        return true;
131.1046 -    // Writeable dependent observable
131.1047 -    if ((typeof instance == "function") && (instance[protoProperty] === ko.dependentObservable) && (instance.hasWriteFunction))
131.1048 -        return true;
131.1049 -    // Anything else
131.1050 -    return false;
131.1051 -}
131.1052 -
131.1053 -
131.1054 -ko.exportSymbol('observable', ko.observable);
131.1055 -ko.exportSymbol('isObservable', ko.isObservable);
131.1056 -ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);
131.1057 -ko.observableArray = function (initialValues) {
131.1058 -    if (arguments.length == 0) {
131.1059 -        // Zero-parameter constructor initializes to empty array
131.1060 -        initialValues = [];
131.1061 -    }
131.1062 -    if ((initialValues !== null) && (initialValues !== undefined) && !('length' in initialValues))
131.1063 -        throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
131.1064 -
131.1065 -    var result = ko.observable(initialValues);
131.1066 -    ko.utils.extend(result, ko.observableArray['fn']);
131.1067 -    return result;
131.1068 -}
131.1069 -
131.1070 -ko.observableArray['fn'] = {
131.1071 -    'remove': function (valueOrPredicate) {
131.1072 -        var underlyingArray = this.peek();
131.1073 -        var removedValues = [];
131.1074 -        var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
131.1075 -        for (var i = 0; i < underlyingArray.length; i++) {
131.1076 -            var value = underlyingArray[i];
131.1077 -            if (predicate(value)) {
131.1078 -                if (removedValues.length === 0) {
131.1079 -                    this.valueWillMutate();
131.1080 -                }
131.1081 -                removedValues.push(value);
131.1082 -                underlyingArray.splice(i, 1);
131.1083 -                i--;
131.1084 -            }
131.1085 -        }
131.1086 -        if (removedValues.length) {
131.1087 -            this.valueHasMutated();
131.1088 -        }
131.1089 -        return removedValues;
131.1090 -    },
131.1091 -
131.1092 -    'removeAll': function (arrayOfValues) {
131.1093 -        // If you passed zero args, we remove everything
131.1094 -        if (arrayOfValues === undefined) {
131.1095 -            var underlyingArray = this.peek();
131.1096 -            var allValues = underlyingArray.slice(0);
131.1097 -            this.valueWillMutate();
131.1098 -            underlyingArray.splice(0, underlyingArray.length);
131.1099 -            this.valueHasMutated();
131.1100 -            return allValues;
131.1101 -        }
131.1102 -        // If you passed an arg, we interpret it as an array of entries to remove
131.1103 -        if (!arrayOfValues)
131.1104 -            return [];
131.1105 -        return this['remove'](function (value) {
131.1106 -            return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
131.1107 -        });
131.1108 -    },
131.1109 -
131.1110 -    'destroy': function (valueOrPredicate) {
131.1111 -        var underlyingArray = this.peek();
131.1112 -        var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
131.1113 -        this.valueWillMutate();
131.1114 -        for (var i = underlyingArray.length - 1; i >= 0; i--) {
131.1115 -            var value = underlyingArray[i];
131.1116 -            if (predicate(value))
131.1117 -                underlyingArray[i]["_destroy"] = true;
131.1118 -        }
131.1119 -        this.valueHasMutated();
131.1120 -    },
131.1121 -
131.1122 -    'destroyAll': function (arrayOfValues) {
131.1123 -        // If you passed zero args, we destroy everything
131.1124 -        if (arrayOfValues === undefined)
131.1125 -            return this['destroy'](function() { return true });
131.1126 -
131.1127 -        // If you passed an arg, we interpret it as an array of entries to destroy
131.1128 -        if (!arrayOfValues)
131.1129 -            return [];
131.1130 -        return this['destroy'](function (value) {
131.1131 -            return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
131.1132 -        });
131.1133 -    },
131.1134 -
131.1135 -    'indexOf': function (item) {
131.1136 -        var underlyingArray = this();
131.1137 -        return ko.utils.arrayIndexOf(underlyingArray, item);
131.1138 -    },
131.1139 -
131.1140 -    'replace': function(oldItem, newItem) {
131.1141 -        var index = this['indexOf'](oldItem);
131.1142 -        if (index >= 0) {
131.1143 -            this.valueWillMutate();
131.1144 -            this.peek()[index] = newItem;
131.1145 -            this.valueHasMutated();
131.1146 -        }
131.1147 -    }
131.1148 -}
131.1149 -
131.1150 -// Populate ko.observableArray.fn with read/write functions from native arrays
131.1151 -// Important: Do not add any additional functions here that may reasonably be used to *read* data from the array
131.1152 -// because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale
131.1153 -ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
131.1154 -    ko.observableArray['fn'][methodName] = function () {
131.1155 -        // Use "peek" to avoid creating a subscription in any computed that we're executing in the context of
131.1156 -        // (for consistency with mutating regular observables)
131.1157 -        var underlyingArray = this.peek();
131.1158 -        this.valueWillMutate();
131.1159 -        var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
131.1160 -        this.valueHasMutated();
131.1161 -        return methodCallResult;
131.1162 -    };
131.1163 -});
131.1164 -
131.1165 -// Populate ko.observableArray.fn with read-only functions from native arrays
131.1166 -ko.utils.arrayForEach(["slice"], function (methodName) {
131.1167 -    ko.observableArray['fn'][methodName] = function () {
131.1168 -        var underlyingArray = this();
131.1169 -        return underlyingArray[methodName].apply(underlyingArray, arguments);
131.1170 -    };
131.1171 -});
131.1172 -
131.1173 -ko.exportSymbol('observableArray', ko.observableArray);
131.1174 -ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {
131.1175 -    var _latestValue,
131.1176 -        _hasBeenEvaluated = false,
131.1177 -        _isBeingEvaluated = false,
131.1178 -        readFunction = evaluatorFunctionOrOptions;
131.1179 -
131.1180 -    if (readFunction && typeof readFunction == "object") {
131.1181 -        // Single-parameter syntax - everything is on this "options" param
131.1182 -        options = readFunction;
131.1183 -        readFunction = options["read"];
131.1184 -    } else {
131.1185 -        // Multi-parameter syntax - construct the options according to the params passed
131.1186 -        options = options || {};
131.1187 -        if (!readFunction)
131.1188 -            readFunction = options["read"];
131.1189 -    }
131.1190 -    if (typeof readFunction != "function")
131.1191 -        throw new Error("Pass a function that returns the value of the ko.computed");
131.1192 -
131.1193 -    function addSubscriptionToDependency(subscribable) {
131.1194 -        _subscriptionsToDependencies.push(subscribable.subscribe(evaluatePossiblyAsync));
131.1195 -    }
131.1196 -
131.1197 -    function disposeAllSubscriptionsToDependencies() {
131.1198 -        ko.utils.arrayForEach(_subscriptionsToDependencies, function (subscription) {
131.1199 -            subscription.dispose();
131.1200 -        });
131.1201 -        _subscriptionsToDependencies = [];
131.1202 -    }
131.1203 -
131.1204 -    function evaluatePossiblyAsync() {
131.1205 -        var throttleEvaluationTimeout = dependentObservable['throttleEvaluation'];
131.1206 -        if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
131.1207 -            clearTimeout(evaluationTimeoutInstance);
131.1208 -            evaluationTimeoutInstance = setTimeout(evaluateImmediate, throttleEvaluationTimeout);
131.1209 -        } else
131.1210 -            evaluateImmediate();
131.1211 -    }
131.1212 -
131.1213 -    function evaluateImmediate() {
131.1214 -        if (_isBeingEvaluated) {
131.1215 -            // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.
131.1216 -            // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost
131.1217 -            // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing
131.1218 -            // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387
131.1219 -            return;
131.1220 -        }
131.1221 -
131.1222 -        // Don't dispose on first evaluation, because the "disposeWhen" callback might
131.1223 -        // e.g., dispose when the associated DOM element isn't in the doc, and it's not
131.1224 -        // going to be in the doc until *after* the first evaluation
131.1225 -        if (_hasBeenEvaluated && disposeWhen()) {
131.1226 -            dispose();
131.1227 -            return;
131.1228 -        }
131.1229 -
131.1230 -        _isBeingEvaluated = true;
131.1231 -        try {
131.1232 -            // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).
131.1233 -            // Then, during evaluation, we cross off any that are in fact still being used.
131.1234 -            var disposalCandidates = ko.utils.arrayMap(_subscriptionsToDependencies, function(item) {return item.target;});
131.1235 -
131.1236 -            ko.dependencyDetection.begin(function(subscribable) {
131.1237 -                var inOld;
131.1238 -                if ((inOld = ko.utils.arrayIndexOf(disposalCandidates, subscribable)) >= 0)
131.1239 -                    disposalCandidates[inOld] = undefined; // Don't want to dispose this subscription, as it's still being used
131.1240 -                else
131.1241 -                    addSubscriptionToDependency(subscribable); // Brand new subscription - add it
131.1242 -            });
131.1243 -
131.1244 -            var newValue = readFunction.call(evaluatorFunctionTarget);
131.1245 -
131.1246 -            // For each subscription no longer being used, remove it from the active subscriptions list and dispose it
131.1247 -            for (var i = disposalCandidates.length - 1; i >= 0; i--) {
131.1248 -                if (disposalCandidates[i])
131.1249 -                    _subscriptionsToDependencies.splice(i, 1)[0].dispose();
131.1250 -            }
131.1251 -            _hasBeenEvaluated = true;
131.1252 -
131.1253 -            dependentObservable["notifySubscribers"](_latestValue, "beforeChange");
131.1254 -            _latestValue = newValue;
131.1255 -            if (DEBUG) dependentObservable._latestValue = _latestValue;
131.1256 -        } finally {
131.1257 -            ko.dependencyDetection.end();
131.1258 -        }
131.1259 -
131.1260 -        dependentObservable["notifySubscribers"](_latestValue);
131.1261 -        _isBeingEvaluated = false;
131.1262 -        if (!_subscriptionsToDependencies.length)
131.1263 -            dispose();
131.1264 -    }
131.1265 -
131.1266 -    function dependentObservable() {
131.1267 -        if (arguments.length > 0) {
131.1268 -            if (typeof writeFunction === "function") {
131.1269 -                // Writing a value
131.1270 -                writeFunction.apply(evaluatorFunctionTarget, arguments);
131.1271 -            } else {
131.1272 -                throw new Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
131.1273 -            }
131.1274 -            return this; // Permits chained assignments
131.1275 -        } else {
131.1276 -            // Reading the value
131.1277 -            if (!_hasBeenEvaluated)
131.1278 -                evaluateImmediate();
131.1279 -            ko.dependencyDetection.registerDependency(dependentObservable);
131.1280 -            return _latestValue;
131.1281 -        }
131.1282 -    }
131.1283 -
131.1284 -    function peek() {
131.1285 -        if (!_hasBeenEvaluated)
131.1286 -            evaluateImmediate();
131.1287 -        return _latestValue;
131.1288 -    }
131.1289 -
131.1290 -    function isActive() {
131.1291 -        return !_hasBeenEvaluated || _subscriptionsToDependencies.length > 0;
131.1292 -    }
131.1293 -
131.1294 -    // By here, "options" is always non-null
131.1295 -    var writeFunction = options["write"],
131.1296 -        disposeWhenNodeIsRemoved = options["disposeWhenNodeIsRemoved"] || options.disposeWhenNodeIsRemoved || null,
131.1297 -        disposeWhen = options["disposeWhen"] || options.disposeWhen || function() { return false; },
131.1298 -        dispose = disposeAllSubscriptionsToDependencies,
131.1299 -        _subscriptionsToDependencies = [],
131.1300 -        evaluationTimeoutInstance = null;
131.1301 -
131.1302 -    if (!evaluatorFunctionTarget)
131.1303 -        evaluatorFunctionTarget = options["owner"];
131.1304 -
131.1305 -    dependentObservable.peek = peek;
131.1306 -    dependentObservable.getDependenciesCount = function () { return _subscriptionsToDependencies.length; };
131.1307 -    dependentObservable.hasWriteFunction = typeof options["write"] === "function";
131.1308 -    dependentObservable.dispose = function () { dispose(); };
131.1309 -    dependentObservable.isActive = isActive;
131.1310 -    dependentObservable.valueHasMutated = function() {
131.1311 -        _hasBeenEvaluated = false;
131.1312 -        evaluateImmediate();
131.1313 -    };
131.1314 -
131.1315 -    ko.subscribable.call(dependentObservable);
131.1316 -    ko.utils.extend(dependentObservable, ko.dependentObservable['fn']);
131.1317 -
131.1318 -    ko.exportProperty(dependentObservable, 'peek', dependentObservable.peek);
131.1319 -    ko.exportProperty(dependentObservable, 'dispose', dependentObservable.dispose);
131.1320 -    ko.exportProperty(dependentObservable, 'isActive', dependentObservable.isActive);
131.1321 -    ko.exportProperty(dependentObservable, 'getDependenciesCount', dependentObservable.getDependenciesCount);
131.1322 -
131.1323 -    // Evaluate, unless deferEvaluation is true
131.1324 -    if (options['deferEvaluation'] !== true)
131.1325 -        evaluateImmediate();
131.1326 -
131.1327 -    // Build "disposeWhenNodeIsRemoved" and "disposeWhenNodeIsRemovedCallback" option values.
131.1328 -    // But skip if isActive is false (there will never be any dependencies to dispose).
131.1329 -    // (Note: "disposeWhenNodeIsRemoved" option both proactively disposes as soon as the node is removed using ko.removeNode(),
131.1330 -    // plus adds a "disposeWhen" callback that, on each evaluation, disposes if the node was removed by some other means.)
131.1331 -    if (disposeWhenNodeIsRemoved && isActive()) {
131.1332 -        dispose = function() {
131.1333 -            ko.utils.domNodeDisposal.removeDisposeCallback(disposeWhenNodeIsRemoved, arguments.callee);
131.1334 -            disposeAllSubscriptionsToDependencies();
131.1335 -        };
131.1336 -        ko.utils.domNodeDisposal.addDisposeCallback(disposeWhenNodeIsRemoved, dispose);
131.1337 -        var existingDisposeWhenFunction = disposeWhen;
131.1338 -        disposeWhen = function () {
131.1339 -            return !ko.utils.domNodeIsAttachedToDocument(disposeWhenNodeIsRemoved) || existingDisposeWhenFunction();
131.1340 -        }
131.1341 -    }
131.1342 -
131.1343 -    return dependentObservable;
131.1344 -};
131.1345 -
131.1346 -ko.isComputed = function(instance) {
131.1347 -    return ko.hasPrototype(instance, ko.dependentObservable);
131.1348 -};
131.1349 -
131.1350 -var protoProp = ko.observable.protoProperty; // == "__ko_proto__"
131.1351 -ko.dependentObservable[protoProp] = ko.observable;
131.1352 -
131.1353 -ko.dependentObservable['fn'] = {};
131.1354 -ko.dependentObservable['fn'][protoProp] = ko.dependentObservable;
131.1355 -
131.1356 -ko.exportSymbol('dependentObservable', ko.dependentObservable);
131.1357 -ko.exportSymbol('computed', ko.dependentObservable); // Make "ko.computed" an alias for "ko.dependentObservable"
131.1358 -ko.exportSymbol('isComputed', ko.isComputed);
131.1359 -
131.1360 -(function() {
131.1361 -    var maxNestedObservableDepth = 10; // Escape the (unlikely) pathalogical case where an observable's current value is itself (or similar reference cycle)
131.1362 -
131.1363 -    ko.toJS = function(rootObject) {
131.1364 -        if (arguments.length == 0)
131.1365 -            throw new Error("When calling ko.toJS, pass the object you want to convert.");
131.1366 -
131.1367 -        // We just unwrap everything at every level in the object graph
131.1368 -        return mapJsObjectGraph(rootObject, function(valueToMap) {
131.1369 -            // Loop because an observable's value might in turn be another observable wrapper
131.1370 -            for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)
131.1371 -                valueToMap = valueToMap();
131.1372 -            return valueToMap;
131.1373 -        });
131.1374 -    };
131.1375 -
131.1376 -    ko.toJSON = function(rootObject, replacer, space) {     // replacer and space are optional
131.1377 -        var plainJavaScriptObject = ko.toJS(rootObject);
131.1378 -        return ko.utils.stringifyJson(plainJavaScriptObject, replacer, space);
131.1379 -    };
131.1380 -
131.1381 -    function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {
131.1382 -        visitedObjects = visitedObjects || new objectLookup();
131.1383 -
131.1384 -        rootObject = mapInputCallback(rootObject);
131.1385 -        var canHaveProperties = (typeof rootObject == "object") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof Date));
131.1386 -        if (!canHaveProperties)
131.1387 -            return rootObject;
131.1388 -
131.1389 -        var outputProperties = rootObject instanceof Array ? [] : {};
131.1390 -        visitedObjects.save(rootObject, outputProperties);
131.1391 -
131.1392 -        visitPropertiesOrArrayEntries(rootObject, function(indexer) {
131.1393 -            var propertyValue = mapInputCallback(rootObject[indexer]);
131.1394 -
131.1395 -            switch (typeof propertyValue) {
131.1396 -                case "boolean":
131.1397 -                case "number":
131.1398 -                case "string":
131.1399 -                case "function":
131.1400 -                    outputProperties[indexer] = propertyValue;
131.1401 -                    break;
131.1402 -                case "object":
131.1403 -                case "undefined":
131.1404 -                    var previouslyMappedValue = visitedObjects.get(propertyValue);
131.1405 -                    outputProperties[indexer] = (previouslyMappedValue !== undefined)
131.1406 -                        ? previouslyMappedValue
131.1407 -                        : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);
131.1408 -                    break;
131.1409 -            }
131.1410 -        });
131.1411 -
131.1412 -        return outputProperties;
131.1413 -    }
131.1414 -
131.1415 -    function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {
131.1416 -        if (rootObject instanceof Array) {
131.1417 -            for (var i = 0; i < rootObject.length; i++)
131.1418 -                visitorCallback(i);
131.1419 -
131.1420 -            // For arrays, also respect toJSON property for custom mappings (fixes #278)
131.1421 -            if (typeof rootObject['toJSON'] == 'function')
131.1422 -                visitorCallback('toJSON');
131.1423 -        } else {
131.1424 -            for (var propertyName in rootObject)
131.1425 -                visitorCallback(propertyName);
131.1426 -        }
131.1427 -    };
131.1428 -
131.1429 -    function objectLookup() {
131.1430 -        var keys = [];
131.1431 -        var values = [];
131.1432 -        this.save = function(key, value) {
131.1433 -            var existingIndex = ko.utils.arrayIndexOf(keys, key);
131.1434 -            if (existingIndex >= 0)
131.1435 -                values[existingIndex] = value;
131.1436 -            else {
131.1437 -                keys.push(key);
131.1438 -                values.push(value);
131.1439 -            }
131.1440 -        };
131.1441 -        this.get = function(key) {
131.1442 -            var existingIndex = ko.utils.arrayIndexOf(keys, key);
131.1443 -            return (existingIndex >= 0) ? values[existingIndex] : undefined;
131.1444 -        };
131.1445 -    };
131.1446 -})();
131.1447 -
131.1448 -ko.exportSymbol('toJS', ko.toJS);
131.1449 -ko.exportSymbol('toJSON', ko.toJSON);
131.1450 -(function () {
131.1451 -    var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';
131.1452 -
131.1453 -    // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
131.1454 -    // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
131.1455 -    // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
131.1456 -    ko.selectExtensions = {
131.1457 -        readValue : function(element) {
131.1458 -            switch (ko.utils.tagNameLower(element)) {
131.1459 -                case 'option':
131.1460 -                    if (element[hasDomDataExpandoProperty] === true)
131.1461 -                        return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
131.1462 -                    return ko.utils.ieVersion <= 7
131.1463 -                        ? (element.getAttributeNode('value').specified ? element.value : element.text)
131.1464 -                        : element.value;
131.1465 -                case 'select':
131.1466 -                    return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
131.1467 -                default:
131.1468 -                    return element.value;
131.1469 -            }
131.1470 -        },
131.1471 -
131.1472 -        writeValue: function(element, value) {
131.1473 -            switch (ko.utils.tagNameLower(element)) {
131.1474 -                case 'option':
131.1475 -                    switch(typeof value) {
131.1476 -                        case "string":
131.1477 -                            ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);
131.1478 -                            if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
131.1479 -                                delete element[hasDomDataExpandoProperty];
131.1480 -                            }
131.1481 -                            element.value = value;
131.1482 -                            break;
131.1483 -                        default:
131.1484 -                            // Store arbitrary object using DomData
131.1485 -                            ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
131.1486 -                            element[hasDomDataExpandoProperty] = true;
131.1487 -
131.1488 -                            // Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.
131.1489 -                            element.value = typeof value === "number" ? value : "";
131.1490 -                            break;
131.1491 -                    }
131.1492 -                    break;
131.1493 -                case 'select':
131.1494 -                    for (var i = element.options.length - 1; i >= 0; i--) {
131.1495 -                        if (ko.selectExtensions.readValue(element.options[i]) == value) {
131.1496 -                            element.selectedIndex = i;
131.1497 -                            break;
131.1498 -                        }
131.1499 -                    }
131.1500 -                    break;
131.1501 -                default:
131.1502 -                    if ((value === null) || (value === undefined))
131.1503 -                        value = "";
131.1504 -                    element.value = value;
131.1505 -                    break;
131.1506 -            }
131.1507 -        }
131.1508 -    };
131.1509 -})();
131.1510 -
131.1511 -ko.exportSymbol('selectExtensions', ko.selectExtensions);
131.1512 -ko.exportSymbol('selectExtensions.readValue', ko.selectExtensions.readValue);
131.1513 -ko.exportSymbol('selectExtensions.writeValue', ko.selectExtensions.writeValue);
131.1514 -ko.expressionRewriting = (function () {
131.1515 -    var restoreCapturedTokensRegex = /\@ko_token_(\d+)\@/g;
131.1516 -    var javaScriptReservedWords = ["true", "false"];
131.1517 -
131.1518 -    // Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor
131.1519 -    // This is designed to be simple and avoid false negatives, but could produce false positives (e.g., a+b.c).
131.1520 -    var javaScriptAssignmentTarget = /^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i;
131.1521 -
131.1522 -    function restoreTokens(string, tokens) {
131.1523 -        var prevValue = null;
131.1524 -        while (string != prevValue) { // Keep restoring tokens until it no longer makes a difference (they may be nested)
131.1525 -            prevValue = string;
131.1526 -            string = string.replace(restoreCapturedTokensRegex, function (match, tokenIndex) {
131.1527 -                return tokens[tokenIndex];
131.1528 -            });
131.1529 -        }
131.1530 -        return string;
131.1531 -    }
131.1532 -
131.1533 -    function getWriteableValue(expression) {
131.1534 -        if (ko.utils.arrayIndexOf(javaScriptReservedWords, ko.utils.stringTrim(expression).toLowerCase()) >= 0)
131.1535 -            return false;
131.1536 -        var match = expression.match(javaScriptAssignmentTarget);
131.1537 -        return match === null ? false : match[1] ? ('Object(' + match[1] + ')' + match[2]) : expression;
131.1538 -    }
131.1539 -
131.1540 -    function ensureQuoted(key) {
131.1541 -        var trimmedKey = ko.utils.stringTrim(key);
131.1542 -        switch (trimmedKey.length && trimmedKey.charAt(0)) {
131.1543 -            case "'":
131.1544 -            case '"':
131.1545 -                return key;
131.1546 -            default:
131.1547 -                return "'" + trimmedKey + "'";
131.1548 -        }
131.1549 -    }
131.1550 -
131.1551 -    return {
131.1552 -        bindingRewriteValidators: [],
131.1553 -
131.1554 -        parseObjectLiteral: function(objectLiteralString) {
131.1555 -            // A full tokeniser+lexer would add too much weight to this library, so here's a simple parser
131.1556 -            // that is sufficient just to split an object literal string into a set of top-level key-value pairs
131.1557 -
131.1558 -            var str = ko.utils.stringTrim(objectLiteralString);
131.1559 -            if (str.length < 3)
131.1560 -                return [];
131.1561 -            if (str.charAt(0) === "{")// Ignore any braces surrounding the whole object literal
131.1562 -                str = str.substring(1, str.length - 1);
131.1563 -
131.1564 -            // Pull out any string literals and regex literals
131.1565 -            var tokens = [];
131.1566 -            var tokenStart = null, tokenEndChar;
131.1567 -            for (var position = 0; position < str.length; position++) {
131.1568 -                var c = str.charAt(position);
131.1569 -                if (tokenStart === null) {
131.1570 -                    switch (c) {
131.1571 -                        case '"':
131.1572 -                        case "'":
131.1573 -                        case "/":
131.1574 -                            tokenStart = position;
131.1575 -                            tokenEndChar = c;
131.1576 -                            break;
131.1577 -                    }
131.1578 -                } else if ((c == tokenEndChar) && (str.charAt(position - 1) !== "\\")) {
131.1579 -                    var token = str.substring(tokenStart, position + 1);
131.1580 -                    tokens.push(token);
131.1581 -                    var replacement = "@ko_token_" + (tokens.length - 1) + "@";
131.1582 -                    str = str.substring(0, tokenStart) + replacement + str.substring(position + 1);
131.1583 -                    position -= (token.length - replacement.length);
131.1584 -                    tokenStart = null;
131.1585 -                }
131.1586 -            }
131.1587 -
131.1588 -            // Next pull out balanced paren, brace, and bracket blocks
131.1589 -            tokenStart = null;
131.1590 -            tokenEndChar = null;
131.1591 -            var tokenDepth = 0, tokenStartChar = null;
131.1592 -            for (var position = 0; position < str.length; position++) {
131.1593 -                var c = str.charAt(position);
131.1594 -                if (tokenStart === null) {
131.1595 -                    switch (c) {
131.1596 -                        case "{": tokenStart = position; tokenStartChar = c;
131.1597 -                                  tokenEndChar = "}";
131.1598 -                                  break;
131.1599 -                        case "(": tokenStart = position; tokenStartChar = c;
131.1600 -                                  tokenEndChar = ")";
131.1601 -                                  break;
131.1602 -                        case "[": tokenStart = position; tokenStartChar = c;
131.1603 -                                  tokenEndChar = "]";
131.1604 -                                  break;
131.1605 -                    }
131.1606 -                }
131.1607 -
131.1608 -                if (c === tokenStartChar)
131.1609 -                    tokenDepth++;
131.1610 -                else if (c === tokenEndChar) {
131.1611 -                    tokenDepth--;
131.1612 -                    if (tokenDepth === 0) {
131.1613 -                        var token = str.substring(tokenStart, position + 1);
131.1614 -                        tokens.push(token);
131.1615 -                        var replacement = "@ko_token_" + (tokens.length - 1) + "@";
131.1616 -                        str = str.substring(0, tokenStart) + replacement + str.substring(position + 1);
131.1617 -                        position -= (token.length - replacement.length);
131.1618 -                        tokenStart = null;
131.1619 -                    }
131.1620 -                }
131.1621 -            }
131.1622 -
131.1623 -            // Now we can safely split on commas to get the key/value pairs
131.1624 -            var result = [];
131.1625 -            var keyValuePairs = str.split(",");
131.1626 -            for (var i = 0, j = keyValuePairs.length; i < j; i++) {
131.1627 -                var pair = keyValuePairs[i];
131.1628 -                var colonPos = pair.indexOf(":");
131.1629 -                if ((colonPos > 0) && (colonPos < pair.length - 1)) {
131.1630 -                    var key = pair.substring(0, colonPos);
131.1631 -                    var value = pair.substring(colonPos + 1);
131.1632 -                    result.push({ 'key': restoreTokens(key, tokens), 'value': restoreTokens(value, tokens) });
131.1633 -                } else {
131.1634 -                    result.push({ 'unknown': restoreTokens(pair, tokens) });
131.1635 -                }
131.1636 -            }
131.1637 -            return result;
131.1638 -        },
131.1639 -
131.1640 -        preProcessBindings: function (objectLiteralStringOrKeyValueArray) {
131.1641 -            var keyValueArray = typeof objectLiteralStringOrKeyValueArray === "string"
131.1642 -                ? ko.expressionRewriting.parseObjectLiteral(objectLiteralStringOrKeyValueArray)
131.1643 -                : objectLiteralStringOrKeyValueArray;
131.1644 -            var resultStrings = [], propertyAccessorResultStrings = [];
131.1645 -
131.1646 -            var keyValueEntry;
131.1647 -            for (var i = 0; keyValueEntry = keyValueArray[i]; i++) {
131.1648 -                if (resultStrings.length > 0)
131.1649 -                    resultStrings.push(",");
131.1650 -
131.1651 -                if (keyValueEntry['key']) {
131.1652 -                    var quotedKey = ensureQuoted(keyValueEntry['key']), val = keyValueEntry['value'];
131.1653 -                    resultStrings.push(quotedKey);
131.1654 -                    resultStrings.push(":");
131.1655 -                    resultStrings.push(val);
131.1656 -
131.1657 -                    if (val = getWriteableValue(ko.utils.stringTrim(val))) {
131.1658 -                        if (propertyAccessorResultStrings.length > 0)
131.1659 -                            propertyAccessorResultStrings.push(", ");
131.1660 -                        propertyAccessorResultStrings.push(quotedKey + " : function(__ko_value) { " + val + " = __ko_value; }");
131.1661 -                    }
131.1662 -                } else if (keyValueEntry['unknown']) {
131.1663 -                    resultStrings.push(keyValueEntry['unknown']);
131.1664 -                }
131.1665 -            }
131.1666 -
131.1667 -            var combinedResult = resultStrings.join("");
131.1668 -            if (propertyAccessorResultStrings.length > 0) {
131.1669 -                var allPropertyAccessors = propertyAccessorResultStrings.join("");
131.1670 -                combinedResult = combinedResult + ", '_ko_property_writers' : { " + allPropertyAccessors + " } ";
131.1671 -            }
131.1672 -
131.1673 -            return combinedResult;
131.1674 -        },
131.1675 -
131.1676 -        keyValueArrayContainsKey: function(keyValueArray, key) {
131.1677 -            for (var i = 0; i < keyValueArray.length; i++)
131.1678 -                if (ko.utils.stringTrim(keyValueArray[i]['key']) == key)
131.1679 -                    return true;
131.1680 -            return false;
131.1681 -        },
131.1682 -
131.1683 -        // Internal, private KO utility for updating model properties from within bindings
131.1684 -        // property:            If the property being updated is (or might be) an observable, pass it here
131.1685 -        //                      If it turns out to be a writable observable, it will be written to directly
131.1686 -        // allBindingsAccessor: All bindings in the current execution context.
131.1687 -        //                      This will be searched for a '_ko_property_writers' property in case you're writing to a non-observable
131.1688 -        // key:                 The key identifying the property to be written. Example: for { hasFocus: myValue }, write to 'myValue' by specifying the key 'hasFocus'
131.1689 -        // value:               The value to be written
131.1690 -        // checkIfDifferent:    If true, and if the property being written is a writable observable, the value will only be written if
131.1691 -        //                      it is !== existing value on that writable observable
131.1692 -        writeValueToProperty: function(property, allBindingsAccessor, key, value, checkIfDifferent) {
131.1693 -            if (!property || !ko.isWriteableObservable(property)) {
131.1694 -                var propWriters = allBindingsAccessor()['_ko_property_writers'];
131.1695 -                if (propWriters && propWriters[key])
131.1696 -                    propWriters[key](value);
131.1697 -            } else if (!checkIfDifferent || property.peek() !== value) {
131.1698 -                property(value);
131.1699 -            }
131.1700 -        }
131.1701 -    };
131.1702 -})();
131.1703 -
131.1704 -ko.exportSymbol('expressionRewriting', ko.expressionRewriting);
131.1705 -ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);
131.1706 -ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);
131.1707 -ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);
131.1708 -
131.1709 -// For backward compatibility, define the following aliases. (Previously, these function names were misleading because
131.1710 -// they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)
131.1711 -ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);
131.1712 -ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);(function() {
131.1713 -    // "Virtual elements" is an abstraction on top of the usual DOM API which understands the notion that comment nodes
131.1714 -    // may be used to represent hierarchy (in addition to the DOM's natural hierarchy).
131.1715 -    // If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state
131.1716 -    // of that virtual hierarchy
131.1717 -    //
131.1718 -    // The point of all this is to support containerless templates (e.g., <!-- ko foreach:someCollection -->blah<!-- /ko -->)
131.1719 -    // without having to scatter special cases all over the binding and templating code.
131.1720 -
131.1721 -    // IE 9 cannot reliably read the "nodeValue" property of a comment node (see https://github.com/SteveSanderson/knockout/issues/186)
131.1722 -    // but it does give them a nonstandard alternative property called "text" that it can read reliably. Other browsers don't have that property.
131.1723 -    // So, use node.text where available, and node.nodeValue elsewhere
131.1724 -    var commentNodesHaveTextProperty = document.createComment("test").text === "<!--test-->";
131.1725 -
131.1726 -    var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*-->$/ : /^\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*$/;
131.1727 -    var endCommentRegex =   commentNodesHaveTextProperty ? /^<!--\s*\/ko\s*-->$/ : /^\s*\/ko\s*$/;
131.1728 -    var htmlTagsWithOptionallyClosingChildren = { 'ul': true, 'ol': true };
131.1729 -
131.1730 -    function isStartComment(node) {
131.1731 -        return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);
131.1732 -    }
131.1733 -
131.1734 -    function isEndComment(node) {
131.1735 -        return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(endCommentRegex);
131.1736 -    }
131.1737 -
131.1738 -    function getVirtualChildren(startComment, allowUnbalanced) {
131.1739 -        var currentNode = startComment;
131.1740 -        var depth = 1;
131.1741 -        var children = [];
131.1742 -        while (currentNode = currentNode.nextSibling) {
131.1743 -            if (isEndComment(currentNode)) {
131.1744 -                depth--;
131.1745 -                if (depth === 0)
131.1746 -                    return children;
131.1747 -            }
131.1748 -
131.1749 -            children.push(currentNode);
131.1750 -
131.1751 -            if (isStartComment(currentNode))
131.1752 -                depth++;
131.1753 -        }
131.1754 -        if (!allowUnbalanced)
131.1755 -            throw new Error("Cannot find closing comment tag to match: " + startComment.nodeValue);
131.1756 -        return null;
131.1757 -    }
131.1758 -
131.1759 -    function getMatchingEndComment(startComment, allowUnbalanced) {
131.1760 -        var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);
131.1761 -        if (allVirtualChildren) {
131.1762 -            if (allVirtualChildren.length > 0)
131.1763 -                return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;
131.1764 -            return startComment.nextSibling;
131.1765 -        } else
131.1766 -            return null; // Must have no matching end comment, and allowUnbalanced is true
131.1767 -    }
131.1768 -
131.1769 -    function getUnbalancedChildTags(node) {
131.1770 -        // e.g., from <div>OK</div><!-- ko blah --><span>Another</span>, returns: <!-- ko blah --><span>Another</span>
131.1771 -        //       from <div>OK</div><!-- /ko --><!-- /ko -->,             returns: <!-- /ko --><!-- /ko -->
131.1772 -        var childNode = node.firstChild, captureRemaining = null;
131.1773 -        if (childNode) {
131.1774 -            do {
131.1775 -                if (captureRemaining)                   // We already hit an unbalanced node and are now just scooping up all subsequent nodes
131.1776 -                    captureRemaining.push(childNode);
131.1777 -                else if (isStartComment(childNode)) {
131.1778 -                    var matchingEndComment = getMatchingEndComment(childNode, /* allowUnbalanced: */ true);
131.1779 -                    if (matchingEndComment)             // It's a balanced tag, so skip immediately to the end of this virtual set
131.1780 -                        childNode = matchingEndComment;
131.1781 -                    else
131.1782 -                        captureRemaining = [childNode]; // It's unbalanced, so start capturing from this point
131.1783 -                } else if (isEndComment(childNode)) {
131.1784 -                    captureRemaining = [childNode];     // It's unbalanced (if it wasn't, we'd have skipped over it already), so start capturing
131.1785 -                }
131.1786 -            } while (childNode = childNode.nextSibling);
131.1787 -        }
131.1788 -        return captureRemaining;
131.1789 -    }
131.1790 -
131.1791 -    ko.virtualElements = {
131.1792 -        allowedBindings: {},
131.1793 -
131.1794 -        childNodes: function(node) {
131.1795 -            return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;
131.1796 -        },
131.1797 -
131.1798 -        emptyNode: function(node) {
131.1799 -            if (!isStartComment(node))
131.1800 -                ko.utils.emptyDomNode(node);
131.1801 -            else {
131.1802 -                var virtualChildren = ko.virtualElements.childNodes(node);
131.1803 -                for (var i = 0, j = virtualChildren.length; i < j; i++)
131.1804 -                    ko.removeNode(virtualChildren[i]);
131.1805 -            }
131.1806 -        },
131.1807 -
131.1808 -        setDomNodeChildren: function(node, childNodes) {
131.1809 -            if (!isStartComment(node))
131.1810 -                ko.utils.setDomNodeChildren(node, childNodes);
131.1811 -            else {
131.1812 -                ko.virtualElements.emptyNode(node);
131.1813 -                var endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children
131.1814 -                for (var i = 0, j = childNodes.length; i < j; i++)
131.1815 -                    endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);
131.1816 -            }
131.1817 -        },
131.1818 -
131.1819 -        prepend: function(containerNode, nodeToPrepend) {
131.1820 -            if (!isStartComment(containerNode)) {
131.1821 -                if (containerNode.firstChild)
131.1822 -                    containerNode.insertBefore(nodeToPrepend, containerNode.firstChild);
131.1823 -                else
131.1824 -                    containerNode.appendChild(nodeToPrepend);
131.1825 -            } else {
131.1826 -                // Start comments must always have a parent and at least one following sibling (the end comment)
131.1827 -                containerNode.parentNode.insertBefore(nodeToPrepend, containerNode.nextSibling);
131.1828 -            }
131.1829 -        },
131.1830 -
131.1831 -        insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {
131.1832 -            if (!insertAfterNode) {
131.1833 -                ko.virtualElements.prepend(containerNode, nodeToInsert);
131.1834 -            } else if (!isStartComment(containerNode)) {
131.1835 -                // Insert after insertion point
131.1836 -                if (insertAfterNode.nextSibling)
131.1837 -                    containerNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
131.1838 -                else
131.1839 -                    containerNode.appendChild(nodeToInsert);
131.1840 -            } else {
131.1841 -                // Children of start comments must always have a parent and at least one following sibling (the end comment)
131.1842 -                containerNode.parentNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
131.1843 -            }
131.1844 -        },
131.1845 -
131.1846 -        firstChild: function(node) {
131.1847 -            if (!isStartComment(node))
131.1848 -                return node.firstChild;
131.1849 -            if (!node.nextSibling || isEndComment(node.nextSibling))
131.1850 -                return null;
131.1851 -            return node.nextSibling;
131.1852 -        },
131.1853 -
131.1854 -        nextSibling: function(node) {
131.1855 -            if (isStartComment(node))
131.1856 -                node = getMatchingEndComment(node);
131.1857 -            if (node.nextSibling && isEndComment(node.nextSibling))
131.1858 -                return null;
131.1859 -            return node.nextSibling;
131.1860 -        },
131.1861 -
131.1862 -        virtualNodeBindingValue: function(node) {
131.1863 -            var regexMatch = isStartComment(node);
131.1864 -            return regexMatch ? regexMatch[1] : null;
131.1865 -        },
131.1866 -
131.1867 -        normaliseVirtualElementDomStructure: function(elementVerified) {
131.1868 -            // Workaround for https://github.com/SteveSanderson/knockout/issues/155
131.1869 -            // (IE <= 8 or IE 9 quirks mode parses your HTML weirdly, treating closing </li> tags as if they don't exist, thereby moving comment nodes
131.1870 -            // that are direct descendants of <ul> into the preceding <li>)
131.1871 -            if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])
131.1872 -                return;
131.1873 -
131.1874 -            // Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags
131.1875 -            // must be intended to appear *after* that child, so move them there.
131.1876 -            var childNode = elementVerified.firstChild;
131.1877 -            if (childNode) {
131.1878 -                do {
131.1879 -                    if (childNode.nodeType === 1) {
131.1880 -                        var unbalancedTags = getUnbalancedChildTags(childNode);
131.1881 -                        if (unbalancedTags) {
131.1882 -                            // Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the child
131.1883 -                            var nodeToInsertBefore = childNode.nextSibling;
131.1884 -                            for (var i = 0; i < unbalancedTags.length; i++) {
131.1885 -                                if (nodeToInsertBefore)
131.1886 -                                    elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);
131.1887 -                                else
131.1888 -                                    elementVerified.appendChild(unbalancedTags[i]);
131.1889 -                            }
131.1890 -                        }
131.1891 -                    }
131.1892 -                } while (childNode = childNode.nextSibling);
131.1893 -            }
131.1894 -        }
131.1895 -    };
131.1896 -})();
131.1897 -ko.exportSymbol('virtualElements', ko.virtualElements);
131.1898 -ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);
131.1899 -ko.exportSymbol('virtualElements.emptyNode', ko.virtualElements.emptyNode);
131.1900 -//ko.exportSymbol('virtualElements.firstChild', ko.virtualElements.firstChild);     // firstChild is not minified
131.1901 -ko.exportSymbol('virtualElements.insertAfter', ko.virtualElements.insertAfter);
131.1902 -//ko.exportSymbol('virtualElements.nextSibling', ko.virtualElements.nextSibling);   // nextSibling is not minified
131.1903 -ko.exportSymbol('virtualElements.prepend', ko.virtualElements.prepend);
131.1904 -ko.exportSymbol('virtualElements.setDomNodeChildren', ko.virtualElements.setDomNodeChildren);
131.1905 -(function() {
131.1906 -    var defaultBindingAttributeName = "data-bind";
131.1907 -
131.1908 -    ko.bindingProvider = function() {
131.1909 -        this.bindingCache = {};
131.1910 -    };
131.1911 -
131.1912 -    ko.utils.extend(ko.bindingProvider.prototype, {
131.1913 -        'nodeHasBindings': function(node) {
131.1914 -            switch (node.nodeType) {
131.1915 -                case 1: return node.getAttribute(defaultBindingAttributeName) != null;   // Element
131.1916 -                case 8: return ko.virtualElements.virtualNodeBindingValue(node) != null; // Comment node
131.1917 -                default: return false;
131.1918 -            }
131.1919 -        },
131.1920 -
131.1921 -        'getBindings': function(node, bindingContext) {
131.1922 -            var bindingsString = this['getBindingsString'](node, bindingContext);
131.1923 -            return bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node) : null;
131.1924 -        },
131.1925 -
131.1926 -        // The following function is only used internally by this default provider.
131.1927 -        // It's not part of the interface definition for a general binding provider.
131.1928 -        'getBindingsString': function(node, bindingContext) {
131.1929 -            switch (node.nodeType) {
131.1930 -                case 1: return node.getAttribute(defaultBindingAttributeName);   // Element
131.1931 -                case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node
131.1932 -                default: return null;
131.1933 -            }
131.1934 -        },
131.1935 -
131.1936 -        // The following function is only used internally by this default provider.
131.1937 -        // It's not part of the interface definition for a general binding provider.
131.1938 -        'parseBindingsString': function(bindingsString, bindingContext, node) {
131.1939 -            try {
131.1940 -                var bindingFunction = createBindingsStringEvaluatorViaCache(bindingsString, this.bindingCache);
131.1941 -                return bindingFunction(bindingContext, node);
131.1942 -            } catch (ex) {
131.1943 -                throw new Error("Unable to parse bindings.\nMessage: " + ex + ";\nBindings value: " + bindingsString);
131.1944 -            }
131.1945 -        }
131.1946 -    });
131.1947 -
131.1948 -    ko.bindingProvider['instance'] = new ko.bindingProvider();
131.1949 -
131.1950 -    function createBindingsStringEvaluatorViaCache(bindingsString, cache) {
131.1951 -        var cacheKey = bindingsString;
131.1952 -        return cache[cacheKey]
131.1953 -            || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString));
131.1954 -    }
131.1955 -
131.1956 -    function createBindingsStringEvaluator(bindingsString) {
131.1957 -        // Build the source for a function that evaluates "expression"
131.1958 -        // For each scope variable, add an extra level of "with" nesting
131.1959 -        // Example result: with(sc1) { with(sc0) { return (expression) } }
131.1960 -        var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString),
131.1961 -            functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}";
131.1962 -        return new Function("$context", "$element", functionBody);
131.1963 -    }
131.1964 -})();
131.1965 -
131.1966 -ko.exportSymbol('bindingProvider', ko.bindingProvider);
131.1967 -(function () {
131.1968 -    ko.bindingHandlers = {};
131.1969 -
131.1970 -    ko.bindingContext = function(dataItem, parentBindingContext, dataItemAlias) {
131.1971 -        if (parentBindingContext) {
131.1972 -            ko.utils.extend(this, parentBindingContext); // Inherit $root and any custom properties
131.1973 -            this['$parentContext'] = parentBindingContext;
131.1974 -            this['$parent'] = parentBindingContext['$data'];
131.1975 -            this['$parents'] = (parentBindingContext['$parents'] || []).slice(0);
131.1976 -            this['$parents'].unshift(this['$parent']);
131.1977 -        } else {
131.1978 -            this['$parents'] = [];
131.1979 -            this['$root'] = dataItem;
131.1980 -            // Export 'ko' in the binding context so it will be available in bindings and templates
131.1981 -            // even if 'ko' isn't exported as a global, such as when using an AMD loader.
131.1982 -            // See https://github.com/SteveSanderson/knockout/issues/490
131.1983 -            this['ko'] = ko;
131.1984 -        }
131.1985 -        this['$data'] = dataItem;
131.1986 -        if (dataItemAlias)
131.1987 -            this[dataItemAlias] = dataItem;
131.1988 -    }
131.1989 -    ko.bindingContext.prototype['createChildContext'] = function (dataItem, dataItemAlias) {
131.1990 -        return new ko.bindingContext(dataItem, this, dataItemAlias);
131.1991 -    };
131.1992 -    ko.bindingContext.prototype['extend'] = function(properties) {
131.1993 -        var clone = ko.utils.extend(new ko.bindingContext(), this);
131.1994 -        return ko.utils.extend(clone, properties);
131.1995 -    };
131.1996 -
131.1997 -    function validateThatBindingIsAllowedForVirtualElements(bindingName) {
131.1998 -        var validator = ko.virtualElements.allowedBindings[bindingName];
131.1999 -        if (!validator)
131.2000 -            throw new Error("The binding '" + bindingName + "' cannot be used with virtual elements")
131.2001 -    }
131.2002 -
131.2003 -    function applyBindingsToDescendantsInternal (viewModel, elementOrVirtualElement, bindingContextsMayDifferFromDomParentElement) {
131.2004 -        var currentChild, nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);
131.2005 -        while (currentChild = nextInQueue) {
131.2006 -            // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position
131.2007 -            nextInQueue = ko.virtualElements.nextSibling(currentChild);
131.2008 -            applyBindingsToNodeAndDescendantsInternal(viewModel, currentChild, bindingContextsMayDifferFromDomParentElement);
131.2009 -        }
131.2010 -    }
131.2011 -
131.2012 -    function applyBindingsToNodeAndDescendantsInternal (viewModel, nodeVerified, bindingContextMayDifferFromDomParentElement) {
131.2013 -        var shouldBindDescendants = true;
131.2014 -
131.2015 -        // Perf optimisation: Apply bindings only if...
131.2016 -        // (1) We need to store the binding context on this node (because it may differ from the DOM parent node's binding context)
131.2017 -        //     Note that we can't store binding contexts on non-elements (e.g., text nodes), as IE doesn't allow expando properties for those
131.2018 -        // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
131.2019 -        var isElement = (nodeVerified.nodeType === 1);
131.2020 -        if (isElement) // Workaround IE <= 8 HTML parsing weirdness
131.2021 -            ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);
131.2022 -
131.2023 -        var shouldApplyBindings = (isElement && bindingContextMayDifferFromDomParentElement)             // Case (1)
131.2024 -                               || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified);       // Case (2)
131.2025 -        if (shouldApplyBindings)
131.2026 -            shouldBindDescendants = applyBindingsToNodeInternal(nodeVerified, null, viewModel, bindingContextMayDifferFromDomParentElement).shouldBindDescendants;
131.2027 -
131.2028 -        if (shouldBindDescendants) {
131.2029 -            // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,
131.2030 -            //  * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,
131.2031 -            //    hence bindingContextsMayDifferFromDomParentElement is false
131.2032 -            //  * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may
131.2033 -            //    skip over any number of intermediate virtual elements, any of which might define a custom binding context,
131.2034 -            //    hence bindingContextsMayDifferFromDomParentElement is true
131.2035 -            applyBindingsToDescendantsInternal(viewModel, nodeVerified, /* bindingContextsMayDifferFromDomParentElement: */ !isElement);
131.2036 -        }
131.2037 -    }
131.2038 -
131.2039 -    function applyBindingsToNodeInternal (node, bindings, viewModelOrBindingContext, bindingContextMayDifferFromDomParentElement) {
131.2040 -        // Need to be sure that inits are only run once, and updates never run until all the inits have been run
131.2041 -        var initPhase = 0; // 0 = before all inits, 1 = during inits, 2 = after all inits
131.2042 -
131.2043 -        // Each time the dependentObservable is evaluated (after data changes),
131.2044 -        // the binding attribute is reparsed so that it can pick out the correct
131.2045 -        // model properties in the context of the changed data.
131.2046 -        // DOM event callbacks need to be able to access this changed data,
131.2047 -        // so we need a single parsedBindings variable (shared by all callbacks
131.2048 -        // associated with this node's bindings) that all the closures can access.
131.2049 -        var parsedBindings;
131.2050 -        function makeValueAccessor(bindingKey) {
131.2051 -            return function () { return parsedBindings[bindingKey] }
131.2052 -        }
131.2053 -        function parsedBindingsAccessor() {
131.2054 -            return parsedBindings;
131.2055 -        }
131.2056 -
131.2057 -        var bindingHandlerThatControlsDescendantBindings;
131.2058 -        ko.dependentObservable(
131.2059 -            function () {
131.2060 -                // Ensure we have a nonnull binding context to work with
131.2061 -                var bindingContextInstance = viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)
131.2062 -                    ? viewModelOrBindingContext
131.2063 -                    : new ko.bindingContext(ko.utils.unwrapObservable(viewModelOrBindingContext));
131.2064 -                var viewModel = bindingContextInstance['$data'];
131.2065 -
131.2066 -                // Optimization: Don't store the binding context on this node if it's definitely the same as on node.parentNode, because
131.2067 -                // we can easily recover it just by scanning up the node's ancestors in the DOM
131.2068 -                // (note: here, parent node means "real DOM parent" not "virtual parent", as there's no O(1) way to find the virtual parent)
131.2069 -                if (bindingContextMayDifferFromDomParentElement)
131.2070 -                    ko.storedBindingContextForNode(node, bindingContextInstance);
131.2071 -
131.2072 -                // Use evaluatedBindings if given, otherwise fall back on asking the bindings provider to give us some bindings
131.2073 -                var evaluatedBindings = (typeof bindings == "function") ? bindings(bindingContextInstance, node) : bindings;
131.2074 -                parsedBindings = evaluatedBindings || ko.bindingProvider['instance']['getBindings'](node, bindingContextInstance);
131.2075 -
131.2076 -                if (parsedBindings) {
131.2077 -                    // First run all the inits, so bindings can register for notification on changes
131.2078 -                    if (initPhase === 0) {
131.2079 -                        initPhase = 1;
131.2080 -                        for (var bindingKey in parsedBindings) {
131.2081 -                            var binding = ko.bindingHandlers[bindingKey];
131.2082 -                            if (binding && node.nodeType === 8)
131.2083 -                                validateThatBindingIsAllowedForVirtualElements(bindingKey);
131.2084 -
131.2085 -                            if (binding && typeof binding["init"] == "function") {
131.2086 -                                var handlerInitFn = binding["init"];
131.2087 -                                var initResult = handlerInitFn(node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel, bindingContextInstance);
131.2088 -
131.2089 -                                // If this binding handler claims to control descendant bindings, make a note of this
131.2090 -                                if (initResult && initResult['controlsDescendantBindings']) {
131.2091 -                                    if (bindingHandlerThatControlsDescendantBindings !== undefined)
131.2092 -                                        throw new Error("Multiple bindings (" + bindingHandlerThatControlsDescendantBindings + " and " + bindingKey + ") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");
131.2093 -                                    bindingHandlerThatControlsDescendantBindings = bindingKey;
131.2094 -                                }
131.2095 -                            }
131.2096 -                        }
131.2097 -                        initPhase = 2;
131.2098 -                    }
131.2099 -
131.2100 -                    // ... then run all the updates, which might trigger changes even on the first evaluation
131.2101 -                    if (initPhase === 2) {
131.2102 -                        for (var bindingKey in parsedBindings) {
131.2103 -                            var binding = ko.bindingHandlers[bindingKey];
131.2104 -                            if (binding && typeof binding["update"] == "function") {
131.2105 -                                var handlerUpdateFn = binding["update"];
131.2106 -                                handlerUpdateFn(node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel, bindingContextInstance);
131.2107 -                            }
131.2108 -                        }
131.2109 -                    }
131.2110 -                }
131.2111 -            },
131.2112 -            null,
131.2113 -            { disposeWhenNodeIsRemoved : node }
131.2114 -        );
131.2115 -
131.2116 -        return {
131.2117 -            shouldBindDescendants: bindingHandlerThatControlsDescendantBindings === undefined
131.2118 -        };
131.2119 -    };
131.2120 -
131.2121 -    var storedBindingContextDomDataKey = "__ko_bindingContext__";
131.2122 -    ko.storedBindingContextForNode = function (node, bindingContext) {
131.2123 -        if (arguments.length == 2)
131.2124 -            ko.utils.domData.set(node, storedBindingContextDomDataKey, bindingContext);
131.2125 -        else
131.2126 -            return ko.utils.domData.get(node, storedBindingContextDomDataKey);
131.2127 -    }
131.2128 -
131.2129 -    ko.applyBindingsToNode = function (node, bindings, viewModel) {
131.2130 -        if (node.nodeType === 1) // If it's an element, workaround IE <= 8 HTML parsing weirdness
131.2131 -            ko.virtualElements.normaliseVirtualElementDomStructure(node);
131.2132 -        return applyBindingsToNodeInternal(node, bindings, viewModel, true);
131.2133 -    };
131.2134 -
131.2135 -    ko.applyBindingsToDescendants = function(viewModel, rootNode) {
131.2136 -        if (rootNode.nodeType === 1 || rootNode.nodeType === 8)
131.2137 -            applyBindingsToDescendantsInternal(viewModel, rootNode, true);
131.2138 -    };
131.2139 -
131.2140 -    ko.applyBindings = function (viewModel, rootNode) {
131.2141 -        if (rootNode && (rootNode.nodeType !== 1) && (rootNode.nodeType !== 8))
131.2142 -            throw new Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
131.2143 -        rootNode = rootNode || window.document.body; // Make "rootNode" parameter optional
131.2144 -
131.2145 -        applyBindingsToNodeAndDescendantsInternal(viewModel, rootNode, true);
131.2146 -    };
131.2147 -
131.2148 -    // Retrieving binding context from arbitrary nodes
131.2149 -    ko.contextFor = function(node) {
131.2150 -        // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)
131.2151 -        switch (node.nodeType) {
131.2152 -            case 1:
131.2153 -            case 8:
131.2154 -                var context = ko.storedBindingContextForNode(node);
131.2155 -                if (context) return context;
131.2156 -                if (node.parentNode) return ko.contextFor(node.parentNode);
131.2157 -                break;
131.2158 -        }
131.2159 -        return undefined;
131.2160 -    };
131.2161 -    ko.dataFor = function(node) {
131.2162 -        var context = ko.contextFor(node);
131.2163 -        return context ? context['$data'] : undefined;
131.2164 -    };
131.2165 -
131.2166 -    ko.exportSymbol('bindingHandlers', ko.bindingHandlers);
131.2167 -    ko.exportSymbol('applyBindings', ko.applyBindings);
131.2168 -    ko.exportSymbol('applyBindingsToDescendants', ko.applyBindingsToDescendants);
131.2169 -    ko.exportSymbol('applyBindingsToNode', ko.applyBindingsToNode);
131.2170 -    ko.exportSymbol('contextFor', ko.contextFor);
131.2171 -    ko.exportSymbol('dataFor', ko.dataFor);
131.2172 -})();
131.2173 -var attrHtmlToJavascriptMap = { 'class': 'className', 'for': 'htmlFor' };
131.2174 -ko.bindingHandlers['attr'] = {
131.2175 -    'update': function(element, valueAccessor, allBindingsAccessor) {
131.2176 -        var value = ko.utils.unwrapObservable(valueAccessor()) || {};
131.2177 -        for (var attrName in value) {
131.2178 -            if (typeof attrName == "string") {
131.2179 -                var attrValue = ko.utils.unwrapObservable(value[attrName]);
131.2180 -
131.2181 -                // To cover cases like "attr: { checked:someProp }", we want to remove the attribute entirely
131.2182 -                // when someProp is a "no value"-like value (strictly null, false, or undefined)
131.2183 -                // (because the absence of the "checked" attr is how to mark an element as not checked, etc.)
131.2184 -                var toRemove = (attrValue === false) || (attrValue === null) || (attrValue === undefined);
131.2185 -                if (toRemove)
131.2186 -                    element.removeAttribute(attrName);
131.2187 -
131.2188 -                // In IE <= 7 and IE8 Quirks Mode, you have to use the Javascript property name instead of the
131.2189 -                // HTML attribute name for certain attributes. IE8 Standards Mode supports the correct behavior,
131.2190 -                // but instead of figuring out the mode, we'll just set the attribute through the Javascript
131.2191 -                // property for IE <= 8.
131.2192 -                if (ko.utils.ieVersion <= 8 && attrName in attrHtmlToJavascriptMap) {
131.2193 -                    attrName = attrHtmlToJavascriptMap[attrName];
131.2194 -                    if (toRemove)
131.2195 -                        element.removeAttribute(attrName);
131.2196 -                    else
131.2197 -                        element[attrName] = attrValue;
131.2198 -                } else if (!toRemove) {
131.2199 -                    try {
131.2200 -                        element.setAttribute(attrName, attrValue.toString());
131.2201 -                    } catch (err) {
131.2202 -                        // ignore for now
131.2203 -                        if (console) {
131.2204 -                            console.log("Can't set attribute " + attrName + " to " + attrValue + " error: " + err);
131.2205 -                        }
131.2206 -                    }
131.2207 -                }
131.2208 -
131.2209 -                // Treat "name" specially - although you can think of it as an attribute, it also needs
131.2210 -                // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)
131.2211 -                // Deliberately being case-sensitive here because XHTML would regard "Name" as a different thing
131.2212 -                // entirely, and there's no strong reason to allow for such casing in HTML.
131.2213 -                if (attrName === "name") {
131.2214 -                    ko.utils.setElementName(element, toRemove ? "" : attrValue.toString());
131.2215 -                }
131.2216 -            }
131.2217 -        }
131.2218 -    }
131.2219 -};
131.2220 -ko.bindingHandlers['checked'] = {
131.2221 -    'init': function (element, valueAccessor, allBindingsAccessor) {
131.2222 -        var updateHandler = function() {
131.2223 -            var valueToWrite;
131.2224 -            if (element.type == "checkbox") {
131.2225 -                valueToWrite = element.checked;
131.2226 -            } else if ((element.type == "radio") && (element.checked)) {
131.2227 -                valueToWrite = element.value;
131.2228 -            } else {
131.2229 -                return; // "checked" binding only responds to checkboxes and selected radio buttons
131.2230 -            }
131.2231 -
131.2232 -            var modelValue = valueAccessor(), unwrappedValue = ko.utils.unwrapObservable(modelValue);
131.2233 -            if ((element.type == "checkbox") && (unwrappedValue instanceof Array)) {
131.2234 -                // For checkboxes bound to an array, we add/remove the checkbox value to that array
131.2235 -                // This works for both observable and non-observable arrays
131.2236 -                var existingEntryIndex = ko.utils.arrayIndexOf(unwrappedValue, element.value);
131.2237 -                if (element.checked && (existingEntryIndex < 0))
131.2238 -                    modelValue.push(element.value);
131.2239 -                else if ((!element.checked) && (existingEntryIndex >= 0))
131.2240 -                    modelValue.splice(existingEntryIndex, 1);
131.2241 -            } else {
131.2242 -                ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'checked', valueToWrite, true);
131.2243 -            }
131.2244 -        };
131.2245 -        ko.utils.registerEventHandler(element, "click", updateHandler);
131.2246 -
131.2247 -        // IE 6 won't allow radio buttons to be selected unless they have a name
131.2248 -        if ((element.type == "radio") && !element.name)
131.2249 -            ko.bindingHandlers['uniqueName']['init'](element, function() { return true });
131.2250 -    },
131.2251 -    'update': function (element, valueAccessor) {
131.2252 -        var value = ko.utils.unwrapObservable(valueAccessor());
131.2253 -
131.2254 -        if (element.type == "checkbox") {
131.2255 -            if (value instanceof Array) {
131.2256 -                // When bound to an array, the checkbox being checked represents its value being present in that array
131.2257 -                element.checked = ko.utils.arrayIndexOf(value, element.value) >= 0;
131.2258 -            } else {
131.2259 -                // When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
131.2260 -                element.checked = value;
131.2261 -            }
131.2262 -        } else if (element.type == "radio") {
131.2263 -            element.checked = (element.value == value);
131.2264 -        }
131.2265 -    }
131.2266 -};
131.2267 -var classesWrittenByBindingKey = '__ko__cssValue';
131.2268 -ko.bindingHandlers['css'] = {
131.2269 -    'update': function (element, valueAccessor) {
131.2270 -        var value = ko.utils.unwrapObservable(valueAccessor());
131.2271 -        if (typeof value == "object") {
131.2272 -            for (var className in value) {
131.2273 -                var shouldHaveClass = ko.utils.unwrapObservable(value[className]);
131.2274 -                ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
131.2275 -            }
131.2276 -        } else {
131.2277 -            value = String(value || ''); // Make sure we don't try to store or set a non-string value
131.2278 -            ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);
131.2279 -            element[classesWrittenByBindingKey] = value;
131.2280 -            ko.utils.toggleDomNodeCssClass(element, value, true);
131.2281 -        }
131.2282 -    }
131.2283 -};
131.2284 -ko.bindingHandlers['enable'] = {
131.2285 -    'update': function (element, valueAccessor) {
131.2286 -        var value = ko.utils.unwrapObservable(valueAccessor());
131.2287 -        if (value && element.disabled)
131.2288 -            element.removeAttribute("disabled");
131.2289 -        else if ((!value) && (!element.disabled))
131.2290 -            element.disabled = true;
131.2291 -    }
131.2292 -};
131.2293 -
131.2294 -ko.bindingHandlers['disable'] = {
131.2295 -    'update': function (element, valueAccessor) {
131.2296 -        ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });
131.2297 -    }
131.2298 -};
131.2299 -// For certain common events (currently just 'click'), allow a simplified data-binding syntax
131.2300 -// e.g. click:handler instead of the usual full-length event:{click:handler}
131.2301 -function makeEventHandlerShortcut(eventName) {
131.2302 -    ko.bindingHandlers[eventName] = {
131.2303 -        'init': function(element, valueAccessor, allBindingsAccessor, viewModel) {
131.2304 -            var newValueAccessor = function () {
131.2305 -                var result = {};
131.2306 -                result[eventName] = valueAccessor();
131.2307 -                return result;
131.2308 -            };
131.2309 -            return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindingsAccessor, viewModel);
131.2310 -        }
131.2311 -    }
131.2312 -}
131.2313 -
131.2314 -ko.bindingHandlers['event'] = {
131.2315 -    'init' : function (element, valueAccessor, allBindingsAccessor, viewModel) {
131.2316 -        var eventsToHandle = valueAccessor() || {};
131.2317 -        for(var eventNameOutsideClosure in eventsToHandle) {
131.2318 -            (function() {
131.2319 -                var eventName = eventNameOutsideClosure; // Separate variable to be captured by event handler closure
131.2320 -                if (typeof eventName == "string") {
131.2321 -                    ko.utils.registerEventHandler(element, eventName, function (event) {
131.2322 -                        var handlerReturnValue;
131.2323 -                        var handlerFunction = valueAccessor()[eventName];
131.2324 -                        if (!handlerFunction)
131.2325 -                            return;
131.2326 -                        var allBindings = allBindingsAccessor();
131.2327 -
131.2328 -                        try {
131.2329 -                            // Take all the event args, and prefix with the viewmodel
131.2330 -                            var argsForHandler = ko.utils.makeArray(arguments);
131.2331 -                            argsForHandler.unshift(viewModel);
131.2332 -                            handlerReturnValue = handlerFunction.apply(viewModel, argsForHandler);
131.2333 -                        } finally {
131.2334 -                            if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
131.2335 -                                if (event.preventDefault)
131.2336 -                                    event.preventDefault();
131.2337 -                                else
131.2338 -                                    event.returnValue = false;
131.2339 -                            }
131.2340 -                        }
131.2341 -
131.2342 -                        var bubble = allBindings[eventName + 'Bubble'] !== false;
131.2343 -                        if (!bubble) {
131.2344 -                            event.cancelBubble = true;
131.2345 -                            if (event.stopPropagation)
131.2346 -                                event.stopPropagation();
131.2347 -                        }
131.2348 -                    });
131.2349 -                }
131.2350 -            })();
131.2351 -        }
131.2352 -    }
131.2353 -};
131.2354 -// "foreach: someExpression" is equivalent to "template: { foreach: someExpression }"
131.2355 -// "foreach: { data: someExpression, afterAdd: myfn }" is equivalent to "template: { foreach: someExpression, afterAdd: myfn }"
131.2356 -ko.bindingHandlers['foreach'] = {
131.2357 -    makeTemplateValueAccessor: function(valueAccessor) {
131.2358 -        return function() {
131.2359 -            var modelValue = valueAccessor(),
131.2360 -                unwrappedValue = ko.utils.peekObservable(modelValue);    // Unwrap without setting a dependency here
131.2361 -
131.2362 -            // If unwrappedValue is the array, pass in the wrapped value on its own
131.2363 -            // The value will be unwrapped and tracked within the template binding
131.2364 -            // (See https://github.com/SteveSanderson/knockout/issues/523)
131.2365 -            if ((!unwrappedValue) || typeof unwrappedValue.length == "number")
131.2366 -                return { 'foreach': modelValue, 'templateEngine': ko.nativeTemplateEngine.instance };
131.2367 -
131.2368 -            // If unwrappedValue.data is the array, preserve all relevant options and unwrap again value so we get updates
131.2369 -            ko.utils.unwrapObservable(modelValue);
131.2370 -            return {
131.2371 -                'foreach': unwrappedValue['data'],
131.2372 -                'as': unwrappedValue['as'],
131.2373 -                'includeDestroyed': unwrappedValue['includeDestroyed'],
131.2374 -                'afterAdd': unwrappedValue['afterAdd'],
131.2375 -                'beforeRemove': unwrappedValue['beforeRemove'],
131.2376 -                'afterRender': unwrappedValue['afterRender'],
131.2377 -                'beforeMove': unwrappedValue['beforeMove'],
131.2378 -                'afterMove': unwrappedValue['afterMove'],
131.2379 -                'templateEngine': ko.nativeTemplateEngine.instance
131.2380 -            };
131.2381 -        };
131.2382 -    },
131.2383 -    'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
131.2384 -        return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));
131.2385 -    },
131.2386 -    'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
131.2387 -        return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindingsAccessor, viewModel, bindingContext);
131.2388 -    }
131.2389 -};
131.2390 -ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings
131.2391 -ko.virtualElements.allowedBindings['foreach'] = true;
131.2392 -var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';
131.2393 -ko.bindingHandlers['hasfocus'] = {
131.2394 -    'init': function(element, valueAccessor, allBindingsAccessor) {
131.2395 -        var handleElementFocusChange = function(isFocused) {
131.2396 -            // Where possible, ignore which event was raised and determine focus state using activeElement,
131.2397 -            // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.
131.2398 -            // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,
131.2399 -            // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus
131.2400 -            // from calling 'blur()' on the element when it loses focus.
131.2401 -            // Discussion at https://github.com/SteveSanderson/knockout/pull/352
131.2402 -            element[hasfocusUpdatingProperty] = true;
131.2403 -            var ownerDoc = element.ownerDocument;
131.2404 -            if ("activeElement" in ownerDoc) {
131.2405 -                isFocused = (ownerDoc.activeElement === element);
131.2406 -            }
131.2407 -            var modelValue = valueAccessor();
131.2408 -            ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'hasfocus', isFocused, true);
131.2409 -            element[hasfocusUpdatingProperty] = false;
131.2410 -        };
131.2411 -        var handleElementFocusIn = handleElementFocusChange.bind(null, true);
131.2412 -        var handleElementFocusOut = handleElementFocusChange.bind(null, false);
131.2413 -
131.2414 -        ko.utils.registerEventHandler(element, "focus", handleElementFocusIn);
131.2415 -        ko.utils.registerEventHandler(element, "focusin", handleElementFocusIn); // For IE
131.2416 -        ko.utils.registerEventHandler(element, "blur",  handleElementFocusOut);
131.2417 -        ko.utils.registerEventHandler(element, "focusout",  handleElementFocusOut); // For IE
131.2418 -    },
131.2419 -    'update': function(element, valueAccessor) {
131.2420 -        var value = ko.utils.unwrapObservable(valueAccessor());
131.2421 -        if (!element[hasfocusUpdatingProperty]) {
131.2422 -            value ? element.focus() : element.blur();
131.2423 -            ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, value ? "focusin" : "focusout"]); // For IE, which doesn't reliably fire "focus" or "blur" events synchronously
131.2424 -        }
131.2425 -    }
131.2426 -};
131.2427 -ko.bindingHandlers['html'] = {
131.2428 -    'init': function() {
131.2429 -        // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
131.2430 -        return { 'controlsDescendantBindings': true };
131.2431 -    },
131.2432 -    'update': function (element, valueAccessor) {
131.2433 -        // setHtml will unwrap the value if needed
131.2434 -        ko.utils.setHtml(element, valueAccessor());
131.2435 -    }
131.2436 -};
131.2437 -var withIfDomDataKey = '__ko_withIfBindingData';
131.2438 -// Makes a binding like with or if
131.2439 -function makeWithIfBinding(bindingKey, isWith, isNot, makeContextCallback) {
131.2440 -    ko.bindingHandlers[bindingKey] = {
131.2441 -        'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
131.2442 -            ko.utils.domData.set(element, withIfDomDataKey, {});
131.2443 -            return { 'controlsDescendantBindings': true };
131.2444 -        },
131.2445 -        'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
131.2446 -            var withIfData = ko.utils.domData.get(element, withIfDomDataKey),
131.2447 -                dataValue = ko.utils.unwrapObservable(valueAccessor()),
131.2448 -                shouldDisplay = !isNot !== !dataValue, // equivalent to isNot ? !dataValue : !!dataValue
131.2449 -                isFirstRender = !withIfData.savedNodes,
131.2450 -                needsRefresh = isFirstRender || isWith || (shouldDisplay !== withIfData.didDisplayOnLastUpdate);
131.2451 -
131.2452 -            if (needsRefresh) {
131.2453 -                if (isFirstRender) {
131.2454 -                    withIfData.savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);
131.2455 -                }
131.2456 -
131.2457 -                if (shouldDisplay) {
131.2458 -                    if (!isFirstRender) {
131.2459 -                        ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(withIfData.savedNodes));
131.2460 -                    }
131.2461 -                    ko.applyBindingsToDescendants(makeContextCallback ? makeContextCallback(bindingContext, dataValue) : bindingContext, element);
131.2462 -                } else {
131.2463 -                    ko.virtualElements.emptyNode(element);
131.2464 -                }
131.2465 -
131.2466 -                withIfData.didDisplayOnLastUpdate = shouldDisplay;
131.2467 -            }
131.2468 -        }
131.2469 -    };
131.2470 -    ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings
131.2471 -    ko.virtualElements.allowedBindings[bindingKey] = true;
131.2472 -}
131.2473 -
131.2474 -// Construct the actual binding handlers
131.2475 -makeWithIfBinding('if');
131.2476 -makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);
131.2477 -makeWithIfBinding('with', true /* isWith */, false /* isNot */,
131.2478 -    function(bindingContext, dataValue) {
131.2479 -        return bindingContext['createChildContext'](dataValue);
131.2480 -    }
131.2481 -);
131.2482 -function ensureDropdownSelectionIsConsistentWithModelValue(element, modelValue, preferModelValue) {
131.2483 -    if (preferModelValue) {
131.2484 -        if (modelValue !== ko.selectExtensions.readValue(element))
131.2485 -            ko.selectExtensions.writeValue(element, modelValue);
131.2486 -    }
131.2487 -
131.2488 -    // No matter which direction we're syncing in, we want the end result to be equality between dropdown value and model value.
131.2489 -    // If they aren't equal, either we prefer the dropdown value, or the model value couldn't be represented, so either way,
131.2490 -    // change the model value to match the dropdown.
131.2491 -    if (modelValue !== ko.selectExtensions.readValue(element))
131.2492 -        ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
131.2493 -};
131.2494 -
131.2495 -ko.bindingHandlers['options'] = {
131.2496 -    'update': function (element, valueAccessor, allBindingsAccessor) {
131.2497 -        if (ko.utils.tagNameLower(element) !== "select")
131.2498 -            throw new Error("options binding applies only to SELECT elements");
131.2499 -
131.2500 -        var selectWasPreviouslyEmpty = element.length == 0;
131.2501 -        var previousSelectedValues = ko.utils.arrayMap(ko.utils.arrayFilter(element.childNodes, function (node) {
131.2502 -            return node.tagName && (ko.utils.tagNameLower(node) === "option") && node.selected;
131.2503 -        }), function (node) {
131.2504 -            return ko.selectExtensions.readValue(node) || node.innerText || node.textContent;
131.2505 -        });
131.2506 -        var previousScrollTop = element.scrollTop;
131.2507 -
131.2508 -        var value = ko.utils.unwrapObservable(valueAccessor());
131.2509 -        var selectedValue = element.value;
131.2510 -
131.2511 -        // Remove all existing <option>s.
131.2512 -        // Need to use .remove() rather than .removeChild() for <option>s otherwise IE behaves oddly (https://github.com/SteveSanderson/knockout/issues/134)
131.2513 -        while (element.length > 0) {
131.2514 -            ko.cleanNode(element.options[0]);
131.2515 -            element.remove(0);
131.2516 -        }
131.2517 -
131.2518 -        if (value) {
131.2519 -            var allBindings = allBindingsAccessor(),
131.2520 -                includeDestroyed = allBindings['optionsIncludeDestroyed'];
131.2521 -
131.2522 -            if (typeof value.length != "number")
131.2523 -                value = [value];
131.2524 -            if (allBindings['optionsCaption']) {
131.2525 -                var option = document.createElement("option");
131.2526 -                ko.utils.setHtml(option, allBindings['optionsCaption']);
131.2527 -                ko.selectExtensions.writeValue(option, undefined);
131.2528 -                element.appendChild(option);
131.2529 -            }
131.2530 -
131.2531 -            for (var i = 0, j = value.length; i < j; i++) {
131.2532 -                // Skip destroyed items
131.2533 -                var arrayEntry = value[i];
131.2534 -                if (arrayEntry && arrayEntry['_destroy'] && !includeDestroyed)
131.2535 -                    continue;
131.2536 -
131.2537 -                var option = document.createElement("option");
131.2538 -
131.2539 -                function applyToObject(object, predicate, defaultValue) {
131.2540 -                    var predicateType = typeof predicate;
131.2541 -                    if (predicateType == "function")    // Given a function; run it against the data value
131.2542 -                        return predicate(object);
131.2543 -                    else if (predicateType == "string") // Given a string; treat it as a property name on the data value
131.2544 -                        return object[predicate];
131.2545 -                    else                                // Given no optionsText arg; use the data value itself
131.2546 -                        return defaultValue;
131.2547 -                }
131.2548 -
131.2549 -                // Apply a value to the option element
131.2550 -                var optionValue = applyToObject(arrayEntry, allBindings['optionsValue'], arrayEntry);
131.2551 -                ko.selectExtensions.writeValue(option, ko.utils.unwrapObservable(optionValue));
131.2552 -
131.2553 -                // Apply some text to the option element
131.2554 -                var optionText = applyToObject(arrayEntry, allBindings['optionsText'], optionValue);
131.2555 -                ko.utils.setTextContent(option, optionText);
131.2556 -
131.2557 -                element.appendChild(option);
131.2558 -            }
131.2559 -
131.2560 -            // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
131.2561 -            // That's why we first added them without selection. Now it's time to set the selection.
131.2562 -            var newOptions = element.getElementsByTagName("option");
131.2563 -            var countSelectionsRetained = 0;
131.2564 -            for (var i = 0, j = newOptions.length; i < j; i++) {
131.2565 -                if (ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[i])) >= 0) {
131.2566 -                    ko.utils.setOptionNodeSelectionState(newOptions[i], true);
131.2567 -                    countSelectionsRetained++;
131.2568 -                }
131.2569 -            }
131.2570 -
131.2571 -            element.scrollTop = previousScrollTop;
131.2572 -
131.2573 -            if (selectWasPreviouslyEmpty && ('value' in allBindings)) {
131.2574 -                // Ensure consistency between model value and selected option.
131.2575 -                // If the dropdown is being populated for the first time here (or was otherwise previously empty),
131.2576 -                // the dropdown selection state is meaningless, so we preserve the model value.
131.2577 -                ensureDropdownSelectionIsConsistentWithModelValue(element, ko.utils.peekObservable(allBindings['value']), /* preferModelValue */ true);
131.2578 -            }
131.2579 -
131.2580 -            // Workaround for IE9 bug
131.2581 -            ko.utils.ensureSelectElementIsRenderedCorrectly(element);
131.2582 -        }
131.2583 -    }
131.2584 -};
131.2585 -ko.bindingHandlers['options'].optionValueDomDataKey = '__ko.optionValueDomData__';
131.2586 -ko.bindingHandlers['selectedOptions'] = {
131.2587 -    'init': function (element, valueAccessor, allBindingsAccessor) {
131.2588 -        ko.utils.registerEventHandler(element, "change", function () {
131.2589 -            var value = valueAccessor(), valueToWrite = [];
131.2590 -            ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
131.2591 -                if (node.selected)
131.2592 -                    valueToWrite.push(ko.selectExtensions.readValue(node));
131.2593 -            });
131.2594 -            ko.expressionRewriting.writeValueToProperty(value, allBindingsAccessor, 'value', valueToWrite);
131.2595 -        });
131.2596 -    },
131.2597 -    'update': function (element, valueAccessor) {
131.2598 -        if (ko.utils.tagNameLower(element) != "select")
131.2599 -            throw new Error("values binding applies only to SELECT elements");
131.2600 -
131.2601 -        var newValue = ko.utils.unwrapObservable(valueAccessor());
131.2602 -        if (newValue && typeof newValue.length == "number") {
131.2603 -            ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
131.2604 -                var isSelected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;
131.2605 -                ko.utils.setOptionNodeSelectionState(node, isSelected);
131.2606 -            });
131.2607 -        }
131.2608 -    }
131.2609 -};
131.2610 -ko.bindingHandlers['style'] = {
131.2611 -    'update': function (element, valueAccessor) {
131.2612 -        var value = ko.utils.unwrapObservable(valueAccessor() || {});
131.2613 -        for (var styleName in value) {
131.2614 -            if (typeof styleName == "string") {
131.2615 -                var styleValue = ko.utils.unwrapObservable(value[styleName]);
131.2616 -                element.style[styleName] = styleValue || ""; // Empty string removes the value, whereas null/undefined have no effect
131.2617 -            }
131.2618 -        }
131.2619 -    }
131.2620 -};
131.2621 -ko.bindingHandlers['submit'] = {
131.2622 -    'init': function (element, valueAccessor, allBindingsAccessor, viewModel) {
131.2623 -        if (typeof valueAccessor() != "function")
131.2624 -            throw new Error("The value for a submit binding must be a function");
131.2625 -        ko.utils.registerEventHandler(element, "submit", function (event) {
131.2626 -            var handlerReturnValue;
131.2627 -            var value = valueAccessor();
131.2628 -            try { handlerReturnValue = value.call(viewModel, element); }
131.2629 -            finally {
131.2630 -                if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
131.2631 -                    if (event.preventDefault)
131.2632 -                        event.preventDefault();
131.2633 -                    else
131.2634 -                        event.returnValue = false;
131.2635 -                }
131.2636 -            }
131.2637 -        });
131.2638 -    }
131.2639 -};
131.2640 -ko.bindingHandlers['text'] = {
131.2641 -    'update': function (element, valueAccessor) {
131.2642 -        ko.utils.setTextContent(element, valueAccessor());
131.2643 -    }
131.2644 -};
131.2645 -ko.virtualElements.allowedBindings['text'] = true;
131.2646 -ko.bindingHandlers['uniqueName'] = {
131.2647 -    'init': function (element, valueAccessor) {
131.2648 -        if (valueAccessor()) {
131.2649 -            var name = "ko_unique_" + (++ko.bindingHandlers['uniqueName'].currentIndex);
131.2650 -            ko.utils.setElementName(element, name);
131.2651 -        }
131.2652 -    }
131.2653 -};
131.2654 -ko.bindingHandlers['uniqueName'].currentIndex = 0;
131.2655 -ko.bindingHandlers['value'] = {
131.2656 -    'init': function (element, valueAccessor, allBindingsAccessor) {
131.2657 -        // Always catch "change" event; possibly other events too if asked
131.2658 -        var eventsToCatch = ["change"];
131.2659 -        var requestedEventsToCatch = allBindingsAccessor()["valueUpdate"];
131.2660 -        var propertyChangedFired = false;
131.2661 -        if (requestedEventsToCatch) {
131.2662 -            if (typeof requestedEventsToCatch == "string") // Allow both individual event names, and arrays of event names
131.2663 -                requestedEventsToCatch = [requestedEventsToCatch];
131.2664 -            ko.utils.arrayPushAll(eventsToCatch, requestedEventsToCatch);
131.2665 -            eventsToCatch = ko.utils.arrayGetDistinctValues(eventsToCatch);
131.2666 -        }
131.2667 -
131.2668 -        var valueUpdateHandler = function() {
131.2669 -            propertyChangedFired = false;
131.2670 -            var modelValue = valueAccessor();
131.2671 -            var elementValue = ko.selectExtensions.readValue(element);
131.2672 -            ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'value', elementValue);
131.2673 -        }
131.2674 -
131.2675 -        // Workaround for https://github.com/SteveSanderson/knockout/issues/122
131.2676 -        // IE doesn't fire "change" events on textboxes if the user selects a value from its autocomplete list
131.2677 -        var ieAutoCompleteHackNeeded = ko.utils.ieVersion && element.tagName.toLowerCase() == "input" && element.type == "text"
131.2678 -                                       && element.autocomplete != "off" && (!element.form || element.form.autocomplete != "off");
131.2679 -        if (ieAutoCompleteHackNeeded && ko.utils.arrayIndexOf(eventsToCatch, "propertychange") == -1) {
131.2680 -            ko.utils.registerEventHandler(element, "propertychange", function () { propertyChangedFired = true });
131.2681 -            ko.utils.registerEventHandler(element, "blur", function() {
131.2682 -                if (propertyChangedFired) {
131.2683 -                    valueUpdateHandler();
131.2684 -                }
131.2685 -            });
131.2686 -        }
131.2687 -
131.2688 -        ko.utils.arrayForEach(eventsToCatch, function(eventName) {
131.2689 -            // The syntax "after<eventname>" means "run the handler asynchronously after the event"
131.2690 -            // This is useful, for example, to catch "keydown" events after the browser has updated the control
131.2691 -            // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)
131.2692 -            var handler = valueUpdateHandler;
131.2693 -            if (ko.utils.stringStartsWith(eventName, "after")) {
131.2694 -                handler = function() { setTimeout(valueUpdateHandler, 0) };
131.2695 -                eventName = eventName.substring("after".length);
131.2696 -            }
131.2697 -            ko.utils.registerEventHandler(element, eventName, handler);
131.2698 -        });
131.2699 -    },
131.2700 -    'update': function (element, valueAccessor) {
131.2701 -        var valueIsSelectOption = ko.utils.tagNameLower(element) === "select";
131.2702 -        var newValue = ko.utils.unwrapObservable(valueAccessor());
131.2703 -        var elementValue = ko.selectExtensions.readValue(element);
131.2704 -        var valueHasChanged = (newValue != elementValue);
131.2705 -
131.2706 -        // JavaScript's 0 == "" behavious is unfortunate here as it prevents writing 0 to an empty text box (loose equality suggests the values are the same).
131.2707 -        // We don't want to do a strict equality comparison as that is more confusing for developers in certain cases, so we specifically special case 0 != "" here.
131.2708 -        if ((newValue === 0) && (elementValue !== 0) && (elementValue !== "0"))
131.2709 -            valueHasChanged = true;
131.2710 -
131.2711 -        if (valueHasChanged) {
131.2712 -            var applyValueAction = function () { ko.selectExtensions.writeValue(element, newValue); };
131.2713 -            applyValueAction();
131.2714 -
131.2715 -            // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread
131.2716 -            // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread
131.2717 -            // to apply the value as well.
131.2718 -            var alsoApplyAsynchronously = valueIsSelectOption;
131.2719 -            if (alsoApplyAsynchronously)
131.2720 -                setTimeout(applyValueAction, 0);
131.2721 -        }
131.2722 -
131.2723 -        // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,
131.2724 -        // because you're not allowed to have a model value that disagrees with a visible UI selection.
131.2725 -        if (valueIsSelectOption && (element.length > 0))
131.2726 -            ensureDropdownSelectionIsConsistentWithModelValue(element, newValue, /* preferModelValue */ false);
131.2727 -    }
131.2728 -};
131.2729 -ko.bindingHandlers['visible'] = {
131.2730 -    'update': function (element, valueAccessor) {
131.2731 -        var value = ko.utils.unwrapObservable(valueAccessor());
131.2732 -        var isCurrentlyVisible = !(element.style.display == "none");
131.2733 -        if (value && !isCurrentlyVisible)
131.2734 -            element.style.display = "";
131.2735 -        else if ((!value) && isCurrentlyVisible)
131.2736 -            element.style.display = "none";
131.2737 -    }
131.2738 -};
131.2739 -// 'click' is just a shorthand for the usual full-length event:{click:handler}
131.2740 -makeEventHandlerShortcut('click');
131.2741 -// If you want to make a custom template engine,
131.2742 -//
131.2743 -// [1] Inherit from this class (like ko.nativeTemplateEngine does)
131.2744 -// [2] Override 'renderTemplateSource', supplying a function with this signature:
131.2745 -//
131.2746 -//        function (templateSource, bindingContext, options) {
131.2747 -//            // - templateSource.text() is the text of the template you should render
131.2748 -//            // - bindingContext.$data is the data you should pass into the template
131.2749 -//            //   - you might also want to make bindingContext.$parent, bindingContext.$parents,
131.2750 -//            //     and bindingContext.$root available in the template too
131.2751 -//            // - options gives you access to any other properties set on "data-bind: { template: options }"
131.2752 -//            //
131.2753 -//            // Return value: an array of DOM nodes
131.2754 -//        }
131.2755 -//
131.2756 -// [3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:
131.2757 -//
131.2758 -//        function (script) {
131.2759 -//            // Return value: Whatever syntax means "Evaluate the JavaScript statement 'script' and output the result"
131.2760 -//            //               For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'
131.2761 -//        }
131.2762 -//
131.2763 -//     This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.
131.2764 -//     If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)
131.2765 -//     and then you don't need to override 'createJavaScriptEvaluatorBlock'.
131.2766 -
131.2767 -ko.templateEngine = function () { };
131.2768 -
131.2769 -ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
131.2770 -    throw new Error("Override renderTemplateSource");
131.2771 -};
131.2772 -
131.2773 -ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {
131.2774 -    throw new Error("Override createJavaScriptEvaluatorBlock");
131.2775 -};
131.2776 -
131.2777 -ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {
131.2778 -    // Named template
131.2779 -    if (typeof template == "string") {
131.2780 -        templateDocument = templateDocument || document;
131.2781 -        var elem = templateDocument.getElementById(template);
131.2782 -        if (!elem)
131.2783 -            throw new Error("Cannot find template with ID " + template);
131.2784 -        return new ko.templateSources.domElement(elem);
131.2785 -    } else if ((template.nodeType == 1) || (template.nodeType == 8)) {
131.2786 -        // Anonymous template
131.2787 -        return new ko.templateSources.anonymousTemplate(template);
131.2788 -    } else
131.2789 -        throw new Error("Unknown template type: " + template);
131.2790 -};
131.2791 -
131.2792 -ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {
131.2793 -    var templateSource = this['makeTemplateSource'](template, templateDocument);
131.2794 -    return this['renderTemplateSource'](templateSource, bindingContext, options);
131.2795 -};
131.2796 -
131.2797 -ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {
131.2798 -    // Skip rewriting if requested
131.2799 -    if (this['allowTemplateRewriting'] === false)
131.2800 -        return true;
131.2801 -    return this['makeTemplateSource'](template, templateDocument)['data']("isRewritten");
131.2802 -};
131.2803 -
131.2804 -ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCallback, templateDocument) {
131.2805 -    var templateSource = this['makeTemplateSource'](template, templateDocument);
131.2806 -    var rewritten = rewriterCallback(templateSource['text']());
131.2807 -    templateSource['text'](rewritten);
131.2808 -    templateSource['data']("isRewritten", true);
131.2809 -};
131.2810 -
131.2811 -ko.exportSymbol('templateEngine', ko.templateEngine);
131.2812 -
131.2813 -ko.templateRewriting = (function () {
131.2814 -    var memoizeDataBindingAttributeSyntaxRegex = /(<[a-z]+\d*(\s+(?!data-bind=)[a-z0-9\-]+(=(\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind=(["'])([\s\S]*?)\5/gi;
131.2815 -    var memoizeVirtualContainerBindingSyntaxRegex = /<!--\s*ko\b\s*([\s\S]*?)\s*-->/g;
131.2816 -
131.2817 -    function validateDataBindValuesForRewriting(keyValueArray) {
131.2818 -        var allValidators = ko.expressionRewriting.bindingRewriteValidators;
131.2819 -        for (var i = 0; i < keyValueArray.length; i++) {
131.2820 -            var key = keyValueArray[i]['key'];
131.2821 -            if (allValidators.hasOwnProperty(key)) {
131.2822 -                var validator = allValidators[key];
131.2823 -
131.2824 -                if (typeof validator === "function") {
131.2825 -                    var possibleErrorMessage = validator(keyValueArray[i]['value']);
131.2826 -                    if (possibleErrorMessage)
131.2827 -                        throw new Error(possibleErrorMessage);
131.2828 -                } else if (!validator) {
131.2829 -                    throw new Error("This template engine does not support the '" + key + "' binding within its templates");
131.2830 -                }
131.2831 -            }
131.2832 -        }
131.2833 -    }
131.2834 -
131.2835 -    function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, templateEngine) {
131.2836 -        var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);
131.2837 -        validateDataBindValuesForRewriting(dataBindKeyValueArray);
131.2838 -        var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray);
131.2839 -
131.2840 -        // For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional
131.2841 -        // anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this
131.2842 -        // extra indirection.
131.2843 -        var applyBindingsToNextSiblingScript =
131.2844 -            "ko.__tr_ambtns(function($context,$element){return(function(){return{ " + rewrittenDataBindAttributeValue + " } })()})";
131.2845 -        return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;
131.2846 -    }
131.2847 -
131.2848 -    return {
131.2849 -        ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {
131.2850 -            if (!templateEngine['isTemplateRewritten'](template, templateDocument))
131.2851 -                templateEngine['rewriteTemplate'](template, function (htmlString) {
131.2852 -                    return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);
131.2853 -                }, templateDocument);
131.2854 -        },
131.2855 -
131.2856 -        memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {
131.2857 -            return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {
131.2858 -                return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[6], /* tagToRetain: */ arguments[1], templateEngine);
131.2859 -            }).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {
131.2860 -                return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ "<!-- ko -->", templateEngine);
131.2861 -            });
131.2862 -        },
131.2863 -
131.2864 -        applyMemoizedBindingsToNextSibling: function (bindings) {
131.2865 -            return ko.memoization.memoize(function (domNode, bindingContext) {
131.2866 -                if (domNode.nextSibling)
131.2867 -                    ko.applyBindingsToNode(domNode.nextSibling, bindings, bindingContext);
131.2868 -            });
131.2869 -        }
131.2870 -    }
131.2871 -})();
131.2872 -
131.2873 -
131.2874 -// Exported only because it has to be referenced by string lookup from within rewritten template
131.2875 -ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);
131.2876 -(function() {
131.2877 -    // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving
131.2878 -    // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)
131.2879 -    //
131.2880 -    // Two are provided by default:
131.2881 -    //  1. ko.templateSources.domElement       - reads/writes the text content of an arbitrary DOM element
131.2882 -    //  2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but
131.2883 -    //                                           without reading/writing the actual element text content, since it will be overwritten
131.2884 -    //                                           with the rendered template output.
131.2885 -    // You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.
131.2886 -    // Template sources need to have the following functions:
131.2887 -    //   text() 			- returns the template text from your storage location
131.2888 -    //   text(value)		- writes the supplied template text to your storage location
131.2889 -    //   data(key)			- reads values stored using data(key, value) - see below
131.2890 -    //   data(key, value)	- associates "value" with this template and the key "key". Is used to store information like "isRewritten".
131.2891 -    //
131.2892 -    // Optionally, template sources can also have the following functions:
131.2893 -    //   nodes()            - returns a DOM element containing the nodes of this template, where available
131.2894 -    //   nodes(value)       - writes the given DOM element to your storage location
131.2895 -    // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()
131.2896 -    // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().
131.2897 -    //
131.2898 -    // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were
131.2899 -    // using and overriding "makeTemplateSource" to return an instance of your custom template source.
131.2900 -
131.2901 -    ko.templateSources = {};
131.2902 -
131.2903 -    // ---- ko.templateSources.domElement -----
131.2904 -
131.2905 -    ko.templateSources.domElement = function(element) {
131.2906 -        this.domElement = element;
131.2907 -    }
131.2908 -
131.2909 -    ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {
131.2910 -        var tagNameLower = ko.utils.tagNameLower(this.domElement),
131.2911 -            elemContentsProperty = tagNameLower === "script" ? "text"
131.2912 -                                 : tagNameLower === "textarea" ? "value"
131.2913 -                                 : "innerHTML";
131.2914 -
131.2915 -        if (arguments.length == 0) {
131.2916 -            return this.domElement[elemContentsProperty];
131.2917 -        } else {
131.2918 -            var valueToWrite = arguments[0];
131.2919 -            if (elemContentsProperty === "innerHTML")
131.2920 -                ko.utils.setHtml(this.domElement, valueToWrite);
131.2921 -            else
131.2922 -                this.domElement[elemContentsProperty] = valueToWrite;
131.2923 -        }
131.2924 -    };
131.2925 -
131.2926 -    ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {
131.2927 -        if (arguments.length === 1) {
131.2928 -            return ko.utils.domData.get(this.domElement, "templateSourceData_" + key);
131.2929 -        } else {
131.2930 -            ko.utils.domData.set(this.domElement, "templateSourceData_" + key, arguments[1]);
131.2931 -        }
131.2932 -    };
131.2933 -
131.2934 -    // ---- ko.templateSources.anonymousTemplate -----
131.2935 -    // Anonymous templates are normally saved/retrieved as DOM nodes through "nodes".
131.2936 -    // For compatibility, you can also read "text"; it will be serialized from the nodes on demand.
131.2937 -    // Writing to "text" is still supported, but then the template data will not be available as DOM nodes.
131.2938 -
131.2939 -    var anonymousTemplatesDomDataKey = "__ko_anon_template__";
131.2940 -    ko.templateSources.anonymousTemplate = function(element) {
131.2941 -        this.domElement = element;
131.2942 -    }
131.2943 -    ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();
131.2944 -    ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {
131.2945 -        if (arguments.length == 0) {
131.2946 -            var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
131.2947 -            if (templateData.textData === undefined && templateData.containerData)
131.2948 -                templateData.textData = templateData.containerData.innerHTML;
131.2949 -            return templateData.textData;
131.2950 -        } else {
131.2951 -            var valueToWrite = arguments[0];
131.2952 -            ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {textData: valueToWrite});
131.2953 -        }
131.2954 -    };
131.2955 -    ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {
131.2956 -        if (arguments.length == 0) {
131.2957 -            var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
131.2958 -            return templateData.containerData;
131.2959 -        } else {
131.2960 -            var valueToWrite = arguments[0];
131.2961 -            ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {containerData: valueToWrite});
131.2962 -        }
131.2963 -    };
131.2964 -
131.2965 -    ko.exportSymbol('templateSources', ko.templateSources);
131.2966 -    ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);
131.2967 -    ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);
131.2968 -})();
131.2969 -(function () {
131.2970 -    var _templateEngine;
131.2971 -    ko.setTemplateEngine = function (templateEngine) {
131.2972 -        if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))
131.2973 -            throw new Error("templateEngine must inherit from ko.templateEngine");
131.2974 -        _templateEngine = templateEngine;
131.2975 -    }
131.2976 -
131.2977 -    function invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, action) {
131.2978 -        var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);
131.2979 -        while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {
131.2980 -            nextInQueue = ko.virtualElements.nextSibling(node);
131.2981 -            if (node.nodeType === 1 || node.nodeType === 8)
131.2982 -                action(node);
131.2983 -        }
131.2984 -    }
131.2985 -
131.2986 -    function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext) {
131.2987 -        // To be used on any nodes that have been rendered by a template and have been inserted into some parent element
131.2988 -        // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because
131.2989 -        // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,
131.2990 -        // (1) Does a regular "applyBindings" to associate bindingContext with this node and to activate any non-memoized bindings
131.2991 -        // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)
131.2992 -
131.2993 -        if (continuousNodeArray.length) {
131.2994 -            var firstNode = continuousNodeArray[0], lastNode = continuousNodeArray[continuousNodeArray.length - 1];
131.2995 -
131.2996 -            // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)
131.2997 -            // whereas a regular applyBindings won't introduce new memoized nodes
131.2998 -            invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, function(node) {
131.2999 -                ko.applyBindings(bindingContext, node);
131.3000 -            });
131.3001 -            invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, function(node) {
131.3002 -                ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);
131.3003 -            });
131.3004 -        }
131.3005 -    }
131.3006 -
131.3007 -    function getFirstNodeFromPossibleArray(nodeOrNodeArray) {
131.3008 -        return nodeOrNodeArray.nodeType ? nodeOrNodeArray
131.3009 -                                        : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]
131.3010 -                                        : null;
131.3011 -    }
131.3012 -
131.3013 -    function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {
131.3014 -        options = options || {};
131.3015 -        var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
131.3016 -        var templateDocument = firstTargetNode && firstTargetNode.ownerDocument;
131.3017 -        var templateEngineToUse = (options['templateEngine'] || _templateEngine);
131.3018 -        ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);
131.3019 -        var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);
131.3020 -
131.3021 -        // Loosely check result is an array of DOM nodes
131.3022 -        if ((typeof renderedNodesArray.length != "number") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != "number"))
131.3023 -            throw new Error("Template engine must return an array of DOM nodes");
131.3024 -
131.3025 -        var haveAddedNodesToParent = false;
131.3026 -        switch (renderMode) {
131.3027 -            case "replaceChildren":
131.3028 -                ko.virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);
131.3029 -                haveAddedNodesToParent = true;
131.3030 -                break;
131.3031 -            case "replaceNode":
131.3032 -                ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray);
131.3033 -                haveAddedNodesToParent = true;
131.3034 -                break;
131.3035 -            case "ignoreTargetNode": break;
131.3036 -            default:
131.3037 -                throw new Error("Unknown renderMode: " + renderMode);
131.3038 -        }
131.3039 -
131.3040 -        if (haveAddedNodesToParent) {
131.3041 -            activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);
131.3042 -            if (options['afterRender'])
131.3043 -                ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext['$data']]);
131.3044 -        }
131.3045 -
131.3046 -        return renderedNodesArray;
131.3047 -    }
131.3048 -
131.3049 -    ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {
131.3050 -        options = options || {};
131.3051 -        if ((options['templateEngine'] || _templateEngine) == undefined)
131.3052 -            throw new Error("Set a template engine before calling renderTemplate");
131.3053 -        renderMode = renderMode || "replaceChildren";
131.3054 -
131.3055 -        if (targetNodeOrNodeArray) {
131.3056 -            var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
131.3057 -
131.3058 -            var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)
131.3059 -            var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == "replaceNode") ? firstTargetNode.parentNode : firstTargetNode;
131.3060 -
131.3061 -            return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes
131.3062 -                function () {
131.3063 -                    // Ensure we've got a proper binding context to work with
131.3064 -                    var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))
131.3065 -                        ? dataOrBindingContext
131.3066 -                        : new ko.bindingContext(ko.utils.unwrapObservable(dataOrBindingContext));
131.3067 -
131.3068 -                    // Support selecting template as a function of the data being rendered
131.3069 -                    var templateName = typeof(template) == 'function' ? template(bindingContext['$data'], bindingContext) : template;
131.3070 -
131.3071 -                    var renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);
131.3072 -                    if (renderMode == "replaceNode") {
131.3073 -                        targetNodeOrNodeArray = renderedNodesArray;
131.3074 -                        firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
131.3075 -                    }
131.3076 -                },
131.3077 -                null,
131.3078 -                { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }
131.3079 -            );
131.3080 -        } else {
131.3081 -            // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node
131.3082 -            return ko.memoization.memoize(function (domNode) {
131.3083 -                ko.renderTemplate(template, dataOrBindingContext, options, domNode, "replaceNode");
131.3084 -            });
131.3085 -        }
131.3086 -    };
131.3087 -
131.3088 -    ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {
131.3089 -        // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then
131.3090 -        // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.
131.3091 -        var arrayItemContext;
131.3092 -
131.3093 -        // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode
131.3094 -        var executeTemplateForArrayItem = function (arrayValue, index) {
131.3095 -            // Support selecting template as a function of the data being rendered
131.3096 -            arrayItemContext = parentBindingContext['createChildContext'](ko.utils.unwrapObservable(arrayValue), options['as']);
131.3097 -            arrayItemContext['$index'] = index;
131.3098 -            var templateName = typeof(template) == 'function' ? template(arrayValue, arrayItemContext) : template;
131.3099 -            return executeTemplate(null, "ignoreTargetNode", templateName, arrayItemContext, options);
131.3100 -        }
131.3101 -
131.3102 -        // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode
131.3103 -        var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {
131.3104 -            activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);
131.3105 -            if (options['afterRender'])
131.3106 -                options['afterRender'](addedNodesArray, arrayValue);
131.3107 -        };
131.3108 -
131.3109 -        return ko.dependentObservable(function () {
131.3110 -            var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];
131.3111 -            if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
131.3112 -                unwrappedArray = [unwrappedArray];
131.3113 -
131.3114 -            // Filter out any entries marked as destroyed
131.3115 -            var filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
131.3116 -                return options['includeDestroyed'] || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
131.3117 -            });
131.3118 -
131.3119 -            // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).
131.3120 -            // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.
131.3121 -            ko.dependencyDetection.ignore(ko.utils.setDomNodeChildrenFromArrayMapping, null, [targetNode, filteredArray, executeTemplateForArrayItem, options, activateBindingsCallback]);
131.3122 -
131.3123 -        }, null, { disposeWhenNodeIsRemoved: targetNode });
131.3124 -    };
131.3125 -
131.3126 -    var templateComputedDomDataKey = '__ko__templateComputedDomDataKey__';
131.3127 -    function disposeOldComputedAndStoreNewOne(element, newComputed) {
131.3128 -        var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);
131.3129 -        if (oldComputed && (typeof(oldComputed.dispose) == 'function'))
131.3130 -            oldComputed.dispose();
131.3131 -        ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && newComputed.isActive()) ? newComputed : undefined);
131.3132 -    }
131.3133 -
131.3134 -    ko.bindingHandlers['template'] = {
131.3135 -        'init': function(element, valueAccessor) {
131.3136 -            // Support anonymous templates
131.3137 -            var bindingValue = ko.utils.unwrapObservable(valueAccessor());
131.3138 -            if ((typeof bindingValue != "string") && (!bindingValue['name']) && (element.nodeType == 1 || element.nodeType == 8)) {
131.3139 -                // It's an anonymous template - store the element contents, then clear the element
131.3140 -                var templateNodes = element.nodeType == 1 ? element.childNodes : ko.virtualElements.childNodes(element),
131.3141 -                    container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent
131.3142 -                new ko.templateSources.anonymousTemplate(element)['nodes'](container);
131.3143 -            }
131.3144 -            return { 'controlsDescendantBindings': true };
131.3145 -        },
131.3146 -        'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
131.3147 -            var templateName = ko.utils.unwrapObservable(valueAccessor()),
131.3148 -                options = {},
131.3149 -                shouldDisplay = true,
131.3150 -                dataValue,
131.3151 -                templateComputed = null;
131.3152 -
131.3153 -            if (typeof templateName != "string") {
131.3154 -                options = templateName;
131.3155 -                templateName = options['name'];
131.3156 -
131.3157 -                // Support "if"/"ifnot" conditions
131.3158 -                if ('if' in options)
131.3159 -                    shouldDisplay = ko.utils.unwrapObservable(options['if']);
131.3160 -                if (shouldDisplay && 'ifnot' in options)
131.3161 -                    shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);
131.3162 -
131.3163 -                dataValue = ko.utils.unwrapObservable(options['data']);
131.3164 -            }
131.3165 -
131.3166 -            if ('foreach' in options) {
131.3167 -                // Render once for each data point (treating data set as empty if shouldDisplay==false)
131.3168 -                var dataArray = (shouldDisplay && options['foreach']) || [];
131.3169 -                templateComputed = ko.renderTemplateForEach(templateName || element, dataArray, options, element, bindingContext);
131.3170 -            } else if (!shouldDisplay) {
131.3171 -                ko.virtualElements.emptyNode(element);
131.3172 -            } else {
131.3173 -                // Render once for this single data point (or use the viewModel if no data was provided)
131.3174 -                var innerBindingContext = ('data' in options) ?
131.3175 -                    bindingContext['createChildContext'](dataValue, options['as']) :  // Given an explitit 'data' value, we create a child binding context for it
131.3176 -                    bindingContext;                                                        // Given no explicit 'data' value, we retain the same binding context
131.3177 -                templateComputed = ko.renderTemplate(templateName || element, innerBindingContext, options, element);
131.3178 -            }
131.3179 -
131.3180 -            // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)
131.3181 -            disposeOldComputedAndStoreNewOne(element, templateComputed);
131.3182 -        }
131.3183 -    };
131.3184 -
131.3185 -    // Anonymous templates can't be rewritten. Give a nice error message if you try to do it.
131.3186 -    ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {
131.3187 -        var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);
131.3188 -
131.3189 -        if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])
131.3190 -            return null; // It looks like a string literal, not an object literal, so treat it as a named template (which is allowed for rewriting)
131.3191 -
131.3192 -        if (ko.expressionRewriting.keyValueArrayContainsKey(parsedBindingValue, "name"))
131.3193 -            return null; // Named templates can be rewritten, so return "no error"
131.3194 -        return "This template engine does not support anonymous templates nested within its templates";
131.3195 -    };
131.3196 -
131.3197 -    ko.virtualElements.allowedBindings['template'] = true;
131.3198 -})();
131.3199 -
131.3200 -ko.exportSymbol('setTemplateEngine', ko.setTemplateEngine);
131.3201 -ko.exportSymbol('renderTemplate', ko.renderTemplate);
131.3202 -
131.3203 -ko.utils.compareArrays = (function () {
131.3204 -    var statusNotInOld = 'added', statusNotInNew = 'deleted';
131.3205 -
131.3206 -    // Simple calculation based on Levenshtein distance.
131.3207 -    function compareArrays(oldArray, newArray, dontLimitMoves) {
131.3208 -        oldArray = oldArray || [];
131.3209 -        newArray = newArray || [];
131.3210 -
131.3211 -        if (oldArray.length <= newArray.length)
131.3212 -            return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, dontLimitMoves);
131.3213 -        else
131.3214 -            return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, dontLimitMoves);
131.3215 -    }
131.3216 -
131.3217 -    function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, dontLimitMoves) {
131.3218 -        var myMin = Math.min,
131.3219 -            myMax = Math.max,
131.3220 -            editDistanceMatrix = [],
131.3221 -            smlIndex, smlIndexMax = smlArray.length,
131.3222 -            bigIndex, bigIndexMax = bigArray.length,
131.3223 -            compareRange = (bigIndexMax - smlIndexMax) || 1,
131.3224 -            maxDistance = smlIndexMax + bigIndexMax + 1,
131.3225 -            thisRow, lastRow,
131.3226 -            bigIndexMaxForRow, bigIndexMinForRow;
131.3227 -
131.3228 -        for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {
131.3229 -            lastRow = thisRow;
131.3230 -            editDistanceMatrix.push(thisRow = []);
131.3231 -            bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);
131.3232 -            bigIndexMinForRow = myMax(0, smlIndex - 1);
131.3233 -            for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) {
131.3234 -                if (!bigIndex)
131.3235 -                    thisRow[bigIndex] = smlIndex + 1;
131.3236 -                else if (!smlIndex)  // Top row - transform empty array into new array via additions
131.3237 -                    thisRow[bigIndex] = bigIndex + 1;
131.3238 -                else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])
131.3239 -                    thisRow[bigIndex] = lastRow[bigIndex - 1];                  // copy value (no edit)
131.3240 -                else {
131.3241 -                    var northDistance = lastRow[bigIndex] || maxDistance;       // not in big (deletion)
131.3242 -                    var westDistance = thisRow[bigIndex - 1] || maxDistance;    // not in small (addition)
131.3243 -                    thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;
131.3244 -                }
131.3245 -            }
131.3246 -        }
131.3247 -
131.3248 -        var editScript = [], meMinusOne, notInSml = [], notInBig = [];
131.3249 -        for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {
131.3250 -            meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;
131.3251 -            if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {
131.3252 -                notInSml.push(editScript[editScript.length] = {     // added
131.3253 -                    'status': statusNotInSml,
131.3254 -                    'value': bigArray[--bigIndex],
131.3255 -                    'index': bigIndex });
131.3256 -            } else if (smlIndex && meMinusOne === editDistanceMatrix[smlIndex - 1][bigIndex]) {
131.3257 -                notInBig.push(editScript[editScript.length] = {     // deleted
131.3258 -                    'status': statusNotInBig,
131.3259 -                    'value': smlArray[--smlIndex],
131.3260 -                    'index': smlIndex });
131.3261 -            } else {
131.3262 -                editScript.push({
131.3263 -                    'status': "retained",
131.3264 -                    'value': bigArray[--bigIndex] });
131.3265 -                --smlIndex;
131.3266 -            }
131.3267 -        }
131.3268 -
131.3269 -        if (notInSml.length && notInBig.length) {
131.3270 -            // Set a limit on the number of consecutive non-matching comparisons; having it a multiple of
131.3271 -            // smlIndexMax keeps the time complexity of this algorithm linear.
131.3272 -            var limitFailedCompares = smlIndexMax * 10, failedCompares,
131.3273 -                a, d, notInSmlItem, notInBigItem;
131.3274 -            // Go through the items that have been added and deleted and try to find matches between them.
131.3275 -            for (failedCompares = a = 0; (dontLimitMoves || failedCompares < limitFailedCompares) && (notInSmlItem = notInSml[a]); a++) {
131.3276 -                for (d = 0; notInBigItem = notInBig[d]; d++) {
131.3277 -                    if (notInSmlItem['value'] === notInBigItem['value']) {
131.3278 -                        notInSmlItem['moved'] = notInBigItem['index'];
131.3279 -                        notInBigItem['moved'] = notInSmlItem['index'];
131.3280 -                        notInBig.splice(d,1);       // This item is marked as moved; so remove it from notInBig list
131.3281 -                        failedCompares = d = 0;     // Reset failed compares count because we're checking for consecutive failures
131.3282 -                        break;
131.3283 -                    }
131.3284 -                }
131.3285 -                failedCompares += d;
131.3286 -            }
131.3287 -        }
131.3288 -        return editScript.reverse();
131.3289 -    }
131.3290 -
131.3291 -    return compareArrays;
131.3292 -})();
131.3293 -
131.3294 -ko.exportSymbol('utils.compareArrays', ko.utils.compareArrays);
131.3295 -
131.3296 -(function () {
131.3297 -    // Objective:
131.3298 -    // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,
131.3299 -    //   map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node
131.3300 -    // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node
131.3301 -    //   so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we
131.3302 -    //   previously mapped - retain those nodes, and just insert/delete other ones
131.3303 -
131.3304 -    // "callbackAfterAddingNodes" will be invoked after any "mapping"-generated nodes are inserted into the container node
131.3305 -    // You can use this, for example, to activate bindings on those nodes.
131.3306 -
131.3307 -    function fixUpNodesToBeMovedOrRemoved(contiguousNodeArray) {
131.3308 -        // Before moving, deleting, or replacing a set of nodes that were previously outputted by the "map" function, we have to reconcile
131.3309 -        // them against what is in the DOM right now. It may be that some of the nodes have already been removed from the document,
131.3310 -        // or that new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been
131.3311 -        // leading comment nodes (created by rewritten string-based templates) that have since been removed during binding.
131.3312 -        // So, this function translates the old "map" output array into its best guess of what set of current DOM nodes should be removed.
131.3313 -        //
131.3314 -        // Rules:
131.3315 -        //   [A] Any leading nodes that aren't in the document any more should be ignored
131.3316 -        //       These most likely correspond to memoization nodes that were already removed during binding
131.3317 -        //       See https://github.com/SteveSanderson/knockout/pull/440
131.3318 -        //   [B] We want to output a contiguous series of nodes that are still in the document. So, ignore any nodes that
131.3319 -        //       have already been removed, and include any nodes that have been inserted among the previous collection
131.3320 -
131.3321 -        // Rule [A]
131.3322 -        while (contiguousNodeArray.length && !ko.utils.domNodeIsAttachedToDocument(contiguousNodeArray[0]))
131.3323 -            contiguousNodeArray.splice(0, 1);
131.3324 -
131.3325 -        // Rule [B]
131.3326 -        if (contiguousNodeArray.length > 1) {
131.3327 -            // Build up the actual new contiguous node set
131.3328 -            var current = contiguousNodeArray[0], last = contiguousNodeArray[contiguousNodeArray.length - 1], newContiguousSet = [current];
131.3329 -            while (current !== last) {
131.3330 -                current = current.nextSibling;
131.3331 -                if (!current) // Won't happen, except if the developer has manually removed some DOM elements (then we're in an undefined scenario)
131.3332 -                    return;
131.3333 -                newContiguousSet.push(current);
131.3334 -            }
131.3335 -
131.3336 -            // ... then mutate the input array to match this.
131.3337 -            // (The following line replaces the contents of contiguousNodeArray with newContiguousSet)
131.3338 -            Array.prototype.splice.apply(contiguousNodeArray, [0, contiguousNodeArray.length].concat(newContiguousSet));
131.3339 -        }
131.3340 -        return contiguousNodeArray;
131.3341 -    }
131.3342 -
131.3343 -    function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
131.3344 -        // Map this array value inside a dependentObservable so we re-map when any dependency changes
131.3345 -        var mappedNodes = [];
131.3346 -        var dependentObservable = ko.dependentObservable(function() {
131.3347 -            var newMappedNodes = mapping(valueToMap, index) || [];
131.3348 -
131.3349 -            // On subsequent evaluations, just replace the previously-inserted DOM nodes
131.3350 -            if (mappedNodes.length > 0) {
131.3351 -                ko.utils.replaceDomNodes(fixUpNodesToBeMovedOrRemoved(mappedNodes), newMappedNodes);
131.3352 -                if (callbackAfterAddingNodes)
131.3353 -                    ko.dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);
131.3354 -            }
131.3355 -
131.3356 -            // Replace the contents of the mappedNodes array, thereby updating the record
131.3357 -            // of which nodes would be deleted if valueToMap was itself later removed
131.3358 -            mappedNodes.splice(0, mappedNodes.length);
131.3359 -            ko.utils.arrayPushAll(mappedNodes, newMappedNodes);
131.3360 -        }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return (mappedNodes.length == 0) || !ko.utils.domNodeIsAttachedToDocument(mappedNodes[0]) } });
131.3361 -        return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };
131.3362 -    }
131.3363 -
131.3364 -    var lastMappingResultDomDataKey = "setDomNodeChildrenFromArrayMapping_lastMappingResult";
131.3365 -
131.3366 -    ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes) {
131.3367 -        // Compare the provided array against the previous one
131.3368 -        array = array || [];
131.3369 -        options = options || {};
131.3370 -        var isFirstExecution = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) === undefined;
131.3371 -        var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) || [];
131.3372 -        var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; });
131.3373 -        var editScript = ko.utils.compareArrays(lastArray, array);
131.3374 -
131.3375 -        // Build the new mapping result
131.3376 -        var newMappingResult = [];
131.3377 -        var lastMappingResultIndex = 0;
131.3378 -        var newMappingResultIndex = 0;
131.3379 -
131.3380 -        var nodesToDelete = [];
131.3381 -        var itemsToProcess = [];
131.3382 -        var itemsForBeforeRemoveCallbacks = [];
131.3383 -        var itemsForMoveCallbacks = [];
131.3384 -        var itemsForAfterAddCallbacks = [];
131.3385 -        var mapData;
131.3386 -
131.3387 -        function itemMovedOrRetained(editScriptIndex, oldPosition) {
131.3388 -            mapData = lastMappingResult[oldPosition];
131.3389 -            if (newMappingResultIndex !== oldPosition)
131.3390 -                itemsForMoveCallbacks[editScriptIndex] = mapData;
131.3391 -            // Since updating the index might change the nodes, do so before calling fixUpNodesToBeMovedOrRemoved
131.3392 -            mapData.indexObservable(newMappingResultIndex++);
131.3393 -            fixUpNodesToBeMovedOrRemoved(mapData.mappedNodes);
131.3394 -            newMappingResult.push(mapData);
131.3395 -            itemsToProcess.push(mapData);
131.3396 -        }
131.3397 -
131.3398 -        function callCallback(callback, items) {
131.3399 -            if (callback) {
131.3400 -                for (var i = 0, n = items.length; i < n; i++) {
131.3401 -                    if (items[i]) {
131.3402 -                        ko.utils.arrayForEach(items[i].mappedNodes, function(node) {
131.3403 -                            callback(node, i, items[i].arrayEntry);
131.3404 -                        });
131.3405 -                    }
131.3406 -                }
131.3407 -            }
131.3408 -        }
131.3409 -
131.3410 -        for (var i = 0, editScriptItem, movedIndex; editScriptItem = editScript[i]; i++) {
131.3411 -            movedIndex = editScriptItem['moved'];
131.3412 -            switch (editScriptItem['status']) {
131.3413 -                case "deleted":
131.3414 -                    if (movedIndex === undefined) {
131.3415 -                        mapData = lastMappingResult[lastMappingResultIndex];
131.3416 -
131.3417 -                        // Stop tracking changes to the mapping for these nodes
131.3418 -                        if (mapData.dependentObservable)
131.3419 -                            mapData.dependentObservable.dispose();
131.3420 -
131.3421 -                        // Queue these nodes for later removal
131.3422 -                        nodesToDelete.push.apply(nodesToDelete, fixUpNodesToBeMovedOrRemoved(mapData.mappedNodes));
131.3423 -                        if (options['beforeRemove']) {
131.3424 -                            itemsForBeforeRemoveCallbacks[i] = mapData;
131.3425 -                            itemsToProcess.push(mapData);
131.3426 -                        }
131.3427 -                    }
131.3428 -                    lastMappingResultIndex++;
131.3429 -                    break;
131.3430 -
131.3431 -                case "retained":
131.3432 -                    itemMovedOrRetained(i, lastMappingResultIndex++);
131.3433 -                    break;
131.3434 -
131.3435 -                case "added":
131.3436 -                    if (movedIndex !== undefined) {
131.3437 -                        itemMovedOrRetained(i, movedIndex);
131.3438 -                    } else {
131.3439 -                        mapData = { arrayEntry: editScriptItem['value'], indexObservable: ko.observable(newMappingResultIndex++) };
131.3440 -                        newMappingResult.push(mapData);
131.3441 -                        itemsToProcess.push(mapData);
131.3442 -                        if (!isFirstExecution)
131.3443 -                            itemsForAfterAddCallbacks[i] = mapData;
131.3444 -                    }
131.3445 -                    break;
131.3446 -            }
131.3447 -        }
131.3448 -
131.3449 -        // Call beforeMove first before any changes have been made to the DOM
131.3450 -        callCallback(options['beforeMove'], itemsForMoveCallbacks);
131.3451 -
131.3452 -        // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)
131.3453 -        ko.utils.arrayForEach(nodesToDelete, options['beforeRemove'] ? ko.cleanNode : ko.removeNode);
131.3454 -
131.3455 -        // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)
131.3456 -        for (var i = 0, nextNode = ko.virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[i]; i++) {
131.3457 -            // Get nodes for newly added items
131.3458 -            if (!mapData.mappedNodes)
131.3459 -                ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));
131.3460 -
131.3461 -            // Put nodes in the right place if they aren't there already
131.3462 -            for (var j = 0; node = mapData.mappedNodes[j]; nextNode = node.nextSibling, lastNode = node, j++) {
131.3463 -                if (node !== nextNode)
131.3464 -                    ko.virtualElements.insertAfter(domNode, node, lastNode);
131.3465 -            }
131.3466 -
131.3467 -            // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)
131.3468 -            if (!mapData.initialized && callbackAfterAddingNodes) {
131.3469 -                callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);
131.3470 -                mapData.initialized = true;
131.3471 -            }
131.3472 -        }
131.3473 -
131.3474 -        // If there's a beforeRemove callback, call it after reordering.
131.3475 -        // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using
131.3476 -        // some sort of animation, which is why we first reorder the nodes that will be removed. If the
131.3477 -        // callback instead removes the nodes right away, it would be more efficient to skip reordering them.
131.3478 -        // Perhaps we'll make that change in the future if this scenario becomes more common.
131.3479 -        callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks);
131.3480 -
131.3481 -        // Finally call afterMove and afterAdd callbacks
131.3482 -        callCallback(options['afterMove'], itemsForMoveCallbacks);
131.3483 -        callCallback(options['afterAdd'], itemsForAfterAddCallbacks);
131.3484 -
131.3485 -        // Store a copy of the array items we just considered so we can difference it next time
131.3486 -        ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);
131.3487 -    }
131.3488 -})();
131.3489 -
131.3490 -ko.exportSymbol('utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);
131.3491 -ko.nativeTemplateEngine = function () {
131.3492 -    this['allowTemplateRewriting'] = false;
131.3493 -}
131.3494 -
131.3495 -ko.nativeTemplateEngine.prototype = new ko.templateEngine();
131.3496 -ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
131.3497 -    var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly
131.3498 -        templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,
131.3499 -        templateNodes = templateNodesFunc ? templateSource['nodes']() : null;
131.3500 -
131.3501 -    if (templateNodes) {
131.3502 -        return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);
131.3503 -    } else {
131.3504 -        var templateText = templateSource['text']();
131.3505 -        return ko.utils.parseHtmlFragment(templateText);
131.3506 -    }
131.3507 -};
131.3508 -
131.3509 -ko.nativeTemplateEngine.instance = new ko.nativeTemplateEngine();
131.3510 -ko.setTemplateEngine(ko.nativeTemplateEngine.instance);
131.3511 -
131.3512 -ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);
131.3513 -(function() {
131.3514 -    ko.jqueryTmplTemplateEngine = function () {
131.3515 -        // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl
131.3516 -        // doesn't expose a version number, so we have to infer it.
131.3517 -        // Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,
131.3518 -        // which KO internally refers to as version "2", so older versions are no longer detected.
131.3519 -        var jQueryTmplVersion = this.jQueryTmplVersion = (function() {
131.3520 -            if ((typeof(jQuery) == "undefined") || !(jQuery['tmpl']))
131.3521 -                return 0;
131.3522 -            // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.
131.3523 -            try {
131.3524 -                if (jQuery['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {
131.3525 -                    // Since 1.0.0pre, custom tags should append markup to an array called "__"
131.3526 -                    return 2; // Final version of jquery.tmpl
131.3527 -                }
131.3528 -            } catch(ex) { /* Apparently not the version we were looking for */ }
131.3529 -
131.3530 -            return 1; // Any older version that we don't support
131.3531 -        })();
131.3532 -
131.3533 -        function ensureHasReferencedJQueryTemplates() {
131.3534 -            if (jQueryTmplVersion < 2)
131.3535 -                throw new Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");
131.3536 -        }
131.3537 -
131.3538 -        function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {
131.3539 -            return jQuery['tmpl'](compiledTemplate, data, jQueryTemplateOptions);
131.3540 -        }
131.3541 -
131.3542 -        this['renderTemplateSource'] = function(templateSource, bindingContext, options) {
131.3543 -            options = options || {};
131.3544 -            ensureHasReferencedJQueryTemplates();
131.3545 -
131.3546 -            // Ensure we have stored a precompiled version of this template (don't want to reparse on every render)
131.3547 -            var precompiled = templateSource['data']('precompiled');
131.3548 -            if (!precompiled) {
131.3549 -                var templateText = templateSource['text']() || "";
131.3550 -                // Wrap in "with($whatever.koBindingContext) { ... }"
131.3551 -                templateText = "{{ko_with $item.koBindingContext}}" + templateText + "{{/ko_with}}";
131.3552 -
131.3553 -                precompiled = jQuery['template'](null, templateText);
131.3554 -                templateSource['data']('precompiled', precompiled);
131.3555 -            }
131.3556 -
131.3557 -            var data = [bindingContext['$data']]; // Prewrap the data in an array to stop jquery.tmpl from trying to unwrap any arrays
131.3558 -            var jQueryTemplateOptions = jQuery['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);
131.3559 -
131.3560 -            var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);
131.3561 -            resultNodes['appendTo'](document.createElement("div")); // Using "appendTo" forces jQuery/jQuery.tmpl to perform necessary cleanup work
131.3562 -
131.3563 -            jQuery['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders
131.3564 -            return resultNodes;
131.3565 -        };
131.3566 -
131.3567 -        this['createJavaScriptEvaluatorBlock'] = function(script) {
131.3568 -            return "{{ko_code ((function() { return " + script + " })()) }}";
131.3569 -        };
131.3570 -
131.3571 -        this['addTemplate'] = function(templateName, templateMarkup) {
131.3572 -            document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "</script>");
131.3573 -        };
131.3574 -
131.3575 -        if (jQueryTmplVersion > 0) {
131.3576 -            jQuery['tmpl']['tag']['ko_code'] = {
131.3577 -                open: "__.push($1 || '');"
131.3578 -            };
131.3579 -            jQuery['tmpl']['tag']['ko_with'] = {
131.3580 -                open: "with($1) {",
131.3581 -                close: "} "
131.3582 -            };
131.3583 -        }
131.3584 -    };
131.3585 -
131.3586 -    ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();
131.3587 -
131.3588 -    // Use this one by default *only if jquery.tmpl is referenced*
131.3589 -    var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine();
131.3590 -    if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0)
131.3591 -        ko.setTemplateEngine(jqueryTmplTemplateEngineInstance);
131.3592 -
131.3593 -    ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);
131.3594 -})();
131.3595 -});
131.3596 -})(window,document,navigator,window["jQuery"]);
131.3597 -})();
131.3598 \ No newline at end of file
   132.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   132.2 +++ b/ko-fx/src/main/resources/org/netbeans/html/kofx/knockout-2.2.1.js	Mon Dec 16 16:59:43 2013 +0100
   132.3 @@ -0,0 +1,3594 @@
   132.4 +// Knockout JavaScript library v2.2.1
   132.5 +// (c) Steven Sanderson - http://knockoutjs.com/
   132.6 +// License: MIT (http://www.opensource.org/licenses/mit-license.php)
   132.7 +
   132.8 +(function(){
   132.9 +var DEBUG=true;
  132.10 +(function(window,document,navigator,jQuery,undefined){
  132.11 +!function(factory) {
  132.12 +    // Support three module loading scenarios
  132.13 +    if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
  132.14 +        // [1] CommonJS/Node.js
  132.15 +        var target = module['exports'] || exports; // module.exports is for Node.js
  132.16 +        factory(target);
  132.17 +    } else if (typeof define === 'function' && define['amd']) {
  132.18 +        // [2] AMD anonymous module
  132.19 +        define(['exports'], factory);
  132.20 +    } else {
  132.21 +        // [3] No module loader (plain <script> tag) - put directly in global namespace
  132.22 +        factory(window['ko'] = {});
  132.23 +    }
  132.24 +}(function(koExports){
  132.25 +// Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).
  132.26 +// In the future, the following "ko" variable may be made distinct from "koExports" so that private objects are not externally reachable.
  132.27 +var ko = typeof koExports !== 'undefined' ? koExports : {};
  132.28 +// Google Closure Compiler helpers (used only to make the minified file smaller)
  132.29 +ko.exportSymbol = function(koPath, object) {
  132.30 +	var tokens = koPath.split(".");
  132.31 +
  132.32 +	// In the future, "ko" may become distinct from "koExports" (so that non-exported objects are not reachable)
  132.33 +	// At that point, "target" would be set to: (typeof koExports !== "undefined" ? koExports : ko)
  132.34 +	var target = ko;
  132.35 +
  132.36 +	for (var i = 0; i < tokens.length - 1; i++)
  132.37 +		target = target[tokens[i]];
  132.38 +	target[tokens[tokens.length - 1]] = object;
  132.39 +};
  132.40 +ko.exportProperty = function(owner, publicName, object) {
  132.41 +  owner[publicName] = object;
  132.42 +};
  132.43 +ko.version = "2.2.1";
  132.44 +
  132.45 +ko.exportSymbol('version', ko.version);
  132.46 +ko.utils = new (function () {
  132.47 +    var stringTrimRegex = /^(\s|\u00A0)+|(\s|\u00A0)+$/g;
  132.48 +
  132.49 +    // Represent the known event types in a compact way, then at runtime transform it into a hash with event name as key (for fast lookup)
  132.50 +    var knownEvents = {}, knownEventTypesByEventName = {};
  132.51 +    var keyEventTypeName = /Firefox\/2/i.test(navigator.userAgent) ? 'KeyboardEvent' : 'UIEvents';
  132.52 +    knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];
  132.53 +    knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];
  132.54 +    for (var eventType in knownEvents) {
  132.55 +        var knownEventsForType = knownEvents[eventType];
  132.56 +        if (knownEventsForType.length) {
  132.57 +            for (var i = 0, j = knownEventsForType.length; i < j; i++)
  132.58 +                knownEventTypesByEventName[knownEventsForType[i]] = eventType;
  132.59 +        }
  132.60 +    }
  132.61 +    var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406
  132.62 +
  132.63 +    // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)
  132.64 +    // Note that, since IE 10 does not support conditional comments, the following logic only detects IE < 10.
  132.65 +    // Currently this is by design, since IE 10+ behaves correctly when treated as a standard browser.
  132.66 +    // If there is a future need to detect specific versions of IE10+, we will amend this.
  132.67 +    var ieVersion = (function() {
  132.68 +        var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');
  132.69 +
  132.70 +        // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment
  132.71 +        while (
  132.72 +            div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',
  132.73 +            iElems[0]
  132.74 +        );
  132.75 +        return version > 4 ? version : undefined;
  132.76 +    }());
  132.77 +    var isIe6 = ieVersion === 6,
  132.78 +        isIe7 = ieVersion === 7;
  132.79 +
  132.80 +    function isClickOnCheckableElement(element, eventType) {
  132.81 +        if ((ko.utils.tagNameLower(element) !== "input") || !element.type) return false;
  132.82 +        if (eventType.toLowerCase() != "click") return false;
  132.83 +        var inputType = element.type;
  132.84 +        return (inputType == "checkbox") || (inputType == "radio");
  132.85 +    }
  132.86 +
  132.87 +    return {
  132.88 +        fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
  132.89 +
  132.90 +        arrayForEach: function (array, action) {
  132.91 +            for (var i = 0, j = array.length; i < j; i++)
  132.92 +                action(array[i]);
  132.93 +        },
  132.94 +
  132.95 +        arrayIndexOf: function (array, item) {
  132.96 +            if (typeof Array.prototype.indexOf == "function")
  132.97 +                return Array.prototype.indexOf.call(array, item);
  132.98 +            for (var i = 0, j = array.length; i < j; i++)
  132.99 +                if (array[i] === item)
 132.100 +                    return i;
 132.101 +            return -1;
 132.102 +        },
 132.103 +
 132.104 +        arrayFirst: function (array, predicate, predicateOwner) {
 132.105 +            for (var i = 0, j = array.length; i < j; i++)
 132.106 +                if (predicate.call(predicateOwner, array[i]))
 132.107 +                    return array[i];
 132.108 +            return null;
 132.109 +        },
 132.110 +
 132.111 +        arrayRemoveItem: function (array, itemToRemove) {
 132.112 +            var index = ko.utils.arrayIndexOf(array, itemToRemove);
 132.113 +            if (index >= 0)
 132.114 +                array.splice(index, 1);
 132.115 +        },
 132.116 +
 132.117 +        arrayGetDistinctValues: function (array) {
 132.118 +            array = array || [];
 132.119 +            var result = [];
 132.120 +            for (var i = 0, j = array.length; i < j; i++) {
 132.121 +                if (ko.utils.arrayIndexOf(result, array[i]) < 0)
 132.122 +                    result.push(array[i]);
 132.123 +            }
 132.124 +            return result;
 132.125 +        },
 132.126 +
 132.127 +        arrayMap: function (array, mapping) {
 132.128 +            array = array || [];
 132.129 +            var result = [];
 132.130 +            for (var i = 0, j = array.length; i < j; i++)
 132.131 +                result.push(mapping(array[i]));
 132.132 +            return result;
 132.133 +        },
 132.134 +
 132.135 +        arrayFilter: function (array, predicate) {
 132.136 +            array = array || [];
 132.137 +            var result = [];
 132.138 +            for (var i = 0, j = array.length; i < j; i++)
 132.139 +                if (predicate(array[i]))
 132.140 +                    result.push(array[i]);
 132.141 +            return result;
 132.142 +        },
 132.143 +
 132.144 +        arrayPushAll: function (array, valuesToPush) {
 132.145 +            if (valuesToPush instanceof Array)
 132.146 +                array.push.apply(array, valuesToPush);
 132.147 +            else
 132.148 +                for (var i = 0, j = valuesToPush.length; i < j; i++)
 132.149 +                    array.push(valuesToPush[i]);
 132.150 +            return array;
 132.151 +        },
 132.152 +
 132.153 +        extend: function (target, source) {
 132.154 +            if (source) {
 132.155 +                for(var prop in source) {
 132.156 +                    if(source.hasOwnProperty(prop)) {
 132.157 +                        target[prop] = source[prop];
 132.158 +                    }
 132.159 +                }
 132.160 +            }
 132.161 +            return target;
 132.162 +        },
 132.163 +
 132.164 +        emptyDomNode: function (domNode) {
 132.165 +            while (domNode.firstChild) {
 132.166 +                ko.removeNode(domNode.firstChild);
 132.167 +            }
 132.168 +        },
 132.169 +
 132.170 +        moveCleanedNodesToContainerElement: function(nodes) {
 132.171 +            // Ensure it's a real array, as we're about to reparent the nodes and
 132.172 +            // we don't want the underlying collection to change while we're doing that.
 132.173 +            var nodesArray = ko.utils.makeArray(nodes);
 132.174 +
 132.175 +            var container = document.createElement('div');
 132.176 +            for (var i = 0, j = nodesArray.length; i < j; i++) {
 132.177 +                container.appendChild(ko.cleanNode(nodesArray[i]));
 132.178 +            }
 132.179 +            return container;
 132.180 +        },
 132.181 +
 132.182 +        cloneNodes: function (nodesArray, shouldCleanNodes) {
 132.183 +            for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {
 132.184 +                var clonedNode = nodesArray[i].cloneNode(true);
 132.185 +                newNodesArray.push(shouldCleanNodes ? ko.cleanNode(clonedNode) : clonedNode);
 132.186 +            }
 132.187 +            return newNodesArray;
 132.188 +        },
 132.189 +
 132.190 +        setDomNodeChildren: function (domNode, childNodes) {
 132.191 +            ko.utils.emptyDomNode(domNode);
 132.192 +            if (childNodes) {
 132.193 +                for (var i = 0, j = childNodes.length; i < j; i++)
 132.194 +                    domNode.appendChild(childNodes[i]);
 132.195 +            }
 132.196 +        },
 132.197 +
 132.198 +        replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {
 132.199 +            var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;
 132.200 +            if (nodesToReplaceArray.length > 0) {
 132.201 +                var insertionPoint = nodesToReplaceArray[0];
 132.202 +                var parent = insertionPoint.parentNode;
 132.203 +                for (var i = 0, j = newNodesArray.length; i < j; i++)
 132.204 +                    parent.insertBefore(newNodesArray[i], insertionPoint);
 132.205 +                for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {
 132.206 +                    ko.removeNode(nodesToReplaceArray[i]);
 132.207 +                }
 132.208 +            }
 132.209 +        },
 132.210 +
 132.211 +        setOptionNodeSelectionState: function (optionNode, isSelected) {
 132.212 +            // IE6 sometimes throws "unknown error" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.
 132.213 +            if (ieVersion < 7)
 132.214 +                optionNode.setAttribute("selected", isSelected);
 132.215 +            else
 132.216 +                optionNode.selected = isSelected;
 132.217 +        },
 132.218 +
 132.219 +        stringTrim: function (string) {
 132.220 +            return (string || "").replace(stringTrimRegex, "");
 132.221 +        },
 132.222 +
 132.223 +        stringTokenize: function (string, delimiter) {
 132.224 +            var result = [];
 132.225 +            var tokens = (string || "").split(delimiter);
 132.226 +            for (var i = 0, j = tokens.length; i < j; i++) {
 132.227 +                var trimmed = ko.utils.stringTrim(tokens[i]);
 132.228 +                if (trimmed !== "")
 132.229 +                    result.push(trimmed);
 132.230 +            }
 132.231 +            return result;
 132.232 +        },
 132.233 +
 132.234 +        stringStartsWith: function (string, startsWith) {
 132.235 +            string = string || "";
 132.236 +            if (startsWith.length > string.length)
 132.237 +                return false;
 132.238 +            return string.substring(0, startsWith.length) === startsWith;
 132.239 +        },
 132.240 +
 132.241 +        domNodeIsContainedBy: function (node, containedByNode) {
 132.242 +            if (containedByNode.compareDocumentPosition)
 132.243 +                return (containedByNode.compareDocumentPosition(node) & 16) == 16;
 132.244 +            while (node != null) {
 132.245 +                if (node == containedByNode)
 132.246 +                    return true;
 132.247 +                node = node.parentNode;
 132.248 +            }
 132.249 +            return false;
 132.250 +        },
 132.251 +
 132.252 +        domNodeIsAttachedToDocument: function (node) {
 132.253 +            return ko.utils.domNodeIsContainedBy(node, node.ownerDocument);
 132.254 +        },
 132.255 +
 132.256 +        tagNameLower: function(element) {
 132.257 +            // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
 132.258 +            // Possible future optimization: If we know it's an element from an XHTML document (not HTML),
 132.259 +            // we don't need to do the .toLowerCase() as it will always be lower case anyway.
 132.260 +            return element && element.tagName && element.tagName.toLowerCase();
 132.261 +        },
 132.262 +
 132.263 +        registerEventHandler: function (element, eventType, handler) {
 132.264 +            var mustUseAttachEvent = ieVersion && eventsThatMustBeRegisteredUsingAttachEvent[eventType];
 132.265 +            if (!mustUseAttachEvent && typeof jQuery != "undefined") {
 132.266 +                if (isClickOnCheckableElement(element, eventType)) {
 132.267 +                    // For click events on checkboxes, jQuery interferes with the event handling in an awkward way:
 132.268 +                    // it toggles the element checked state *after* the click event handlers run, whereas native
 132.269 +                    // click events toggle the checked state *before* the event handler.
 132.270 +                    // Fix this by intecepting the handler and applying the correct checkedness before it runs.
 132.271 +                    var originalHandler = handler;
 132.272 +                    handler = function(event, eventData) {
 132.273 +                        var jQuerySuppliedCheckedState = this.checked;
 132.274 +                        if (eventData)
 132.275 +                            this.checked = eventData.checkedStateBeforeEvent !== true;
 132.276 +                        originalHandler.call(this, event);
 132.277 +                        this.checked = jQuerySuppliedCheckedState; // Restore the state jQuery applied
 132.278 +                    };
 132.279 +                }
 132.280 +                jQuery(element)['bind'](eventType, handler);
 132.281 +            } else if (!mustUseAttachEvent && typeof element.addEventListener == "function")
 132.282 +                element.addEventListener(eventType, handler, false);
 132.283 +            else if (typeof element.attachEvent != "undefined")
 132.284 +                element.attachEvent("on" + eventType, function (event) {
 132.285 +                    handler.call(element, event);
 132.286 +                });
 132.287 +            else
 132.288 +                throw new Error("Browser doesn't support addEventListener or attachEvent");
 132.289 +        },
 132.290 +
 132.291 +        triggerEvent: function (element, eventType) {
 132.292 +            if (!(element && element.nodeType))
 132.293 +                throw new Error("element must be a DOM node when calling triggerEvent");
 132.294 +
 132.295 +            if (typeof jQuery != "undefined") {
 132.296 +                var eventData = [];
 132.297 +                if (isClickOnCheckableElement(element, eventType)) {
 132.298 +                    // Work around the jQuery "click events on checkboxes" issue described above by storing the original checked state before triggering the handler
 132.299 +                    eventData.push({ checkedStateBeforeEvent: element.checked });
 132.300 +                }
 132.301 +                jQuery(element)['trigger'](eventType, eventData);
 132.302 +            } else if (typeof document.createEvent == "function") {
 132.303 +                if (typeof element.dispatchEvent == "function") {
 132.304 +                    var eventCategory = knownEventTypesByEventName[eventType] || "HTMLEvents";
 132.305 +                    var event = document.createEvent(eventCategory);
 132.306 +                    event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);
 132.307 +                    element.dispatchEvent(event);
 132.308 +                }
 132.309 +                else
 132.310 +                    throw new Error("The supplied element doesn't support dispatchEvent");
 132.311 +            } else if (typeof element.fireEvent != "undefined") {
 132.312 +                // Unlike other browsers, IE doesn't change the checked state of checkboxes/radiobuttons when you trigger their "click" event
 132.313 +                // so to make it consistent, we'll do it manually here
 132.314 +                if (isClickOnCheckableElement(element, eventType))
 132.315 +                    element.checked = element.checked !== true;
 132.316 +                element.fireEvent("on" + eventType);
 132.317 +            }
 132.318 +            else
 132.319 +                throw new Error("Browser doesn't support triggering events");
 132.320 +        },
 132.321 +
 132.322 +        unwrapObservable: function (value) {
 132.323 +            return ko.isObservable(value) ? value() : value;
 132.324 +        },
 132.325 +
 132.326 +        peekObservable: function (value) {
 132.327 +            return ko.isObservable(value) ? value.peek() : value;
 132.328 +        },
 132.329 +
 132.330 +        toggleDomNodeCssClass: function (node, classNames, shouldHaveClass) {
 132.331 +            if (classNames) {
 132.332 +                var cssClassNameRegex = /[\w-]+/g,
 132.333 +                    currentClassNames = node.className.match(cssClassNameRegex) || [];
 132.334 +                ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
 132.335 +                    var indexOfClass = ko.utils.arrayIndexOf(currentClassNames, className);
 132.336 +                    if (indexOfClass >= 0) {
 132.337 +                        if (!shouldHaveClass)
 132.338 +                            currentClassNames.splice(indexOfClass, 1);
 132.339 +                    } else {
 132.340 +                        if (shouldHaveClass)
 132.341 +                            currentClassNames.push(className);
 132.342 +                    }
 132.343 +                });
 132.344 +                node.className = currentClassNames.join(" ");
 132.345 +            }
 132.346 +        },
 132.347 +
 132.348 +        setTextContent: function(element, textContent) {
 132.349 +            var value = ko.utils.unwrapObservable(textContent);
 132.350 +            if ((value === null) || (value === undefined))
 132.351 +                value = "";
 132.352 +
 132.353 +            if (element.nodeType === 3) {
 132.354 +                element.data = value;
 132.355 +            } else {
 132.356 +                // We need there to be exactly one child: a text node.
 132.357 +                // If there are no children, more than one, or if it's not a text node,
 132.358 +                // we'll clear everything and create a single text node.
 132.359 +                var innerTextNode = ko.virtualElements.firstChild(element);
 132.360 +                if (!innerTextNode || innerTextNode.nodeType != 3 || ko.virtualElements.nextSibling(innerTextNode)) {
 132.361 +                    ko.virtualElements.setDomNodeChildren(element, [document.createTextNode(value)]);
 132.362 +                } else {
 132.363 +                    innerTextNode.data = value;
 132.364 +                }
 132.365 +
 132.366 +                ko.utils.forceRefresh(element);
 132.367 +            }
 132.368 +        },
 132.369 +
 132.370 +        setElementName: function(element, name) {
 132.371 +            element.name = name;
 132.372 +
 132.373 +            // Workaround IE 6/7 issue
 132.374 +            // - https://github.com/SteveSanderson/knockout/issues/197
 132.375 +            // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/
 132.376 +            if (ieVersion <= 7) {
 132.377 +                try {
 132.378 +                    element.mergeAttributes(document.createElement("<input name='" + element.name + "'/>"), false);
 132.379 +                }
 132.380 +                catch(e) {} // For IE9 with doc mode "IE9 Standards" and browser mode "IE9 Compatibility View"
 132.381 +            }
 132.382 +        },
 132.383 +
 132.384 +        forceRefresh: function(node) {
 132.385 +            // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209
 132.386 +            if (ieVersion >= 9) {
 132.387 +                // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container
 132.388 +                var elem = node.nodeType == 1 ? node : node.parentNode;
 132.389 +                if (elem.style)
 132.390 +                    elem.style.zoom = elem.style.zoom;
 132.391 +            }
 132.392 +        },
 132.393 +
 132.394 +        ensureSelectElementIsRenderedCorrectly: function(selectElement) {
 132.395 +            // Workaround for IE9 rendering bug - it doesn't reliably display all the text in dynamically-added select boxes unless you force it to re-render by updating the width.
 132.396 +            // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)
 132.397 +            if (ieVersion >= 9) {
 132.398 +                var originalWidth = selectElement.style.width;
 132.399 +                selectElement.style.width = 0;
 132.400 +                selectElement.style.width = originalWidth;
 132.401 +            }
 132.402 +        },
 132.403 +
 132.404 +        range: function (min, max) {
 132.405 +            min = ko.utils.unwrapObservable(min);
 132.406 +            max = ko.utils.unwrapObservable(max);
 132.407 +            var result = [];
 132.408 +            for (var i = min; i <= max; i++)
 132.409 +                result.push(i);
 132.410 +            return result;
 132.411 +        },
 132.412 +
 132.413 +        makeArray: function(arrayLikeObject) {
 132.414 +            var result = [];
 132.415 +            for (var i = 0, j = arrayLikeObject.length; i < j; i++) {
 132.416 +                result.push(arrayLikeObject[i]);
 132.417 +            };
 132.418 +            return result;
 132.419 +        },
 132.420 +
 132.421 +        isIe6 : isIe6,
 132.422 +        isIe7 : isIe7,
 132.423 +        ieVersion : ieVersion,
 132.424 +
 132.425 +        getFormFields: function(form, fieldName) {
 132.426 +            var fields = ko.utils.makeArray(form.getElementsByTagName("input")).concat(ko.utils.makeArray(form.getElementsByTagName("textarea")));
 132.427 +            var isMatchingField = (typeof fieldName == 'string')
 132.428 +                ? function(field) { return field.name === fieldName }
 132.429 +                : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate
 132.430 +            var matches = [];
 132.431 +            for (var i = fields.length - 1; i >= 0; i--) {
 132.432 +                if (isMatchingField(fields[i]))
 132.433 +                    matches.push(fields[i]);
 132.434 +            };
 132.435 +            return matches;
 132.436 +        },
 132.437 +
 132.438 +        parseJson: function (jsonString) {
 132.439 +            if (typeof jsonString == "string") {
 132.440 +                jsonString = ko.utils.stringTrim(jsonString);
 132.441 +                if (jsonString) {
 132.442 +                    if (window.JSON && window.JSON.parse) // Use native parsing where available
 132.443 +                        return window.JSON.parse(jsonString);
 132.444 +                    return (new Function("return " + jsonString))(); // Fallback on less safe parsing for older browsers
 132.445 +                }
 132.446 +            }
 132.447 +            return null;
 132.448 +        },
 132.449 +
 132.450 +        stringifyJson: function (data, replacer, space) {   // replacer and space are optional
 132.451 +            if ((typeof JSON == "undefined") || (typeof JSON.stringify == "undefined"))
 132.452 +                throw new Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
 132.453 +            return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);
 132.454 +        },
 132.455 +
 132.456 +        postJson: function (urlOrForm, data, options) {
 132.457 +            options = options || {};
 132.458 +            var params = options['params'] || {};
 132.459 +            var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;
 132.460 +            var url = urlOrForm;
 132.461 +
 132.462 +            // If we were given a form, use its 'action' URL and pick out any requested field values
 132.463 +            if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === "form")) {
 132.464 +                var originalForm = urlOrForm;
 132.465 +                url = originalForm.action;
 132.466 +                for (var i = includeFields.length - 1; i >= 0; i--) {
 132.467 +                    var fields = ko.utils.getFormFields(originalForm, includeFields[i]);
 132.468 +                    for (var j = fields.length - 1; j >= 0; j--)
 132.469 +                        params[fields[j].name] = fields[j].value;
 132.470 +                }
 132.471 +            }
 132.472 +
 132.473 +            data = ko.utils.unwrapObservable(data);
 132.474 +            var form = document.createElement("form");
 132.475 +            form.style.display = "none";
 132.476 +            form.action = url;
 132.477 +            form.method = "post";
 132.478 +            for (var key in data) {
 132.479 +                var input = document.createElement("input");
 132.480 +                input.name = key;
 132.481 +                input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));
 132.482 +                form.appendChild(input);
 132.483 +            }
 132.484 +            for (var key in params) {
 132.485 +                var input = document.createElement("input");
 132.486 +                input.name = key;
 132.487 +                input.value = params[key];
 132.488 +                form.appendChild(input);
 132.489 +            }
 132.490 +            document.body.appendChild(form);
 132.491 +            options['submitter'] ? options['submitter'](form) : form.submit();
 132.492 +            setTimeout(function () { form.parentNode.removeChild(form); }, 0);
 132.493 +        }
 132.494 +    }
 132.495 +})();
 132.496 +
 132.497 +ko.exportSymbol('utils', ko.utils);
 132.498 +ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);
 132.499 +ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);
 132.500 +ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);
 132.501 +ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);
 132.502 +ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);
 132.503 +ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);
 132.504 +ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);
 132.505 +ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);
 132.506 +ko.exportSymbol('utils.extend', ko.utils.extend);
 132.507 +ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);
 132.508 +ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);
 132.509 +ko.exportSymbol('utils.peekObservable', ko.utils.peekObservable);
 132.510 +ko.exportSymbol('utils.postJson', ko.utils.postJson);
 132.511 +ko.exportSymbol('utils.parseJson', ko.utils.parseJson);
 132.512 +ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);
 132.513 +ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);
 132.514 +ko.exportSymbol('utils.range', ko.utils.range);
 132.515 +ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);
 132.516 +ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);
 132.517 +ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);
 132.518 +
 132.519 +if (!Function.prototype['bind']) {
 132.520 +    // Function.prototype.bind is a standard part of ECMAScript 5th Edition (December 2009, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf)
 132.521 +    // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js
 132.522 +    Function.prototype['bind'] = function (object) {
 132.523 +        var originalFunction = this, args = Array.prototype.slice.call(arguments), object = args.shift();
 132.524 +        return function () {
 132.525 +            return originalFunction.apply(object, args.concat(Array.prototype.slice.call(arguments)));
 132.526 +        };
 132.527 +    };
 132.528 +}
 132.529 +
 132.530 +ko.utils.domData = new (function () {
 132.531 +    var uniqueId = 0;
 132.532 +    var dataStoreKeyExpandoPropertyName = "__ko__" + (new Date).getTime();
 132.533 +    var dataStore = {};
 132.534 +    return {
 132.535 +        get: function (node, key) {
 132.536 +            var allDataForNode = ko.utils.domData.getAll(node, false);
 132.537 +            return allDataForNode === undefined ? undefined : allDataForNode[key];
 132.538 +        },
 132.539 +        set: function (node, key, value) {
 132.540 +            if (value === undefined) {
 132.541 +                // Make sure we don't actually create a new domData key if we are actually deleting a value
 132.542 +                if (ko.utils.domData.getAll(node, false) === undefined)
 132.543 +                    return;
 132.544 +            }
 132.545 +            var allDataForNode = ko.utils.domData.getAll(node, true);
 132.546 +            allDataForNode[key] = value;
 132.547 +        },
 132.548 +        getAll: function (node, createIfNotFound) {
 132.549 +            var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
 132.550 +            var hasExistingDataStore = dataStoreKey && (dataStoreKey !== "null") && dataStore[dataStoreKey];
 132.551 +            if (!hasExistingDataStore) {
 132.552 +                if (!createIfNotFound)
 132.553 +                    return undefined;
 132.554 +                dataStoreKey = node[dataStoreKeyExpandoPropertyName] = "ko" + uniqueId++;
 132.555 +                dataStore[dataStoreKey] = {};
 132.556 +            }
 132.557 +            return dataStore[dataStoreKey];
 132.558 +        },
 132.559 +        clear: function (node) {
 132.560 +            var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
 132.561 +            if (dataStoreKey) {
 132.562 +                delete dataStore[dataStoreKey];
 132.563 +                node[dataStoreKeyExpandoPropertyName] = null;
 132.564 +                return true; // Exposing "did clean" flag purely so specs can infer whether things have been cleaned up as intended
 132.565 +            }
 132.566 +            return false;
 132.567 +        }
 132.568 +    }
 132.569 +})();
 132.570 +
 132.571 +ko.exportSymbol('utils.domData', ko.utils.domData);
 132.572 +ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully
 132.573 +
 132.574 +ko.utils.domNodeDisposal = new (function () {
 132.575 +    var domDataKey = "__ko_domNodeDisposal__" + (new Date).getTime();
 132.576 +    var cleanableNodeTypes = { 1: true, 8: true, 9: true };       // Element, Comment, Document
 132.577 +    var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document
 132.578 +
 132.579 +    function getDisposeCallbacksCollection(node, createIfNotFound) {
 132.580 +        var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);
 132.581 +        if ((allDisposeCallbacks === undefined) && createIfNotFound) {
 132.582 +            allDisposeCallbacks = [];
 132.583 +            ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);
 132.584 +        }
 132.585 +        return allDisposeCallbacks;
 132.586 +    }
 132.587 +    function destroyCallbacksCollection(node) {
 132.588 +        ko.utils.domData.set(node, domDataKey, undefined);
 132.589 +    }
 132.590 +
 132.591 +    function cleanSingleNode(node) {
 132.592 +        // Run all the dispose callbacks
 132.593 +        var callbacks = getDisposeCallbacksCollection(node, false);
 132.594 +        if (callbacks) {
 132.595 +            callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)
 132.596 +            for (var i = 0; i < callbacks.length; i++)
 132.597 +                callbacks[i](node);
 132.598 +        }
 132.599 +
 132.600 +        // Also erase the DOM data
 132.601 +        ko.utils.domData.clear(node);
 132.602 +
 132.603 +        // Special support for jQuery here because it's so commonly used.
 132.604 +        // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData
 132.605 +        // so notify it to tear down any resources associated with the node & descendants here.
 132.606 +        if ((typeof jQuery == "function") && (typeof jQuery['cleanData'] == "function"))
 132.607 +            jQuery['cleanData']([node]);
 132.608 +
 132.609 +        // Also clear any immediate-child comment nodes, as these wouldn't have been found by
 132.610 +        // node.getElementsByTagName("*") in cleanNode() (comment nodes aren't elements)
 132.611 +        if (cleanableNodeTypesWithDescendants[node.nodeType])
 132.612 +            cleanImmediateCommentTypeChildren(node);
 132.613 +    }
 132.614 +
 132.615 +    function cleanImmediateCommentTypeChildren(nodeWithChildren) {
 132.616 +        var child, nextChild = nodeWithChildren.firstChild;
 132.617 +        while (child = nextChild) {
 132.618 +            nextChild = child.nextSibling;
 132.619 +            if (child.nodeType === 8)
 132.620 +                cleanSingleNode(child);
 132.621 +        }
 132.622 +    }
 132.623 +
 132.624 +    return {
 132.625 +        addDisposeCallback : function(node, callback) {
 132.626 +            if (typeof callback != "function")
 132.627 +                throw new Error("Callback must be a function");
 132.628 +            getDisposeCallbacksCollection(node, true).push(callback);
 132.629 +        },
 132.630 +
 132.631 +        removeDisposeCallback : function(node, callback) {
 132.632 +            var callbacksCollection = getDisposeCallbacksCollection(node, false);
 132.633 +            if (callbacksCollection) {
 132.634 +                ko.utils.arrayRemoveItem(callbacksCollection, callback);
 132.635 +                if (callbacksCollection.length == 0)
 132.636 +                    destroyCallbacksCollection(node);
 132.637 +            }
 132.638 +        },
 132.639 +
 132.640 +        cleanNode : function(node) {
 132.641 +            // First clean this node, where applicable
 132.642 +            if (cleanableNodeTypes[node.nodeType]) {
 132.643 +                cleanSingleNode(node);
 132.644 +
 132.645 +                // ... then its descendants, where applicable
 132.646 +                if (cleanableNodeTypesWithDescendants[node.nodeType]) {
 132.647 +                    // Clone the descendants list in case it changes during iteration
 132.648 +                    var descendants = [];
 132.649 +                    ko.utils.arrayPushAll(descendants, node.getElementsByTagName("*"));
 132.650 +                    for (var i = 0, j = descendants.length; i < j; i++)
 132.651 +                        cleanSingleNode(descendants[i]);
 132.652 +                }
 132.653 +            }
 132.654 +            return node;
 132.655 +        },
 132.656 +
 132.657 +        removeNode : function(node) {
 132.658 +            ko.cleanNode(node);
 132.659 +            if (node.parentNode)
 132.660 +                node.parentNode.removeChild(node);
 132.661 +        }
 132.662 +    }
 132.663 +})();
 132.664 +ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience
 132.665 +ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience
 132.666 +ko.exportSymbol('cleanNode', ko.cleanNode);
 132.667 +ko.exportSymbol('removeNode', ko.removeNode);
 132.668 +ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);
 132.669 +ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);
 132.670 +ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);
 132.671 +(function () {
 132.672 +    var leadingCommentRegex = /^(\s*)<!--(.*?)-->/;
 132.673 +
 132.674 +    function simpleHtmlParse(html) {
 132.675 +        // Based on jQuery's "clean" function, but only accounting for table-related elements.
 132.676 +        // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's "clean" function directly
 132.677 +
 132.678 +        // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of
 132.679 +        // a descendant node. For example: "<div><!-- mycomment -->abc</div>" will get parsed as "<div>abc</div>"
 132.680 +        // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node
 132.681 +        // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.
 132.682 +
 132.683 +        // Trim whitespace, otherwise indexOf won't work as expected
 132.684 +        var tags = ko.utils.stringTrim(html).toLowerCase(), div = document.createElement("div");
 132.685 +
 132.686 +        // Finds the first match from the left column, and returns the corresponding "wrap" data from the right column
 132.687 +        var wrap = tags.match(/^<(thead|tbody|tfoot)/)              && [1, "<table>", "</table>"] ||
 132.688 +                   !tags.indexOf("<tr")                             && [2, "<table><tbody>", "</tbody></table>"] ||
 132.689 +                   (!tags.indexOf("<td") || !tags.indexOf("<th"))   && [3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
 132.690 +                   /* anything else */                                 [0, "", ""];
 132.691 +
 132.692 +        // Go to html and back, then peel off extra wrappers
 132.693 +        // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
 132.694 +        var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
 132.695 +        if (typeof window['innerShiv'] == "function") {
 132.696 +            div.appendChild(window['innerShiv'](markup));
 132.697 +        } else {
 132.698 +            div.innerHTML = markup;
 132.699 +        }
 132.700 +
 132.701 +        // Move to the right depth
 132.702 +        while (wrap[0]--)
 132.703 +            div = div.lastChild;
 132.704 +
 132.705 +        return ko.utils.makeArray(div.lastChild.childNodes);
 132.706 +    }
 132.707 +
 132.708 +    function jQueryHtmlParse(html) {
 132.709 +        // jQuery's "parseHTML" function was introduced in jQuery 1.8.0 and is a documented public API.
 132.710 +        if (jQuery['parseHTML']) {
 132.711 +            return jQuery['parseHTML'](html);
 132.712 +        } else {
 132.713 +            // For jQuery < 1.8.0, we fall back on the undocumented internal "clean" function.
 132.714 +            var elems = jQuery['clean']([html]);
 132.715 +
 132.716 +            // As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment.
 132.717 +            // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.
 132.718 +            // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.
 132.719 +            if (elems && elems[0]) {
 132.720 +                // Find the top-most parent element that's a direct child of a document fragment
 132.721 +                var elem = elems[0];
 132.722 +                while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)
 132.723 +                    elem = elem.parentNode;
 132.724 +                // ... then detach it
 132.725 +                if (elem.parentNode)
 132.726 +                    elem.parentNode.removeChild(elem);
 132.727 +            }
 132.728 +
 132.729 +            return elems;
 132.730 +        }
 132.731 +    }
 132.732 +
 132.733 +    ko.utils.parseHtmlFragment = function(html) {
 132.734 +        return typeof jQuery != 'undefined' ? jQueryHtmlParse(html)   // As below, benefit from jQuery's optimisations where possible
 132.735 +                                            : simpleHtmlParse(html);  // ... otherwise, this simple logic will do in most common cases.
 132.736 +    };
 132.737 +
 132.738 +    ko.utils.setHtml = function(node, html) {
 132.739 +        ko.utils.emptyDomNode(node);
 132.740 +
 132.741 +        // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it
 132.742 +        html = ko.utils.unwrapObservable(html);
 132.743 +
 132.744 +        if ((html !== null) && (html !== undefined)) {
 132.745 +            if (typeof html != 'string')
 132.746 +                html = html.toString();
 132.747 +
 132.748 +            // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,
 132.749 +            // for example <tr> elements which are not normally allowed to exist on their own.
 132.750 +            // If you've referenced jQuery we'll use that rather than duplicating its code.
 132.751 +            if (typeof jQuery != 'undefined') {
 132.752 +                jQuery(node)['html'](html);
 132.753 +            } else {
 132.754 +                // ... otherwise, use KO's own parsing logic.
 132.755 +                var parsedNodes = ko.utils.parseHtmlFragment(html);
 132.756 +                for (var i = 0; i < parsedNodes.length; i++)
 132.757 +                    node.appendChild(parsedNodes[i]);
 132.758 +            }
 132.759 +        }
 132.760 +    };
 132.761 +})();
 132.762 +
 132.763 +ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);
 132.764 +ko.exportSymbol('utils.setHtml', ko.utils.setHtml);
 132.765 +
 132.766 +ko.memoization = (function () {
 132.767 +    var memos = {};
 132.768 +
 132.769 +    function randomMax8HexChars() {
 132.770 +        return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
 132.771 +    }
 132.772 +    function generateRandomId() {
 132.773 +        return randomMax8HexChars() + randomMax8HexChars();
 132.774 +    }
 132.775 +    function findMemoNodes(rootNode, appendToArray) {
 132.776 +        if (!rootNode)
 132.777 +            return;
 132.778 +        if (rootNode.nodeType == 8) {
 132.779 +            var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);
 132.780 +            if (memoId != null)
 132.781 +                appendToArray.push({ domNode: rootNode, memoId: memoId });
 132.782 +        } else if (rootNode.nodeType == 1) {
 132.783 +            for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)
 132.784 +                findMemoNodes(childNodes[i], appendToArray);
 132.785 +        }
 132.786 +    }
 132.787 +
 132.788 +    return {
 132.789 +        memoize: function (callback) {
 132.790 +            if (typeof callback != "function")
 132.791 +                throw new Error("You can only pass a function to ko.memoization.memoize()");
 132.792 +            var memoId = generateRandomId();
 132.793 +            memos[memoId] = callback;
 132.794 +            return "<!--[ko_memo:" + memoId + "]-->";
 132.795 +        },
 132.796 +
 132.797 +        unmemoize: function (memoId, callbackParams) {
 132.798 +            var callback = memos[memoId];
 132.799 +            if (callback === undefined)
 132.800 +                throw new Error("Couldn't find any memo with ID " + memoId + ". Perhaps it's already been unmemoized.");
 132.801 +            try {
 132.802 +                callback.apply(null, callbackParams || []);
 132.803 +                return true;
 132.804 +            }
 132.805 +            finally { delete memos[memoId]; }
 132.806 +        },
 132.807 +
 132.808 +        unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {
 132.809 +            var memos = [];
 132.810 +            findMemoNodes(domNode, memos);
 132.811 +            for (var i = 0, j = memos.length; i < j; i++) {
 132.812 +                var node = memos[i].domNode;
 132.813 +                var combinedParams = [node];
 132.814 +                if (extraCallbackParamsArray)
 132.815 +                    ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);
 132.816 +                ko.memoization.unmemoize(memos[i].memoId, combinedParams);
 132.817 +                node.nodeValue = ""; // Neuter this node so we don't try to unmemoize it again
 132.818 +                if (node.parentNode)
 132.819 +                    node.parentNode.removeChild(node); // If possible, erase it totally (not always possible - someone else might just hold a reference to it then call unmemoizeDomNodeAndDescendants again)
 132.820 +            }
 132.821 +        },
 132.822 +
 132.823 +        parseMemoText: function (memoText) {
 132.824 +            var match = memoText.match(/^\[ko_memo\:(.*?)\]$/);
 132.825 +            return match ? match[1] : null;
 132.826 +        }
 132.827 +    };
 132.828 +})();
 132.829 +
 132.830 +ko.exportSymbol('memoization', ko.memoization);
 132.831 +ko.exportSymbol('memoization.memoize', ko.memoization.memoize);
 132.832 +ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);
 132.833 +ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);
 132.834 +ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);
 132.835 +ko.extenders = {
 132.836 +    'throttle': function(target, timeout) {
 132.837 +        // Throttling means two things:
 132.838 +
 132.839 +        // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
 132.840 +        //     notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
 132.841 +        target['throttleEvaluation'] = timeout;
 132.842 +
 132.843 +        // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
 132.844 +        //     so the target cannot change value synchronously or faster than a certain rate
 132.845 +        var writeTimeoutInstance = null;
 132.846 +        return ko.dependentObservable({
 132.847 +            'read': target,
 132.848 +            'write': function(value) {
 132.849 +                clearTimeout(writeTimeoutInstance);
 132.850 +                writeTimeoutInstance = setTimeout(function() {
 132.851 +                    target(value);
 132.852 +                }, timeout);
 132.853 +            }
 132.854 +        });
 132.855 +    },
 132.856 +
 132.857 +    'notify': function(target, notifyWhen) {
 132.858 +        target["equalityComparer"] = notifyWhen == "always"
 132.859 +            ? function() { return false } // Treat all values as not equal
 132.860 +            : ko.observable["fn"]["equalityComparer"];
 132.861 +        return target;
 132.862 +    }
 132.863 +};
 132.864 +
 132.865 +function applyExtenders(requestedExtenders) {
 132.866 +    var target = this;
 132.867 +    if (requestedExtenders) {
 132.868 +        for (var key in requestedExtenders) {
 132.869 +            var extenderHandler = ko.extenders[key];
 132.870 +            if (typeof extenderHandler == 'function') {
 132.871 +                target = extenderHandler(target, requestedExtenders[key]);
 132.872 +            }
 132.873 +        }
 132.874 +    }
 132.875 +    return target;
 132.876 +}
 132.877 +
 132.878 +ko.exportSymbol('extenders', ko.extenders);
 132.879 +
 132.880 +ko.subscription = function (target, callback, disposeCallback) {
 132.881 +    this.target = target;
 132.882 +    this.callback = callback;
 132.883 +    this.disposeCallback = disposeCallback;
 132.884 +    ko.exportProperty(this, 'dispose', this.dispose);
 132.885 +};
 132.886 +ko.subscription.prototype.dispose = function () {
 132.887 +    this.isDisposed = true;
 132.888 +    this.disposeCallback();
 132.889 +};
 132.890 +
 132.891 +ko.subscribable = function () {
 132.892 +    this._subscriptions = {};
 132.893 +
 132.894 +    ko.utils.extend(this, ko.subscribable['fn']);
 132.895 +    ko.exportProperty(this, 'subscribe', this.subscribe);
 132.896 +    ko.exportProperty(this, 'extend', this.extend);
 132.897 +    ko.exportProperty(this, 'getSubscriptionsCount', this.getSubscriptionsCount);
 132.898 +}
 132.899 +
 132.900 +var defaultEvent = "change";
 132.901 +
 132.902 +ko.subscribable['fn'] = {
 132.903 +    subscribe: function (callback, callbackTarget, event) {
 132.904 +        event = event || defaultEvent;
 132.905 +        var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;
 132.906 +
 132.907 +        var subscription = new ko.subscription(this, boundCallback, function () {
 132.908 +            ko.utils.arrayRemoveItem(this._subscriptions[event], subscription);
 132.909 +        }.bind(this));
 132.910 +
 132.911 +        if (!this._subscriptions[event])
 132.912 +            this._subscriptions[event] = [];
 132.913 +        this._subscriptions[event].push(subscription);
 132.914 +        return subscription;
 132.915 +    },
 132.916 +
 132.917 +    "notifySubscribers": function (valueToNotify, event) {
 132.918 +        event = event || defaultEvent;
 132.919 +        if (this._subscriptions[event]) {
 132.920 +            ko.dependencyDetection.ignore(function() {
 132.921 +                ko.utils.arrayForEach(this._subscriptions[event].slice(0), function (subscription) {
 132.922 +                    // In case a subscription was disposed during the arrayForEach cycle, check
 132.923 +                    // for isDisposed on each subscription before invoking its callback
 132.924 +                    if (subscription && (subscription.isDisposed !== true))
 132.925 +                        subscription.callback(valueToNotify);
 132.926 +                });
 132.927 +            }, this);
 132.928 +        }
 132.929 +    },
 132.930 +
 132.931 +    getSubscriptionsCount: function () {
 132.932 +        var total = 0;
 132.933 +        for (var eventName in this._subscriptions) {
 132.934 +            if (this._subscriptions.hasOwnProperty(eventName))
 132.935 +                total += this._subscriptions[eventName].length;
 132.936 +        }
 132.937 +        return total;
 132.938 +    },
 132.939 +
 132.940 +    extend: applyExtenders
 132.941 +};
 132.942 +
 132.943 +
 132.944 +ko.isSubscribable = function (instance) {
 132.945 +    return typeof instance.subscribe == "function" && typeof instance["notifySubscribers"] == "function";
 132.946 +};
 132.947 +
 132.948 +ko.exportSymbol('subscribable', ko.subscribable);
 132.949 +ko.exportSymbol('isSubscribable', ko.isSubscribable);
 132.950 +
 132.951 +ko.dependencyDetection = (function () {
 132.952 +    var _frames = [];
 132.953 +
 132.954 +    return {
 132.955 +        begin: function (callback) {
 132.956 +            _frames.push({ callback: callback, distinctDependencies:[] });
 132.957 +        },
 132.958 +
 132.959 +        end: function () {
 132.960 +            _frames.pop();
 132.961 +        },
 132.962 +
 132.963 +        registerDependency: function (subscribable) {
 132.964 +            if (!ko.isSubscribable(subscribable))
 132.965 +                throw new Error("Only subscribable things can act as dependencies");
 132.966 +            if (_frames.length > 0) {
 132.967 +                var topFrame = _frames[_frames.length - 1];
 132.968 +                if (!topFrame || ko.utils.arrayIndexOf(topFrame.distinctDependencies, subscribable) >= 0)
 132.969 +                    return;
 132.970 +                topFrame.distinctDependencies.push(subscribable);
 132.971 +                topFrame.callback(subscribable);
 132.972 +            }
 132.973 +        },
 132.974 +
 132.975 +        ignore: function(callback, callbackTarget, callbackArgs) {
 132.976 +            try {
 132.977 +                _frames.push(null);
 132.978 +                return callback.apply(callbackTarget, callbackArgs || []);
 132.979 +            } finally {
 132.980 +                _frames.pop();
 132.981 +            }
 132.982 +        }
 132.983 +    };
 132.984 +})();
 132.985 +var primitiveTypes = { 'undefined':true, 'boolean':true, 'number':true, 'string':true };
 132.986 +
 132.987 +ko.observable = function (initialValue) {
 132.988 +    var _latestValue = initialValue;
 132.989 +
 132.990 +    function observable() {
 132.991 +        if (arguments.length > 0) {
 132.992 +            // Write
 132.993 +
 132.994 +            // Ignore writes if the value hasn't changed
 132.995 +            if ((!observable['equalityComparer']) || !observable['equalityComparer'](_latestValue, arguments[0])) {
 132.996 +                observable.valueWillMutate();
 132.997 +                _latestValue = arguments[0];
 132.998 +                if (DEBUG) observable._latestValue = _latestValue;
 132.999 +                observable.valueHasMutated();
132.1000 +            }
132.1001 +            return this; // Permits chained assignments
132.1002 +        }
132.1003 +        else {
132.1004 +            // Read
132.1005 +            ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
132.1006 +            return _latestValue;
132.1007 +        }
132.1008 +    }
132.1009 +    if (DEBUG) observable._latestValue = _latestValue;
132.1010 +    ko.subscribable.call(observable);
132.1011 +    observable.peek = function() { return _latestValue };
132.1012 +    observable.valueHasMutated = function () { observable["notifySubscribers"](_latestValue); }
132.1013 +    observable.valueWillMutate = function () { observable["notifySubscribers"](_latestValue, "beforeChange"); }
132.1014 +    ko.utils.extend(observable, ko.observable['fn']);
132.1015 +
132.1016 +    ko.exportProperty(observable, 'peek', observable.peek);
132.1017 +    ko.exportProperty(observable, "valueHasMutated", observable.valueHasMutated);
132.1018 +    ko.exportProperty(observable, "valueWillMutate", observable.valueWillMutate);
132.1019 +
132.1020 +    return observable;
132.1021 +}
132.1022 +
132.1023 +ko.observable['fn'] = {
132.1024 +    "equalityComparer": function valuesArePrimitiveAndEqual(a, b) {
132.1025 +        var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);
132.1026 +        return oldValueIsPrimitive ? (a === b) : false;
132.1027 +    }
132.1028 +};
132.1029 +
132.1030 +var protoProperty = ko.observable.protoProperty = "__ko_proto__";
132.1031 +ko.observable['fn'][protoProperty] = ko.observable;
132.1032 +
132.1033 +ko.hasPrototype = function(instance, prototype) {
132.1034 +    if ((instance === null) || (instance === undefined) || (instance[protoProperty] === undefined)) return false;
132.1035 +    if (instance[protoProperty] === prototype) return true;
132.1036 +    return ko.hasPrototype(instance[protoProperty], prototype); // Walk the prototype chain
132.1037 +};
132.1038 +
132.1039 +ko.isObservable = function (instance) {
132.1040 +    return ko.hasPrototype(instance, ko.observable);
132.1041 +}
132.1042 +ko.isWriteableObservable = function (instance) {
132.1043 +    // Observable
132.1044 +    if ((typeof instance == "function") && instance[protoProperty] === ko.observable)
132.1045 +        return true;
132.1046 +    // Writeable dependent observable
132.1047 +    if ((typeof instance == "function") && (instance[protoProperty] === ko.dependentObservable) && (instance.hasWriteFunction))
132.1048 +        return true;
132.1049 +    // Anything else
132.1050 +    return false;
132.1051 +}
132.1052 +
132.1053 +
132.1054 +ko.exportSymbol('observable', ko.observable);
132.1055 +ko.exportSymbol('isObservable', ko.isObservable);
132.1056 +ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);
132.1057 +ko.observableArray = function (initialValues) {
132.1058 +    if (arguments.length == 0) {
132.1059 +        // Zero-parameter constructor initializes to empty array
132.1060 +        initialValues = [];
132.1061 +    }
132.1062 +    if ((initialValues !== null) && (initialValues !== undefined) && !('length' in initialValues))
132.1063 +        throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
132.1064 +
132.1065 +    var result = ko.observable(initialValues);
132.1066 +    ko.utils.extend(result, ko.observableArray['fn']);
132.1067 +    return result;
132.1068 +}
132.1069 +
132.1070 +ko.observableArray['fn'] = {
132.1071 +    'remove': function (valueOrPredicate) {
132.1072 +        var underlyingArray = this.peek();
132.1073 +        var removedValues = [];
132.1074 +        var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
132.1075 +        for (var i = 0; i < underlyingArray.length; i++) {
132.1076 +            var value = underlyingArray[i];
132.1077 +            if (predicate(value)) {
132.1078 +                if (removedValues.length === 0) {
132.1079 +                    this.valueWillMutate();
132.1080 +                }
132.1081 +                removedValues.push(value);
132.1082 +                underlyingArray.splice(i, 1);
132.1083 +                i--;
132.1084 +            }
132.1085 +        }
132.1086 +        if (removedValues.length) {
132.1087 +            this.valueHasMutated();
132.1088 +        }
132.1089 +        return removedValues;
132.1090 +    },
132.1091 +
132.1092 +    'removeAll': function (arrayOfValues) {
132.1093 +        // If you passed zero args, we remove everything
132.1094 +        if (arrayOfValues === undefined) {
132.1095 +            var underlyingArray = this.peek();
132.1096 +            var allValues = underlyingArray.slice(0);
132.1097 +            this.valueWillMutate();
132.1098 +            underlyingArray.splice(0, underlyingArray.length);
132.1099 +            this.valueHasMutated();
132.1100 +            return allValues;
132.1101 +        }
132.1102 +        // If you passed an arg, we interpret it as an array of entries to remove
132.1103 +        if (!arrayOfValues)
132.1104 +            return [];
132.1105 +        return this['remove'](function (value) {
132.1106 +            return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
132.1107 +        });
132.1108 +    },
132.1109 +
132.1110 +    'destroy': function (valueOrPredicate) {
132.1111 +        var underlyingArray = this.peek();
132.1112 +        var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
132.1113 +        this.valueWillMutate();
132.1114 +        for (var i = underlyingArray.length - 1; i >= 0; i--) {
132.1115 +            var value = underlyingArray[i];
132.1116 +            if (predicate(value))
132.1117 +                underlyingArray[i]["_destroy"] = true;
132.1118 +        }
132.1119 +        this.valueHasMutated();
132.1120 +    },
132.1121 +
132.1122 +    'destroyAll': function (arrayOfValues) {
132.1123 +        // If you passed zero args, we destroy everything
132.1124 +        if (arrayOfValues === undefined)
132.1125 +            return this['destroy'](function() { return true });
132.1126 +
132.1127 +        // If you passed an arg, we interpret it as an array of entries to destroy
132.1128 +        if (!arrayOfValues)
132.1129 +            return [];
132.1130 +        return this['destroy'](function (value) {
132.1131 +            return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
132.1132 +        });
132.1133 +    },
132.1134 +
132.1135 +    'indexOf': function (item) {
132.1136 +        var underlyingArray = this();
132.1137 +        return ko.utils.arrayIndexOf(underlyingArray, item);
132.1138 +    },
132.1139 +
132.1140 +    'replace': function(oldItem, newItem) {
132.1141 +        var index = this['indexOf'](oldItem);
132.1142 +        if (index >= 0) {
132.1143 +            this.valueWillMutate();
132.1144 +            this.peek()[index] = newItem;
132.1145 +            this.valueHasMutated();
132.1146 +        }
132.1147 +    }
132.1148 +}
132.1149 +
132.1150 +// Populate ko.observableArray.fn with read/write functions from native arrays
132.1151 +// Important: Do not add any additional functions here that may reasonably be used to *read* data from the array
132.1152 +// because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale
132.1153 +ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
132.1154 +    ko.observableArray['fn'][methodName] = function () {
132.1155 +        // Use "peek" to avoid creating a subscription in any computed that we're executing in the context of
132.1156 +        // (for consistency with mutating regular observables)
132.1157 +        var underlyingArray = this.peek();
132.1158 +        this.valueWillMutate();
132.1159 +        var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
132.1160 +        this.valueHasMutated();
132.1161 +        return methodCallResult;
132.1162 +    };
132.1163 +});
132.1164 +
132.1165 +// Populate ko.observableArray.fn with read-only functions from native arrays
132.1166 +ko.utils.arrayForEach(["slice"], function (methodName) {
132.1167 +    ko.observableArray['fn'][methodName] = function () {
132.1168 +        var underlyingArray = this();
132.1169 +        return underlyingArray[methodName].apply(underlyingArray, arguments);
132.1170 +    };
132.1171 +});
132.1172 +
132.1173 +ko.exportSymbol('observableArray', ko.observableArray);
132.1174 +ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {
132.1175 +    var _latestValue,
132.1176 +        _hasBeenEvaluated = false,
132.1177 +        _isBeingEvaluated = false,
132.1178 +        readFunction = evaluatorFunctionOrOptions;
132.1179 +
132.1180 +    if (readFunction && typeof readFunction == "object") {
132.1181 +        // Single-parameter syntax - everything is on this "options" param
132.1182 +        options = readFunction;
132.1183 +        readFunction = options["read"];
132.1184 +    } else {
132.1185 +        // Multi-parameter syntax - construct the options according to the params passed
132.1186 +        options = options || {};
132.1187 +        if (!readFunction)
132.1188 +            readFunction = options["read"];
132.1189 +    }
132.1190 +    if (typeof readFunction != "function")
132.1191 +        throw new Error("Pass a function that returns the value of the ko.computed");
132.1192 +
132.1193 +    function addSubscriptionToDependency(subscribable) {
132.1194 +        _subscriptionsToDependencies.push(subscribable.subscribe(evaluatePossiblyAsync));
132.1195 +    }
132.1196 +
132.1197 +    function disposeAllSubscriptionsToDependencies() {
132.1198 +        ko.utils.arrayForEach(_subscriptionsToDependencies, function (subscription) {
132.1199 +            subscription.dispose();
132.1200 +        });
132.1201 +        _subscriptionsToDependencies = [];
132.1202 +    }
132.1203 +
132.1204 +    function evaluatePossiblyAsync() {
132.1205 +        var throttleEvaluationTimeout = dependentObservable['throttleEvaluation'];
132.1206 +        if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
132.1207 +            clearTimeout(evaluationTimeoutInstance);
132.1208 +            evaluationTimeoutInstance = setTimeout(evaluateImmediate, throttleEvaluationTimeout);
132.1209 +        } else
132.1210 +            evaluateImmediate();
132.1211 +    }
132.1212 +
132.1213 +    function evaluateImmediate() {
132.1214 +        if (_isBeingEvaluated) {
132.1215 +            // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.
132.1216 +            // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost
132.1217 +            // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing
132.1218 +            // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387
132.1219 +            return;
132.1220 +        }
132.1221 +
132.1222 +        // Don't dispose on first evaluation, because the "disposeWhen" callback might
132.1223 +        // e.g., dispose when the associated DOM element isn't in the doc, and it's not
132.1224 +        // going to be in the doc until *after* the first evaluation
132.1225 +        if (_hasBeenEvaluated && disposeWhen()) {
132.1226 +            dispose();
132.1227 +            return;
132.1228 +        }
132.1229 +
132.1230 +        _isBeingEvaluated = true;
132.1231 +        try {
132.1232 +            // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).
132.1233 +            // Then, during evaluation, we cross off any that are in fact still being used.
132.1234 +            var disposalCandidates = ko.utils.arrayMap(_subscriptionsToDependencies, function(item) {return item.target;});
132.1235 +
132.1236 +            ko.dependencyDetection.begin(function(subscribable) {
132.1237 +                var inOld;
132.1238 +                if ((inOld = ko.utils.arrayIndexOf(disposalCandidates, subscribable)) >= 0)
132.1239 +                    disposalCandidates[inOld] = undefined; // Don't want to dispose this subscription, as it's still being used
132.1240 +                else
132.1241 +                    addSubscriptionToDependency(subscribable); // Brand new subscription - add it
132.1242 +            });
132.1243 +
132.1244 +            var newValue = readFunction.call(evaluatorFunctionTarget);
132.1245 +
132.1246 +            // For each subscription no longer being used, remove it from the active subscriptions list and dispose it
132.1247 +            for (var i = disposalCandidates.length - 1; i >= 0; i--) {
132.1248 +                if (disposalCandidates[i])
132.1249 +                    _subscriptionsToDependencies.splice(i, 1)[0].dispose();
132.1250 +            }
132.1251 +            _hasBeenEvaluated = true;
132.1252 +
132.1253 +            dependentObservable["notifySubscribers"](_latestValue, "beforeChange");
132.1254 +            _latestValue = newValue;
132.1255 +            if (DEBUG) dependentObservable._latestValue = _latestValue;
132.1256 +        } finally {
132.1257 +            ko.dependencyDetection.end();
132.1258 +        }
132.1259 +
132.1260 +        dependentObservable["notifySubscribers"](_latestValue);
132.1261 +        _isBeingEvaluated = false;
132.1262 +        if (!_subscriptionsToDependencies.length)
132.1263 +            dispose();
132.1264 +    }
132.1265 +
132.1266 +    function dependentObservable() {
132.1267 +        if (arguments.length > 0) {
132.1268 +            if (typeof writeFunction === "function") {
132.1269 +                // Writing a value
132.1270 +                writeFunction.apply(evaluatorFunctionTarget, arguments);
132.1271 +            } else {
132.1272 +                throw new Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
132.1273 +            }
132.1274 +            return this; // Permits chained assignments
132.1275 +        } else {
132.1276 +            // Reading the value
132.1277 +            if (!_hasBeenEvaluated)
132.1278 +                evaluateImmediate();
132.1279 +            ko.dependencyDetection.registerDependency(dependentObservable);
132.1280 +            return _latestValue;
132.1281 +        }
132.1282 +    }
132.1283 +
132.1284 +    function peek() {
132.1285 +        if (!_hasBeenEvaluated)
132.1286 +            evaluateImmediate();
132.1287 +        return _latestValue;
132.1288 +    }
132.1289 +
132.1290 +    function isActive() {
132.1291 +        return !_hasBeenEvaluated || _subscriptionsToDependencies.length > 0;
132.1292 +    }
132.1293 +
132.1294 +    // By here, "options" is always non-null
132.1295 +    var writeFunction = options["write"],
132.1296 +        disposeWhenNodeIsRemoved = options["disposeWhenNodeIsRemoved"] || options.disposeWhenNodeIsRemoved || null,
132.1297 +        disposeWhen = options["disposeWhen"] || options.disposeWhen || function() { return false; },
132.1298 +        dispose = disposeAllSubscriptionsToDependencies,
132.1299 +        _subscriptionsToDependencies = [],
132.1300 +        evaluationTimeoutInstance = null;
132.1301 +
132.1302 +    if (!evaluatorFunctionTarget)
132.1303 +        evaluatorFunctionTarget = options["owner"];
132.1304 +
132.1305 +    dependentObservable.peek = peek;
132.1306 +    dependentObservable.getDependenciesCount = function () { return _subscriptionsToDependencies.length; };
132.1307 +    dependentObservable.hasWriteFunction = typeof options["write"] === "function";
132.1308 +    dependentObservable.dispose = function () { dispose(); };
132.1309 +    dependentObservable.isActive = isActive;
132.1310 +    dependentObservable.valueHasMutated = function() {
132.1311 +        _hasBeenEvaluated = false;
132.1312 +        evaluateImmediate();
132.1313 +    };
132.1314 +
132.1315 +    ko.subscribable.call(dependentObservable);
132.1316 +    ko.utils.extend(dependentObservable, ko.dependentObservable['fn']);
132.1317 +
132.1318 +    ko.exportProperty(dependentObservable, 'peek', dependentObservable.peek);
132.1319 +    ko.exportProperty(dependentObservable, 'dispose', dependentObservable.dispose);
132.1320 +    ko.exportProperty(dependentObservable, 'isActive', dependentObservable.isActive);
132.1321 +    ko.exportProperty(dependentObservable, 'getDependenciesCount', dependentObservable.getDependenciesCount);
132.1322 +
132.1323 +    // Evaluate, unless deferEvaluation is true
132.1324 +    if (options['deferEvaluation'] !== true)
132.1325 +        evaluateImmediate();
132.1326 +
132.1327 +    // Build "disposeWhenNodeIsRemoved" and "disposeWhenNodeIsRemovedCallback" option values.
132.1328 +    // But skip if isActive is false (there will never be any dependencies to dispose).
132.1329 +    // (Note: "disposeWhenNodeIsRemoved" option both proactively disposes as soon as the node is removed using ko.removeNode(),
132.1330 +    // plus adds a "disposeWhen" callback that, on each evaluation, disposes if the node was removed by some other means.)
132.1331 +    if (disposeWhenNodeIsRemoved && isActive()) {
132.1332 +        dispose = function() {
132.1333 +            ko.utils.domNodeDisposal.removeDisposeCallback(disposeWhenNodeIsRemoved, arguments.callee);
132.1334 +            disposeAllSubscriptionsToDependencies();
132.1335 +        };
132.1336 +        ko.utils.domNodeDisposal.addDisposeCallback(disposeWhenNodeIsRemoved, dispose);
132.1337 +        var existingDisposeWhenFunction = disposeWhen;
132.1338 +        disposeWhen = function () {
132.1339 +            return !ko.utils.domNodeIsAttachedToDocument(disposeWhenNodeIsRemoved) || existingDisposeWhenFunction();
132.1340 +        }
132.1341 +    }
132.1342 +
132.1343 +    return dependentObservable;
132.1344 +};
132.1345 +
132.1346 +ko.isComputed = function(instance) {
132.1347 +    return ko.hasPrototype(instance, ko.dependentObservable);
132.1348 +};
132.1349 +
132.1350 +var protoProp = ko.observable.protoProperty; // == "__ko_proto__"
132.1351 +ko.dependentObservable[protoProp] = ko.observable;
132.1352 +
132.1353 +ko.dependentObservable['fn'] = {};
132.1354 +ko.dependentObservable['fn'][protoProp] = ko.dependentObservable;
132.1355 +
132.1356 +ko.exportSymbol('dependentObservable', ko.dependentObservable);
132.1357 +ko.exportSymbol('computed', ko.dependentObservable); // Make "ko.computed" an alias for "ko.dependentObservable"
132.1358 +ko.exportSymbol('isComputed', ko.isComputed);
132.1359 +
132.1360 +(function() {
132.1361 +    var maxNestedObservableDepth = 10; // Escape the (unlikely) pathalogical case where an observable's current value is itself (or similar reference cycle)
132.1362 +
132.1363 +    ko.toJS = function(rootObject) {
132.1364 +        if (arguments.length == 0)
132.1365 +            throw new Error("When calling ko.toJS, pass the object you want to convert.");
132.1366 +
132.1367 +        // We just unwrap everything at every level in the object graph
132.1368 +        return mapJsObjectGraph(rootObject, function(valueToMap) {
132.1369 +            // Loop because an observable's value might in turn be another observable wrapper
132.1370 +            for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)
132.1371 +                valueToMap = valueToMap();
132.1372 +            return valueToMap;
132.1373 +        });
132.1374 +    };
132.1375 +
132.1376 +    ko.toJSON = function(rootObject, replacer, space) {     // replacer and space are optional
132.1377 +        var plainJavaScriptObject = ko.toJS(rootObject);
132.1378 +        return ko.utils.stringifyJson(plainJavaScriptObject, replacer, space);
132.1379 +    };
132.1380 +
132.1381 +    function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {
132.1382 +        visitedObjects = visitedObjects || new objectLookup();
132.1383 +
132.1384 +        rootObject = mapInputCallback(rootObject);
132.1385 +        var canHaveProperties = (typeof rootObject == "object") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof Date));
132.1386 +        if (!canHaveProperties)
132.1387 +            return rootObject;
132.1388 +
132.1389 +        var outputProperties = rootObject instanceof Array ? [] : {};
132.1390 +        visitedObjects.save(rootObject, outputProperties);
132.1391 +
132.1392 +        visitPropertiesOrArrayEntries(rootObject, function(indexer) {
132.1393 +            var propertyValue = mapInputCallback(rootObject[indexer]);
132.1394 +
132.1395 +            switch (typeof propertyValue) {
132.1396 +                case "boolean":
132.1397 +                case "number":
132.1398 +                case "string":
132.1399 +                case "function":
132.1400 +                    outputProperties[indexer] = propertyValue;
132.1401 +                    break;
132.1402 +                case "object":
132.1403 +                case "undefined":
132.1404 +                    var previouslyMappedValue = visitedObjects.get(propertyValue);
132.1405 +                    outputProperties[indexer] = (previouslyMappedValue !== undefined)
132.1406 +                        ? previouslyMappedValue
132.1407 +                        : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);
132.1408 +                    break;
132.1409 +            }
132.1410 +        });
132.1411 +
132.1412 +        return outputProperties;
132.1413 +    }
132.1414 +
132.1415 +    function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {
132.1416 +        if (rootObject instanceof Array) {
132.1417 +            for (var i = 0; i < rootObject.length; i++)
132.1418 +                visitorCallback(i);
132.1419 +
132.1420 +            // For arrays, also respect toJSON property for custom mappings (fixes #278)
132.1421 +            if (typeof rootObject['toJSON'] == 'function')
132.1422 +                visitorCallback('toJSON');
132.1423 +        } else {
132.1424 +            for (var propertyName in rootObject)
132.1425 +                visitorCallback(propertyName);
132.1426 +        }
132.1427 +    };
132.1428 +
132.1429 +    function objectLookup() {
132.1430 +        var keys = [];
132.1431 +        var values = [];
132.1432 +        this.save = function(key, value) {
132.1433 +            var existingIndex = ko.utils.arrayIndexOf(keys, key);
132.1434 +            if (existingIndex >= 0)
132.1435 +                values[existingIndex] = value;
132.1436 +            else {
132.1437 +                keys.push(key);
132.1438 +                values.push(value);
132.1439 +            }
132.1440 +        };
132.1441 +        this.get = function(key) {
132.1442 +            var existingIndex = ko.utils.arrayIndexOf(keys, key);
132.1443 +            return (existingIndex >= 0) ? values[existingIndex] : undefined;
132.1444 +        };
132.1445 +    };
132.1446 +})();
132.1447 +
132.1448 +ko.exportSymbol('toJS', ko.toJS);
132.1449 +ko.exportSymbol('toJSON', ko.toJSON);
132.1450 +(function () {
132.1451 +    var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';
132.1452 +
132.1453 +    // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
132.1454 +    // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
132.1455 +    // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
132.1456 +    ko.selectExtensions = {
132.1457 +        readValue : function(element) {
132.1458 +            switch (ko.utils.tagNameLower(element)) {
132.1459 +                case 'option':
132.1460 +                    if (element[hasDomDataExpandoProperty] === true)
132.1461 +                        return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
132.1462 +                    return ko.utils.ieVersion <= 7
132.1463 +                        ? (element.getAttributeNode('value').specified ? element.value : element.text)
132.1464 +                        : element.value;
132.1465 +                case 'select':
132.1466 +                    return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
132.1467 +                default:
132.1468 +                    return element.value;
132.1469 +            }
132.1470 +        },
132.1471 +
132.1472 +        writeValue: function(element, value) {
132.1473 +            switch (ko.utils.tagNameLower(element)) {
132.1474 +                case 'option':
132.1475 +                    switch(typeof value) {
132.1476 +                        case "string":
132.1477 +                            ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);
132.1478 +                            if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
132.1479 +                                delete element[hasDomDataExpandoProperty];
132.1480 +                            }
132.1481 +                            element.value = value;
132.1482 +                            break;
132.1483 +                        default:
132.1484 +                            // Store arbitrary object using DomData
132.1485 +                            ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
132.1486 +                            element[hasDomDataExpandoProperty] = true;
132.1487 +
132.1488 +                            // Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.
132.1489 +                            element.value = typeof value === "number" ? value : "";
132.1490 +                            break;
132.1491 +                    }
132.1492 +                    break;
132.1493 +                case 'select':
132.1494 +                    for (var i = element.options.length - 1; i >= 0; i--) {
132.1495 +                        if (ko.selectExtensions.readValue(element.options[i]) == value) {
132.1496 +                            element.selectedIndex = i;
132.1497 +                            break;
132.1498 +                        }
132.1499 +                    }
132.1500 +                    break;
132.1501 +                default:
132.1502 +                    if ((value === null) || (value === undefined))
132.1503 +                        value = "";
132.1504 +                    element.value = value;
132.1505 +                    break;
132.1506 +            }
132.1507 +        }
132.1508 +    };
132.1509 +})();
132.1510 +
132.1511 +ko.exportSymbol('selectExtensions', ko.selectExtensions);
132.1512 +ko.exportSymbol('selectExtensions.readValue', ko.selectExtensions.readValue);
132.1513 +ko.exportSymbol('selectExtensions.writeValue', ko.selectExtensions.writeValue);
132.1514 +ko.expressionRewriting = (function () {
132.1515 +    var restoreCapturedTokensRegex = /\@ko_token_(\d+)\@/g;
132.1516 +    var javaScriptReservedWords = ["true", "false"];
132.1517 +
132.1518 +    // Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor
132.1519 +    // This is designed to be simple and avoid false negatives, but could produce false positives (e.g., a+b.c).
132.1520 +    var javaScriptAssignmentTarget = /^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i;
132.1521 +
132.1522 +    function restoreTokens(string, tokens) {
132.1523 +        var prevValue = null;
132.1524 +        while (string != prevValue) { // Keep restoring tokens until it no longer makes a difference (they may be nested)
132.1525 +            prevValue = string;
132.1526 +            string = string.replace(restoreCapturedTokensRegex, function (match, tokenIndex) {
132.1527 +                return tokens[tokenIndex];
132.1528 +            });
132.1529 +        }
132.1530 +        return string;
132.1531 +    }
132.1532 +
132.1533 +    function getWriteableValue(expression) {
132.1534 +        if (ko.utils.arrayIndexOf(javaScriptReservedWords, ko.utils.stringTrim(expression).toLowerCase()) >= 0)
132.1535 +            return false;
132.1536 +        var match = expression.match(javaScriptAssignmentTarget);
132.1537 +        return match === null ? false : match[1] ? ('Object(' + match[1] + ')' + match[2]) : expression;
132.1538 +    }
132.1539 +
132.1540 +    function ensureQuoted(key) {
132.1541 +        var trimmedKey = ko.utils.stringTrim(key);
132.1542 +        switch (trimmedKey.length && trimmedKey.charAt(0)) {
132.1543 +            case "'":
132.1544 +            case '"':
132.1545 +                return key;
132.1546 +            default:
132.1547 +                return "'" + trimmedKey + "'";
132.1548 +        }
132.1549 +    }
132.1550 +
132.1551 +    return {
132.1552 +        bindingRewriteValidators: [],
132.1553 +
132.1554 +        parseObjectLiteral: function(objectLiteralString) {
132.1555 +            // A full tokeniser+lexer would add too much weight to this library, so here's a simple parser
132.1556 +            // that is sufficient just to split an object literal string into a set of top-level key-value pairs
132.1557 +
132.1558 +            var str = ko.utils.stringTrim(objectLiteralString);
132.1559 +            if (str.length < 3)
132.1560 +                return [];
132.1561 +            if (str.charAt(0) === "{")// Ignore any braces surrounding the whole object literal
132.1562 +                str = str.substring(1, str.length - 1);
132.1563 +
132.1564 +            // Pull out any string literals and regex literals
132.1565 +            var tokens = [];
132.1566 +            var tokenStart = null, tokenEndChar;
132.1567 +            for (var position = 0; position < str.length; position++) {
132.1568 +                var c = str.charAt(position);
132.1569 +                if (tokenStart === null) {
132.1570 +                    switch (c) {
132.1571 +                        case '"':
132.1572 +                        case "'":
132.1573 +                        case "/":
132.1574 +                            tokenStart = position;
132.1575 +                            tokenEndChar = c;
132.1576 +                            break;
132.1577 +                    }
132.1578 +                } else if ((c == tokenEndChar) && (str.charAt(position - 1) !== "\\")) {
132.1579 +                    var token = str.substring(tokenStart, position + 1);
132.1580 +                    tokens.push(token);
132.1581 +                    var replacement = "@ko_token_" + (tokens.length - 1) + "@";
132.1582 +                    str = str.substring(0, tokenStart) + replacement + str.substring(position + 1);
132.1583 +                    position -= (token.length - replacement.length);
132.1584 +                    tokenStart = null;
132.1585 +                }
132.1586 +            }
132.1587 +
132.1588 +            // Next pull out balanced paren, brace, and bracket blocks
132.1589 +            tokenStart = null;
132.1590 +            tokenEndChar = null;
132.1591 +            var tokenDepth = 0, tokenStartChar = null;
132.1592 +            for (var position = 0; position < str.length; position++) {
132.1593 +                var c = str.charAt(position);
132.1594 +                if (tokenStart === null) {
132.1595 +                    switch (c) {
132.1596 +                        case "{": tokenStart = position; tokenStartChar = c;
132.1597 +                                  tokenEndChar = "}";
132.1598 +                                  break;
132.1599 +                        case "(": tokenStart = position; tokenStartChar = c;
132.1600 +                                  tokenEndChar = ")";
132.1601 +                                  break;
132.1602 +                        case "[": tokenStart = position; tokenStartChar = c;
132.1603 +                                  tokenEndChar = "]";
132.1604 +                                  break;
132.1605 +                    }
132.1606 +                }
132.1607 +
132.1608 +                if (c === tokenStartChar)
132.1609 +                    tokenDepth++;
132.1610 +                else if (c === tokenEndChar) {
132.1611 +                    tokenDepth--;
132.1612 +                    if (tokenDepth === 0) {
132.1613 +                        var token = str.substring(tokenStart, position + 1);
132.1614 +                        tokens.push(token);
132.1615 +                        var replacement = "@ko_token_" + (tokens.length - 1) + "@";
132.1616 +                        str = str.substring(0, tokenStart) + replacement + str.substring(position + 1);
132.1617 +                        position -= (token.length - replacement.length);
132.1618 +                        tokenStart = null;
132.1619 +                    }
132.1620 +                }
132.1621 +            }
132.1622 +
132.1623 +            // Now we can safely split on commas to get the key/value pairs
132.1624 +            var result = [];
132.1625 +            var keyValuePairs = str.split(",");
132.1626 +            for (var i = 0, j = keyValuePairs.length; i < j; i++) {
132.1627 +                var pair = keyValuePairs[i];
132.1628 +                var colonPos = pair.indexOf(":");
132.1629 +                if ((colonPos > 0) && (colonPos < pair.length - 1)) {
132.1630 +                    var key = pair.substring(0, colonPos);
132.1631 +                    var value = pair.substring(colonPos + 1);
132.1632 +                    result.push({ 'key': restoreTokens(key, tokens), 'value': restoreTokens(value, tokens) });
132.1633 +                } else {
132.1634 +                    result.push({ 'unknown': restoreTokens(pair, tokens) });
132.1635 +                }
132.1636 +            }
132.1637 +            return result;
132.1638 +        },
132.1639 +
132.1640 +        preProcessBindings: function (objectLiteralStringOrKeyValueArray) {
132.1641 +            var keyValueArray = typeof objectLiteralStringOrKeyValueArray === "string"
132.1642 +                ? ko.expressionRewriting.parseObjectLiteral(objectLiteralStringOrKeyValueArray)
132.1643 +                : objectLiteralStringOrKeyValueArray;
132.1644 +            var resultStrings = [], propertyAccessorResultStrings = [];
132.1645 +
132.1646 +            var keyValueEntry;
132.1647 +            for (var i = 0; keyValueEntry = keyValueArray[i]; i++) {
132.1648 +                if (resultStrings.length > 0)
132.1649 +                    resultStrings.push(",");
132.1650 +
132.1651 +                if (keyValueEntry['key']) {
132.1652 +                    var quotedKey = ensureQuoted(keyValueEntry['key']), val = keyValueEntry['value'];
132.1653 +                    resultStrings.push(quotedKey);
132.1654 +                    resultStrings.push(":");
132.1655 +                    resultStrings.push(val);
132.1656 +
132.1657 +                    if (val = getWriteableValue(ko.utils.stringTrim(val))) {
132.1658 +                        if (propertyAccessorResultStrings.length > 0)
132.1659 +                            propertyAccessorResultStrings.push(", ");
132.1660 +                        propertyAccessorResultStrings.push(quotedKey + " : function(__ko_value) { " + val + " = __ko_value; }");
132.1661 +                    }
132.1662 +                } else if (keyValueEntry['unknown']) {
132.1663 +                    resultStrings.push(keyValueEntry['unknown']);
132.1664 +                }
132.1665 +            }
132.1666 +
132.1667 +            var combinedResult = resultStrings.join("");
132.1668 +            if (propertyAccessorResultStrings.length > 0) {
132.1669 +                var allPropertyAccessors = propertyAccessorResultStrings.join("");
132.1670 +                combinedResult = combinedResult + ", '_ko_property_writers' : { " + allPropertyAccessors + " } ";
132.1671 +            }
132.1672 +
132.1673 +            return combinedResult;
132.1674 +        },
132.1675 +
132.1676 +        keyValueArrayContainsKey: function(keyValueArray, key) {
132.1677 +            for (var i = 0; i < keyValueArray.length; i++)
132.1678 +                if (ko.utils.stringTrim(keyValueArray[i]['key']) == key)
132.1679 +                    return true;
132.1680 +            return false;
132.1681 +        },
132.1682 +
132.1683 +        // Internal, private KO utility for updating model properties from within bindings
132.1684 +        // property:            If the property being updated is (or might be) an observable, pass it here
132.1685 +        //                      If it turns out to be a writable observable, it will be written to directly
132.1686 +        // allBindingsAccessor: All bindings in the current execution context.
132.1687 +        //                      This will be searched for a '_ko_property_writers' property in case you're writing to a non-observable
132.1688 +        // key:                 The key identifying the property to be written. Example: for { hasFocus: myValue }, write to 'myValue' by specifying the key 'hasFocus'
132.1689 +        // value:               The value to be written
132.1690 +        // checkIfDifferent:    If true, and if the property being written is a writable observable, the value will only be written if
132.1691 +        //                      it is !== existing value on that writable observable
132.1692 +        writeValueToProperty: function(property, allBindingsAccessor, key, value, checkIfDifferent) {
132.1693 +            if (!property || !ko.isWriteableObservable(property)) {
132.1694 +                var propWriters = allBindingsAccessor()['_ko_property_writers'];
132.1695 +                if (propWriters && propWriters[key])
132.1696 +                    propWriters[key](value);
132.1697 +            } else if (!checkIfDifferent || property.peek() !== value) {
132.1698 +                property(value);
132.1699 +            }
132.1700 +        }
132.1701 +    };
132.1702 +})();
132.1703 +
132.1704 +ko.exportSymbol('expressionRewriting', ko.expressionRewriting);
132.1705 +ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);
132.1706 +ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);
132.1707 +ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);
132.1708 +
132.1709 +// For backward compatibility, define the following aliases. (Previously, these function names were misleading because
132.1710 +// they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)
132.1711 +ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);
132.1712 +ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);(function() {
132.1713 +    // "Virtual elements" is an abstraction on top of the usual DOM API which understands the notion that comment nodes
132.1714 +    // may be used to represent hierarchy (in addition to the DOM's natural hierarchy).
132.1715 +    // If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state
132.1716 +    // of that virtual hierarchy
132.1717 +    //
132.1718 +    // The point of all this is to support containerless templates (e.g., <!-- ko foreach:someCollection -->blah<!-- /ko -->)
132.1719 +    // without having to scatter special cases all over the binding and templating code.
132.1720 +
132.1721 +    // IE 9 cannot reliably read the "nodeValue" property of a comment node (see https://github.com/SteveSanderson/knockout/issues/186)
132.1722 +    // but it does give them a nonstandard alternative property called "text" that it can read reliably. Other browsers don't have that property.
132.1723 +    // So, use node.text where available, and node.nodeValue elsewhere
132.1724 +    var commentNodesHaveTextProperty = document.createComment("test").text === "<!--test-->";
132.1725 +
132.1726 +    var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*-->$/ : /^\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*$/;
132.1727 +    var endCommentRegex =   commentNodesHaveTextProperty ? /^<!--\s*\/ko\s*-->$/ : /^\s*\/ko\s*$/;
132.1728 +    var htmlTagsWithOptionallyClosingChildren = { 'ul': true, 'ol': true };
132.1729 +
132.1730 +    function isStartComment(node) {
132.1731 +        return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);
132.1732 +    }
132.1733 +
132.1734 +    function isEndComment(node) {
132.1735 +        return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(endCommentRegex);
132.1736 +    }
132.1737 +
132.1738 +    function getVirtualChildren(startComment, allowUnbalanced) {
132.1739 +        var currentNode = startComment;
132.1740 +        var depth = 1;
132.1741 +        var children = [];
132.1742 +        while (currentNode = currentNode.nextSibling) {
132.1743 +            if (isEndComment(currentNode)) {
132.1744 +                depth--;
132.1745 +                if (depth === 0)
132.1746 +                    return children;
132.1747 +            }
132.1748 +
132.1749 +            children.push(currentNode);
132.1750 +
132.1751 +            if (isStartComment(currentNode))
132.1752 +                depth++;
132.1753 +        }
132.1754 +        if (!allowUnbalanced)
132.1755 +            throw new Error("Cannot find closing comment tag to match: " + startComment.nodeValue);
132.1756 +        return null;
132.1757 +    }
132.1758 +
132.1759 +    function getMatchingEndComment(startComment, allowUnbalanced) {
132.1760 +        var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);
132.1761 +        if (allVirtualChildren) {
132.1762 +            if (allVirtualChildren.length > 0)
132.1763 +                return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;
132.1764 +            return startComment.nextSibling;
132.1765 +        } else
132.1766 +            return null; // Must have no matching end comment, and allowUnbalanced is true
132.1767 +    }
132.1768 +
132.1769 +    function getUnbalancedChildTags(node) {
132.1770 +        // e.g., from <div>OK</div><!-- ko blah --><span>Another</span>, returns: <!-- ko blah --><span>Another</span>
132.1771 +        //       from <div>OK</div><!-- /ko --><!-- /ko -->,             returns: <!-- /ko --><!-- /ko -->
132.1772 +        var childNode = node.firstChild, captureRemaining = null;
132.1773 +        if (childNode) {
132.1774 +            do {
132.1775 +                if (captureRemaining)                   // We already hit an unbalanced node and are now just scooping up all subsequent nodes
132.1776 +                    captureRemaining.push(childNode);
132.1777 +                else if (isStartComment(childNode)) {
132.1778 +                    var matchingEndComment = getMatchingEndComment(childNode, /* allowUnbalanced: */ true);
132.1779 +                    if (matchingEndComment)             // It's a balanced tag, so skip immediately to the end of this virtual set
132.1780 +                        childNode = matchingEndComment;
132.1781 +                    else
132.1782 +                        captureRemaining = [childNode]; // It's unbalanced, so start capturing from this point
132.1783 +                } else if (isEndComment(childNode)) {
132.1784 +                    captureRemaining = [childNode];     // It's unbalanced (if it wasn't, we'd have skipped over it already), so start capturing
132.1785 +                }
132.1786 +            } while (childNode = childNode.nextSibling);
132.1787 +        }
132.1788 +        return captureRemaining;
132.1789 +    }
132.1790 +
132.1791 +    ko.virtualElements = {
132.1792 +        allowedBindings: {},
132.1793 +
132.1794 +        childNodes: function(node) {
132.1795 +            return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;
132.1796 +        },
132.1797 +
132.1798 +        emptyNode: function(node) {
132.1799 +            if (!isStartComment(node))
132.1800 +                ko.utils.emptyDomNode(node);
132.1801 +            else {
132.1802 +                var virtualChildren = ko.virtualElements.childNodes(node);
132.1803 +                for (var i = 0, j = virtualChildren.length; i < j; i++)
132.1804 +                    ko.removeNode(virtualChildren[i]);
132.1805 +            }
132.1806 +        },
132.1807 +
132.1808 +        setDomNodeChildren: function(node, childNodes) {
132.1809 +            if (!isStartComment(node))
132.1810 +                ko.utils.setDomNodeChildren(node, childNodes);
132.1811 +            else {
132.1812 +                ko.virtualElements.emptyNode(node);
132.1813 +                var endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children
132.1814 +                for (var i = 0, j = childNodes.length; i < j; i++)
132.1815 +                    endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);
132.1816 +            }
132.1817 +        },
132.1818 +
132.1819 +        prepend: function(containerNode, nodeToPrepend) {
132.1820 +            if (!isStartComment(containerNode)) {
132.1821 +                if (containerNode.firstChild)
132.1822 +                    containerNode.insertBefore(nodeToPrepend, containerNode.firstChild);
132.1823 +                else
132.1824 +                    containerNode.appendChild(nodeToPrepend);
132.1825 +            } else {
132.1826 +                // Start comments must always have a parent and at least one following sibling (the end comment)
132.1827 +                containerNode.parentNode.insertBefore(nodeToPrepend, containerNode.nextSibling);
132.1828 +            }
132.1829 +        },
132.1830 +
132.1831 +        insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {
132.1832 +            if (!insertAfterNode) {
132.1833 +                ko.virtualElements.prepend(containerNode, nodeToInsert);
132.1834 +            } else if (!isStartComment(containerNode)) {
132.1835 +                // Insert after insertion point
132.1836 +                if (insertAfterNode.nextSibling)
132.1837 +                    containerNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
132.1838 +                else
132.1839 +                    containerNode.appendChild(nodeToInsert);
132.1840 +            } else {
132.1841 +                // Children of start comments must always have a parent and at least one following sibling (the end comment)
132.1842 +                containerNode.parentNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
132.1843 +            }
132.1844 +        },
132.1845 +
132.1846 +        firstChild: function(node) {
132.1847 +            if (!isStartComment(node))
132.1848 +                return node.firstChild;
132.1849 +            if (!node.nextSibling || isEndComment(node.nextSibling))
132.1850 +                return null;
132.1851 +            return node.nextSibling;
132.1852 +        },
132.1853 +
132.1854 +        nextSibling: function(node) {
132.1855 +            if (isStartComment(node))
132.1856 +                node = getMatchingEndComment(node);
132.1857 +            if (node.nextSibling && isEndComment(node.nextSibling))
132.1858 +                return null;
132.1859 +            return node.nextSibling;
132.1860 +        },
132.1861 +
132.1862 +        virtualNodeBindingValue: function(node) {
132.1863 +            var regexMatch = isStartComment(node);
132.1864 +            return regexMatch ? regexMatch[1] : null;
132.1865 +        },
132.1866 +
132.1867 +        normaliseVirtualElementDomStructure: function(elementVerified) {
132.1868 +            // Workaround for https://github.com/SteveSanderson/knockout/issues/155
132.1869 +            // (IE <= 8 or IE 9 quirks mode parses your HTML weirdly, treating closing </li> tags as if they don't exist, thereby moving comment nodes
132.1870 +            // that are direct descendants of <ul> into the preceding <li>)
132.1871 +            if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])
132.1872 +                return;
132.1873 +
132.1874 +            // Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags
132.1875 +            // must be intended to appear *after* that child, so move them there.
132.1876 +            var childNode = elementVerified.firstChild;
132.1877 +            if (childNode) {
132.1878 +                do {
132.1879 +                    if (childNode.nodeType === 1) {
132.1880 +                        var unbalancedTags = getUnbalancedChildTags(childNode);
132.1881 +                        if (unbalancedTags) {
132.1882 +                            // Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the child
132.1883 +                            var nodeToInsertBefore = childNode.nextSibling;
132.1884 +                            for (var i = 0; i < unbalancedTags.length; i++) {
132.1885 +                                if (nodeToInsertBefore)
132.1886 +                                    elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);
132.1887 +                                else
132.1888 +                                    elementVerified.appendChild(unbalancedTags[i]);
132.1889 +                            }
132.1890 +                        }
132.1891 +                    }
132.1892 +                } while (childNode = childNode.nextSibling);
132.1893 +            }
132.1894 +        }
132.1895 +    };
132.1896 +})();
132.1897 +ko.exportSymbol('virtualElements', ko.virtualElements);
132.1898 +ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);
132.1899 +ko.exportSymbol('virtualElements.emptyNode', ko.virtualElements.emptyNode);
132.1900 +//ko.exportSymbol('virtualElements.firstChild', ko.virtualElements.firstChild);     // firstChild is not minified
132.1901 +ko.exportSymbol('virtualElements.insertAfter', ko.virtualElements.insertAfter);
132.1902 +//ko.exportSymbol('virtualElements.nextSibling', ko.virtualElements.nextSibling);   // nextSibling is not minified
132.1903 +ko.exportSymbol('virtualElements.prepend', ko.virtualElements.prepend);
132.1904 +ko.exportSymbol('virtualElements.setDomNodeChildren', ko.virtualElements.setDomNodeChildren);
132.1905 +(function() {
132.1906 +    var defaultBindingAttributeName = "data-bind";
132.1907 +
132.1908 +    ko.bindingProvider = function() {
132.1909 +        this.bindingCache = {};
132.1910 +    };
132.1911 +
132.1912 +    ko.utils.extend(ko.bindingProvider.prototype, {
132.1913 +        'nodeHasBindings': function(node) {
132.1914 +            switch (node.nodeType) {
132.1915 +                case 1: return node.getAttribute(defaultBindingAttributeName) != null;   // Element
132.1916 +                case 8: return ko.virtualElements.virtualNodeBindingValue(node) != null; // Comment node
132.1917 +                default: return false;
132.1918 +            }
132.1919 +        },
132.1920 +
132.1921 +        'getBindings': function(node, bindingContext) {
132.1922 +            var bindingsString = this['getBindingsString'](node, bindingContext);
132.1923 +            return bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node) : null;
132.1924 +        },
132.1925 +
132.1926 +        // The following function is only used internally by this default provider.
132.1927 +        // It's not part of the interface definition for a general binding provider.
132.1928 +        'getBindingsString': function(node, bindingContext) {
132.1929 +            switch (node.nodeType) {
132.1930 +                case 1: return node.getAttribute(defaultBindingAttributeName);   // Element
132.1931 +                case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node
132.1932 +                default: return null;
132.1933 +            }
132.1934 +        },
132.1935 +
132.1936 +        // The following function is only used internally by this default provider.
132.1937 +        // It's not part of the interface definition for a general binding provider.
132.1938 +        'parseBindingsString': function(bindingsString, bindingContext, node) {
132.1939 +            try {
132.1940 +                var bindingFunction = createBindingsStringEvaluatorViaCache(bindingsString, this.bindingCache);
132.1941 +                return bindingFunction(bindingContext, node);
132.1942 +            } catch (ex) {
132.1943 +                throw new Error("Unable to parse bindings.\nMessage: " + ex + ";\nBindings value: " + bindingsString);
132.1944 +            }
132.1945 +        }
132.1946 +    });
132.1947 +
132.1948 +    ko.bindingProvider['instance'] = new ko.bindingProvider();
132.1949 +
132.1950 +    function createBindingsStringEvaluatorViaCache(bindingsString, cache) {
132.1951 +        var cacheKey = bindingsString;
132.1952 +        return cache[cacheKey]
132.1953 +            || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString));
132.1954 +    }
132.1955 +
132.1956 +    function createBindingsStringEvaluator(bindingsString) {
132.1957 +        // Build the source for a function that evaluates "expression"
132.1958 +        // For each scope variable, add an extra level of "with" nesting
132.1959 +        // Example result: with(sc1) { with(sc0) { return (expression) } }
132.1960 +        var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString),
132.1961 +            functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}";
132.1962 +        return new Function("$context", "$element", functionBody);
132.1963 +    }
132.1964 +})();
132.1965 +
132.1966 +ko.exportSymbol('bindingProvider', ko.bindingProvider);
132.1967 +(function () {
132.1968 +    ko.bindingHandlers = {};
132.1969 +
132.1970 +    ko.bindingContext = function(dataItem, parentBindingContext, dataItemAlias) {
132.1971 +        if (parentBindingContext) {
132.1972 +            ko.utils.extend(this, parentBindingContext); // Inherit $root and any custom properties
132.1973 +            this['$parentContext'] = parentBindingContext;
132.1974 +            this['$parent'] = parentBindingContext['$data'];
132.1975 +            this['$parents'] = (parentBindingContext['$parents'] || []).slice(0);
132.1976 +            this['$parents'].unshift(this['$parent']);
132.1977 +        } else {
132.1978 +            this['$parents'] = [];
132.1979 +            this['$root'] = dataItem;
132.1980 +            // Export 'ko' in the binding context so it will be available in bindings and templates
132.1981 +            // even if 'ko' isn't exported as a global, such as when using an AMD loader.
132.1982 +            // See https://github.com/SteveSanderson/knockout/issues/490
132.1983 +            this['ko'] = ko;
132.1984 +        }
132.1985 +        this['$data'] = dataItem;
132.1986 +        if (dataItemAlias)
132.1987 +            this[dataItemAlias] = dataItem;
132.1988 +    }
132.1989 +    ko.bindingContext.prototype['createChildContext'] = function (dataItem, dataItemAlias) {
132.1990 +        return new ko.bindingContext(dataItem, this, dataItemAlias);
132.1991 +    };
132.1992 +    ko.bindingContext.prototype['extend'] = function(properties) {
132.1993 +        var clone = ko.utils.extend(new ko.bindingContext(), this);
132.1994 +        return ko.utils.extend(clone, properties);
132.1995 +    };
132.1996 +
132.1997 +    function validateThatBindingIsAllowedForVirtualElements(bindingName) {
132.1998 +        var validator = ko.virtualElements.allowedBindings[bindingName];
132.1999 +        if (!validator)
132.2000 +            throw new Error("The binding '" + bindingName + "' cannot be used with virtual elements")
132.2001 +    }
132.2002 +
132.2003 +    function applyBindingsToDescendantsInternal (viewModel, elementOrVirtualElement, bindingContextsMayDifferFromDomParentElement) {
132.2004 +        var currentChild, nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);
132.2005 +        while (currentChild = nextInQueue) {
132.2006 +            // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position
132.2007 +            nextInQueue = ko.virtualElements.nextSibling(currentChild);
132.2008 +            applyBindingsToNodeAndDescendantsInternal(viewModel, currentChild, bindingContextsMayDifferFromDomParentElement);
132.2009 +        }
132.2010 +    }
132.2011 +
132.2012 +    function applyBindingsToNodeAndDescendantsInternal (viewModel, nodeVerified, bindingContextMayDifferFromDomParentElement) {
132.2013 +        var shouldBindDescendants = true;
132.2014 +
132.2015 +        // Perf optimisation: Apply bindings only if...
132.2016 +        // (1) We need to store the binding context on this node (because it may differ from the DOM parent node's binding context)
132.2017 +        //     Note that we can't store binding contexts on non-elements (e.g., text nodes), as IE doesn't allow expando properties for those
132.2018 +        // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
132.2019 +        var isElement = (nodeVerified.nodeType === 1);
132.2020 +        if (isElement) // Workaround IE <= 8 HTML parsing weirdness
132.2021 +            ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);
132.2022 +
132.2023 +        var shouldApplyBindings = (isElement && bindingContextMayDifferFromDomParentElement)             // Case (1)
132.2024 +                               || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified);       // Case (2)
132.2025 +        if (shouldApplyBindings)
132.2026 +            shouldBindDescendants = applyBindingsToNodeInternal(nodeVerified, null, viewModel, bindingContextMayDifferFromDomParentElement).shouldBindDescendants;
132.2027 +
132.2028 +        if (shouldBindDescendants) {
132.2029 +            // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,
132.2030 +            //  * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,
132.2031 +            //    hence bindingContextsMayDifferFromDomParentElement is false
132.2032 +            //  * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may
132.2033 +            //    skip over any number of intermediate virtual elements, any of which might define a custom binding context,
132.2034 +            //    hence bindingContextsMayDifferFromDomParentElement is true
132.2035 +            applyBindingsToDescendantsInternal(viewModel, nodeVerified, /* bindingContextsMayDifferFromDomParentElement: */ !isElement);
132.2036 +        }
132.2037 +    }
132.2038 +
132.2039 +    function applyBindingsToNodeInternal (node, bindings, viewModelOrBindingContext, bindingContextMayDifferFromDomParentElement) {
132.2040 +        // Need to be sure that inits are only run once, and updates never run until all the inits have been run
132.2041 +        var initPhase = 0; // 0 = before all inits, 1 = during inits, 2 = after all inits
132.2042 +
132.2043 +        // Each time the dependentObservable is evaluated (after data changes),
132.2044 +        // the binding attribute is reparsed so that it can pick out the correct
132.2045 +        // model properties in the context of the changed data.
132.2046 +        // DOM event callbacks need to be able to access this changed data,
132.2047 +        // so we need a single parsedBindings variable (shared by all callbacks
132.2048 +        // associated with this node's bindings) that all the closures can access.
132.2049 +        var parsedBindings;
132.2050 +        function makeValueAccessor(bindingKey) {
132.2051 +            return function () { return parsedBindings[bindingKey] }
132.2052 +        }
132.2053 +        function parsedBindingsAccessor() {
132.2054 +            return parsedBindings;
132.2055 +        }
132.2056 +
132.2057 +        var bindingHandlerThatControlsDescendantBindings;
132.2058 +        ko.dependentObservable(
132.2059 +            function () {
132.2060 +                // Ensure we have a nonnull binding context to work with
132.2061 +                var bindingContextInstance = viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)
132.2062 +                    ? viewModelOrBindingContext
132.2063 +                    : new ko.bindingContext(ko.utils.unwrapObservable(viewModelOrBindingContext));
132.2064 +                var viewModel = bindingContextInstance['$data'];
132.2065 +
132.2066 +                // Optimization: Don't store the binding context on this node if it's definitely the same as on node.parentNode, because
132.2067 +                // we can easily recover it just by scanning up the node's ancestors in the DOM
132.2068 +                // (note: here, parent node means "real DOM parent" not "virtual parent", as there's no O(1) way to find the virtual parent)
132.2069 +                if (bindingContextMayDifferFromDomParentElement)
132.2070 +                    ko.storedBindingContextForNode(node, bindingContextInstance);
132.2071 +
132.2072 +                // Use evaluatedBindings if given, otherwise fall back on asking the bindings provider to give us some bindings
132.2073 +                var evaluatedBindings = (typeof bindings == "function") ? bindings(bindingContextInstance, node) : bindings;
132.2074 +                parsedBindings = evaluatedBindings || ko.bindingProvider['instance']['getBindings'](node, bindingContextInstance);
132.2075 +
132.2076 +                if (parsedBindings) {
132.2077 +                    // First run all the inits, so bindings can register for notification on changes
132.2078 +                    if (initPhase === 0) {
132.2079 +                        initPhase = 1;
132.2080 +                        for (var bindingKey in parsedBindings) {
132.2081 +                            var binding = ko.bindingHandlers[bindingKey];
132.2082 +                            if (binding && node.nodeType === 8)
132.2083 +                                validateThatBindingIsAllowedForVirtualElements(bindingKey);
132.2084 +
132.2085 +                            if (binding && typeof binding["init"] == "function") {
132.2086 +                                var handlerInitFn = binding["init"];
132.2087 +                                var initResult = handlerInitFn(node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel, bindingContextInstance);
132.2088 +
132.2089 +                                // If this binding handler claims to control descendant bindings, make a note of this
132.2090 +                                if (initResult && initResult['controlsDescendantBindings']) {
132.2091 +                                    if (bindingHandlerThatControlsDescendantBindings !== undefined)
132.2092 +                                        throw new Error("Multiple bindings (" + bindingHandlerThatControlsDescendantBindings + " and " + bindingKey + ") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");
132.2093 +                                    bindingHandlerThatControlsDescendantBindings = bindingKey;
132.2094 +                                }
132.2095 +                            }
132.2096 +                        }
132.2097 +                        initPhase = 2;
132.2098 +                    }
132.2099 +
132.2100 +                    // ... then run all the updates, which might trigger changes even on the first evaluation
132.2101 +                    if (initPhase === 2) {
132.2102 +                        for (var bindingKey in parsedBindings) {
132.2103 +                            var binding = ko.bindingHandlers[bindingKey];
132.2104 +                            if (binding && typeof binding["update"] == "function") {
132.2105 +                                var handlerUpdateFn = binding["update"];
132.2106 +                                handlerUpdateFn(node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel, bindingContextInstance);
132.2107 +                            }
132.2108 +                        }
132.2109 +                    }
132.2110 +                }
132.2111 +            },
132.2112 +            null,
132.2113 +            { disposeWhenNodeIsRemoved : node }
132.2114 +        );
132.2115 +
132.2116 +        return {
132.2117 +            shouldBindDescendants: bindingHandlerThatControlsDescendantBindings === undefined
132.2118 +        };
132.2119 +    };
132.2120 +
132.2121 +    var storedBindingContextDomDataKey = "__ko_bindingContext__";
132.2122 +    ko.storedBindingContextForNode = function (node, bindingContext) {
132.2123 +        if (arguments.length == 2)
132.2124 +            ko.utils.domData.set(node, storedBindingContextDomDataKey, bindingContext);
132.2125 +        else
132.2126 +            return ko.utils.domData.get(node, storedBindingContextDomDataKey);
132.2127 +    }
132.2128 +
132.2129 +    ko.applyBindingsToNode = function (node, bindings, viewModel) {
132.2130 +        if (node.nodeType === 1) // If it's an element, workaround IE <= 8 HTML parsing weirdness
132.2131 +            ko.virtualElements.normaliseVirtualElementDomStructure(node);
132.2132 +        return applyBindingsToNodeInternal(node, bindings, viewModel, true);
132.2133 +    };
132.2134 +
132.2135 +    ko.applyBindingsToDescendants = function(viewModel, rootNode) {
132.2136 +        if (rootNode.nodeType === 1 || rootNode.nodeType === 8)
132.2137 +            applyBindingsToDescendantsInternal(viewModel, rootNode, true);
132.2138 +    };
132.2139 +
132.2140 +    ko.applyBindings = function (viewModel, rootNode) {
132.2141 +        if (rootNode && (rootNode.nodeType !== 1) && (rootNode.nodeType !== 8))
132.2142 +            throw new Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
132.2143 +        rootNode = rootNode || window.document.body; // Make "rootNode" parameter optional
132.2144 +
132.2145 +        applyBindingsToNodeAndDescendantsInternal(viewModel, rootNode, true);
132.2146 +    };
132.2147 +
132.2148 +    // Retrieving binding context from arbitrary nodes
132.2149 +    ko.contextFor = function(node) {
132.2150 +        // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)
132.2151 +        switch (node.nodeType) {
132.2152 +            case 1:
132.2153 +            case 8:
132.2154 +                var context = ko.storedBindingContextForNode(node);
132.2155 +                if (context) return context;
132.2156 +                if (node.parentNode) return ko.contextFor(node.parentNode);
132.2157 +                break;
132.2158 +        }
132.2159 +        return undefined;
132.2160 +    };
132.2161 +    ko.dataFor = function(node) {
132.2162 +        var context = ko.contextFor(node);
132.2163 +        return context ? context['$data'] : undefined;
132.2164 +    };
132.2165 +
132.2166 +    ko.exportSymbol('bindingHandlers', ko.bindingHandlers);
132.2167 +    ko.exportSymbol('applyBindings', ko.applyBindings);
132.2168 +    ko.exportSymbol('applyBindingsToDescendants', ko.applyBindingsToDescendants);
132.2169 +    ko.exportSymbol('applyBindingsToNode', ko.applyBindingsToNode);
132.2170 +    ko.exportSymbol('contextFor', ko.contextFor);
132.2171 +    ko.exportSymbol('dataFor', ko.dataFor);
132.2172 +})();
132.2173 +var attrHtmlToJavascriptMap = { 'class': 'className', 'for': 'htmlFor' };
132.2174 +ko.bindingHandlers['attr'] = {
132.2175 +    'update': function(element, valueAccessor, allBindingsAccessor) {
132.2176 +        var value = ko.utils.unwrapObservable(valueAccessor()) || {};
132.2177 +        for (var attrName in value) {
132.2178 +            if (typeof attrName == "string") {
132.2179 +                var attrValue = ko.utils.unwrapObservable(value[attrName]);
132.2180 +
132.2181 +                // To cover cases like "attr: { checked:someProp }", we want to remove the attribute entirely
132.2182 +                // when someProp is a "no value"-like value (strictly null, false, or undefined)
132.2183 +                // (because the absence of the "checked" attr is how to mark an element as not checked, etc.)
132.2184 +                var toRemove = (attrValue === false) || (attrValue === null) || (attrValue === undefined);
132.2185 +                if (toRemove)
132.2186 +                    element.removeAttribute(attrName);
132.2187 +
132.2188 +                // In IE <= 7 and IE8 Quirks Mode, you have to use the Javascript property name instead of the
132.2189 +                // HTML attribute name for certain attributes. IE8 Standards Mode supports the correct behavior,
132.2190 +                // but instead of figuring out the mode, we'll just set the attribute through the Javascript
132.2191 +                // property for IE <= 8.
132.2192 +                if (ko.utils.ieVersion <= 8 && attrName in attrHtmlToJavascriptMap) {
132.2193 +                    attrName = attrHtmlToJavascriptMap[attrName];
132.2194 +                    if (toRemove)
132.2195 +                        element.removeAttribute(attrName);
132.2196 +                    else
132.2197 +                        element[attrName] = attrValue;
132.2198 +                } else if (!toRemove) {
132.2199 +                    try {
132.2200 +                        element.setAttribute(attrName, attrValue.toString());
132.2201 +                    } catch (err) {
132.2202 +                        // ignore for now
132.2203 +                        if (console) {
132.2204 +                            console.log("Can't set attribute " + attrName + " to " + attrValue + " error: " + err);
132.2205 +                        }
132.2206 +                    }
132.2207 +                }
132.2208 +
132.2209 +                // Treat "name" specially - although you can think of it as an attribute, it also needs
132.2210 +                // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)
132.2211 +                // Deliberately being case-sensitive here because XHTML would regard "Name" as a different thing
132.2212 +                // entirely, and there's no strong reason to allow for such casing in HTML.
132.2213 +                if (attrName === "name") {
132.2214 +                    ko.utils.setElementName(element, toRemove ? "" : attrValue.toString());
132.2215 +                }
132.2216 +            }
132.2217 +        }
132.2218 +    }
132.2219 +};
132.2220 +ko.bindingHandlers['checked'] = {
132.2221 +    'init': function (element, valueAccessor, allBindingsAccessor) {
132.2222 +        var updateHandler = function() {
132.2223 +            var valueToWrite;
132.2224 +            if (element.type == "checkbox") {
132.2225 +                valueToWrite = element.checked;
132.2226 +            } else if ((element.type == "radio") && (element.checked)) {
132.2227 +                valueToWrite = element.value;
132.2228 +            } else {
132.2229 +                return; // "checked" binding only responds to checkboxes and selected radio buttons
132.2230 +            }
132.2231 +
132.2232 +            var modelValue = valueAccessor(), unwrappedValue = ko.utils.unwrapObservable(modelValue);
132.2233 +            if ((element.type == "checkbox") && (unwrappedValue instanceof Array)) {
132.2234 +                // For checkboxes bound to an array, we add/remove the checkbox value to that array
132.2235 +                // This works for both observable and non-observable arrays
132.2236 +                var existingEntryIndex = ko.utils.arrayIndexOf(unwrappedValue, element.value);
132.2237 +                if (element.checked && (existingEntryIndex < 0))
132.2238 +                    modelValue.push(element.value);
132.2239 +                else if ((!element.checked) && (existingEntryIndex >= 0))
132.2240 +                    modelValue.splice(existingEntryIndex, 1);
132.2241 +            } else {
132.2242 +                ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'checked', valueToWrite, true);
132.2243 +            }
132.2244 +        };
132.2245 +        ko.utils.registerEventHandler(element, "click", updateHandler);
132.2246 +
132.2247 +        // IE 6 won't allow radio buttons to be selected unless they have a name
132.2248 +        if ((element.type == "radio") && !element.name)
132.2249 +            ko.bindingHandlers['uniqueName']['init'](element, function() { return true });
132.2250 +    },
132.2251 +    'update': function (element, valueAccessor) {
132.2252 +        var value = ko.utils.unwrapObservable(valueAccessor());
132.2253 +
132.2254 +        if (element.type == "checkbox") {
132.2255 +            if (value instanceof Array) {
132.2256 +                // When bound to an array, the checkbox being checked represents its value being present in that array
132.2257 +                element.checked = ko.utils.arrayIndexOf(value, element.value) >= 0;
132.2258 +            } else {
132.2259 +                // When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
132.2260 +                element.checked = value;
132.2261 +            }
132.2262 +        } else if (element.type == "radio") {
132.2263 +            element.checked = (element.value == value);
132.2264 +        }
132.2265 +    }
132.2266 +};
132.2267 +var classesWrittenByBindingKey = '__ko__cssValue';
132.2268 +ko.bindingHandlers['css'] = {
132.2269 +    'update': function (element, valueAccessor) {
132.2270 +        var value = ko.utils.unwrapObservable(valueAccessor());
132.2271 +        if (typeof value == "object") {
132.2272 +            for (var className in value) {
132.2273 +                var shouldHaveClass = ko.utils.unwrapObservable(value[className]);
132.2274 +                ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
132.2275 +            }
132.2276 +        } else {
132.2277 +            value = String(value || ''); // Make sure we don't try to store or set a non-string value
132.2278 +            ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);
132.2279 +            element[classesWrittenByBindingKey] = value;
132.2280 +            ko.utils.toggleDomNodeCssClass(element, value, true);
132.2281 +        }
132.2282 +    }
132.2283 +};
132.2284 +ko.bindingHandlers['enable'] = {
132.2285 +    'update': function (element, valueAccessor) {
132.2286 +        var value = ko.utils.unwrapObservable(valueAccessor());
132.2287 +        if (value && element.disabled)
132.2288 +            element.removeAttribute("disabled");
132.2289 +        else if ((!value) && (!element.disabled))
132.2290 +            element.disabled = true;
132.2291 +    }
132.2292 +};
132.2293 +
132.2294 +ko.bindingHandlers['disable'] = {
132.2295 +    'update': function (element, valueAccessor) {
132.2296 +        ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });
132.2297 +    }
132.2298 +};
132.2299 +// For certain common events (currently just 'click'), allow a simplified data-binding syntax
132.2300 +// e.g. click:handler instead of the usual full-length event:{click:handler}
132.2301 +function makeEventHandlerShortcut(eventName) {
132.2302 +    ko.bindingHandlers[eventName] = {
132.2303 +        'init': function(element, valueAccessor, allBindingsAccessor, viewModel) {
132.2304 +            var newValueAccessor = function () {
132.2305 +                var result = {};
132.2306 +                result[eventName] = valueAccessor();
132.2307 +                return result;
132.2308 +            };
132.2309 +            return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindingsAccessor, viewModel);
132.2310 +        }
132.2311 +    }
132.2312 +}
132.2313 +
132.2314 +ko.bindingHandlers['event'] = {
132.2315 +    'init' : function (element, valueAccessor, allBindingsAccessor, viewModel) {
132.2316 +        var eventsToHandle = valueAccessor() || {};
132.2317 +        for(var eventNameOutsideClosure in eventsToHandle) {
132.2318 +            (function() {
132.2319 +                var eventName = eventNameOutsideClosure; // Separate variable to be captured by event handler closure
132.2320 +                if (typeof eventName == "string") {
132.2321 +                    ko.utils.registerEventHandler(element, eventName, function (event) {
132.2322 +                        var handlerReturnValue;
132.2323 +                        var handlerFunction = valueAccessor()[eventName];
132.2324 +                        if (!handlerFunction)
132.2325 +                            return;
132.2326 +                        var allBindings = allBindingsAccessor();
132.2327 +
132.2328 +                        try {
132.2329 +                            // Take all the event args, and prefix with the viewmodel
132.2330 +                            var argsForHandler = ko.utils.makeArray(arguments);
132.2331 +                            argsForHandler.unshift(viewModel);
132.2332 +                            handlerReturnValue = handlerFunction.apply(viewModel, argsForHandler);
132.2333 +                        } finally {
132.2334 +                            if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
132.2335 +                                if (event.preventDefault)
132.2336 +                                    event.preventDefault();
132.2337 +                                else
132.2338 +                                    event.returnValue = false;
132.2339 +                            }
132.2340 +                        }
132.2341 +
132.2342 +                        var bubble = allBindings[eventName + 'Bubble'] !== false;
132.2343 +                        if (!bubble) {
132.2344 +                            event.cancelBubble = true;
132.2345 +                            if (event.stopPropagation)
132.2346 +                                event.stopPropagation();
132.2347 +                        }
132.2348 +                    });
132.2349 +                }
132.2350 +            })();
132.2351 +        }
132.2352 +    }
132.2353 +};
132.2354 +// "foreach: someExpression" is equivalent to "template: { foreach: someExpression }"
132.2355 +// "foreach: { data: someExpression, afterAdd: myfn }" is equivalent to "template: { foreach: someExpression, afterAdd: myfn }"
132.2356 +ko.bindingHandlers['foreach'] = {
132.2357 +    makeTemplateValueAccessor: function(valueAccessor) {
132.2358 +        return function() {
132.2359 +            var modelValue = valueAccessor(),
132.2360 +                unwrappedValue = ko.utils.peekObservable(modelValue);    // Unwrap without setting a dependency here
132.2361 +
132.2362 +            // If unwrappedValue is the array, pass in the wrapped value on its own
132.2363 +            // The value will be unwrapped and tracked within the template binding
132.2364 +            // (See https://github.com/SteveSanderson/knockout/issues/523)
132.2365 +            if ((!unwrappedValue) || typeof unwrappedValue.length == "number")
132.2366 +                return { 'foreach': modelValue, 'templateEngine': ko.nativeTemplateEngine.instance };
132.2367 +
132.2368 +            // If unwrappedValue.data is the array, preserve all relevant options and unwrap again value so we get updates
132.2369 +            ko.utils.unwrapObservable(modelValue);
132.2370 +            return {
132.2371 +                'foreach': unwrappedValue['data'],
132.2372 +                'as': unwrappedValue['as'],
132.2373 +                'includeDestroyed': unwrappedValue['includeDestroyed'],
132.2374 +                'afterAdd': unwrappedValue['afterAdd'],
132.2375 +                'beforeRemove': unwrappedValue['beforeRemove'],
132.2376 +                'afterRender': unwrappedValue['afterRender'],
132.2377 +                'beforeMove': unwrappedValue['beforeMove'],
132.2378 +                'afterMove': unwrappedValue['afterMove'],
132.2379 +                'templateEngine': ko.nativeTemplateEngine.instance
132.2380 +            };
132.2381 +        };
132.2382 +    },
132.2383 +    'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
132.2384 +        return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));
132.2385 +    },
132.2386 +    'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
132.2387 +        return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindingsAccessor, viewModel, bindingContext);
132.2388 +    }
132.2389 +};
132.2390 +ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings
132.2391 +ko.virtualElements.allowedBindings['foreach'] = true;
132.2392 +var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';
132.2393 +ko.bindingHandlers['hasfocus'] = {
132.2394 +    'init': function(element, valueAccessor, allBindingsAccessor) {
132.2395 +        var handleElementFocusChange = function(isFocused) {
132.2396 +            // Where possible, ignore which event was raised and determine focus state using activeElement,
132.2397 +            // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.
132.2398 +            // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,
132.2399 +            // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus
132.2400 +            // from calling 'blur()' on the element when it loses focus.
132.2401 +            // Discussion at https://github.com/SteveSanderson/knockout/pull/352
132.2402 +            element[hasfocusUpdatingProperty] = true;
132.2403 +            var ownerDoc = element.ownerDocument;
132.2404 +            if ("activeElement" in ownerDoc) {
132.2405 +                isFocused = (ownerDoc.activeElement === element);
132.2406 +            }
132.2407 +            var modelValue = valueAccessor();
132.2408 +            ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'hasfocus', isFocused, true);
132.2409 +            element[hasfocusUpdatingProperty] = false;
132.2410 +        };
132.2411 +        var handleElementFocusIn = handleElementFocusChange.bind(null, true);
132.2412 +        var handleElementFocusOut = handleElementFocusChange.bind(null, false);
132.2413 +
132.2414 +        ko.utils.registerEventHandler(element, "focus", handleElementFocusIn);
132.2415 +        ko.utils.registerEventHandler(element, "focusin", handleElementFocusIn); // For IE
132.2416 +        ko.utils.registerEventHandler(element, "blur",  handleElementFocusOut);
132.2417 +        ko.utils.registerEventHandler(element, "focusout",  handleElementFocusOut); // For IE
132.2418 +    },
132.2419 +    'update': function(element, valueAccessor) {
132.2420 +        var value = ko.utils.unwrapObservable(valueAccessor());
132.2421 +        if (!element[hasfocusUpdatingProperty]) {
132.2422 +            value ? element.focus() : element.blur();
132.2423 +            ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, value ? "focusin" : "focusout"]); // For IE, which doesn't reliably fire "focus" or "blur" events synchronously
132.2424 +        }
132.2425 +    }
132.2426 +};
132.2427 +ko.bindingHandlers['html'] = {
132.2428 +    'init': function() {
132.2429 +        // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
132.2430 +        return { 'controlsDescendantBindings': true };
132.2431 +    },
132.2432 +    'update': function (element, valueAccessor) {
132.2433 +        // setHtml will unwrap the value if needed
132.2434 +        ko.utils.setHtml(element, valueAccessor());
132.2435 +    }
132.2436 +};
132.2437 +var withIfDomDataKey = '__ko_withIfBindingData';
132.2438 +// Makes a binding like with or if
132.2439 +function makeWithIfBinding(bindingKey, isWith, isNot, makeContextCallback) {
132.2440 +    ko.bindingHandlers[bindingKey] = {
132.2441 +        'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
132.2442 +            ko.utils.domData.set(element, withIfDomDataKey, {});
132.2443 +            return { 'controlsDescendantBindings': true };
132.2444 +        },
132.2445 +        'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
132.2446 +            var withIfData = ko.utils.domData.get(element, withIfDomDataKey),
132.2447 +                dataValue = ko.utils.unwrapObservable(valueAccessor()),
132.2448 +                shouldDisplay = !isNot !== !dataValue, // equivalent to isNot ? !dataValue : !!dataValue
132.2449 +                isFirstRender = !withIfData.savedNodes,
132.2450 +                needsRefresh = isFirstRender || isWith || (shouldDisplay !== withIfData.didDisplayOnLastUpdate);
132.2451 +
132.2452 +            if (needsRefresh) {
132.2453 +                if (isFirstRender) {
132.2454 +                    withIfData.savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);
132.2455 +                }
132.2456 +
132.2457 +                if (shouldDisplay) {
132.2458 +                    if (!isFirstRender) {
132.2459 +                        ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(withIfData.savedNodes));
132.2460 +                    }
132.2461 +                    ko.applyBindingsToDescendants(makeContextCallback ? makeContextCallback(bindingContext, dataValue) : bindingContext, element);
132.2462 +                } else {
132.2463 +                    ko.virtualElements.emptyNode(element);
132.2464 +                }
132.2465 +
132.2466 +                withIfData.didDisplayOnLastUpdate = shouldDisplay;
132.2467 +            }
132.2468 +        }
132.2469 +    };
132.2470 +    ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings
132.2471 +    ko.virtualElements.allowedBindings[bindingKey] = true;
132.2472 +}
132.2473 +
132.2474 +// Construct the actual binding handlers
132.2475 +makeWithIfBinding('if');
132.2476 +makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);
132.2477 +makeWithIfBinding('with', true /* isWith */, false /* isNot */,
132.2478 +    function(bindingContext, dataValue) {
132.2479 +        return bindingContext['createChildContext'](dataValue);
132.2480 +    }
132.2481 +);
132.2482 +function ensureDropdownSelectionIsConsistentWithModelValue(element, modelValue, preferModelValue) {
132.2483 +    if (preferModelValue) {
132.2484 +        if (modelValue !== ko.selectExtensions.readValue(element))
132.2485 +            ko.selectExtensions.writeValue(element, modelValue);
132.2486 +    }
132.2487 +
132.2488 +    // No matter which direction we're syncing in, we want the end result to be equality between dropdown value and model value.
132.2489 +    // If they aren't equal, either we prefer the dropdown value, or the model value couldn't be represented, so either way,
132.2490 +    // change the model value to match the dropdown.
132.2491 +    if (modelValue !== ko.selectExtensions.readValue(element))
132.2492 +        ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
132.2493 +};
132.2494 +
132.2495 +ko.bindingHandlers['options'] = {
132.2496 +    'update': function (element, valueAccessor, allBindingsAccessor) {
132.2497 +        if (ko.utils.tagNameLower(element) !== "select")
132.2498 +            throw new Error("options binding applies only to SELECT elements");
132.2499 +
132.2500 +        var selectWasPreviouslyEmpty = element.length == 0;
132.2501 +        var previousSelectedValues = ko.utils.arrayMap(ko.utils.arrayFilter(element.childNodes, function (node) {
132.2502 +            return node.tagName && (ko.utils.tagNameLower(node) === "option") && node.selected;
132.2503 +        }), function (node) {
132.2504 +            return ko.selectExtensions.readValue(node) || node.innerText || node.textContent;
132.2505 +        });
132.2506 +        var previousScrollTop = element.scrollTop;
132.2507 +
132.2508 +        var value = ko.utils.unwrapObservable(valueAccessor());
132.2509 +        var selectedValue = element.value;
132.2510 +
132.2511 +        // Remove all existing <option>s.
132.2512 +        // Need to use .remove() rather than .removeChild() for <option>s otherwise IE behaves oddly (https://github.com/SteveSanderson/knockout/issues/134)
132.2513 +        while (element.length > 0) {
132.2514 +            ko.cleanNode(element.options[0]);
132.2515 +            element.remove(0);
132.2516 +        }
132.2517 +
132.2518 +        if (value) {
132.2519 +            var allBindings = allBindingsAccessor(),
132.2520 +                includeDestroyed = allBindings['optionsIncludeDestroyed'];
132.2521 +
132.2522 +            if (typeof value.length != "number")
132.2523 +                value = [value];
132.2524 +            if (allBindings['optionsCaption']) {
132.2525 +                var option = document.createElement("option");
132.2526 +                ko.utils.setHtml(option, allBindings['optionsCaption']);
132.2527 +                ko.selectExtensions.writeValue(option, undefined);
132.2528 +                element.appendChild(option);
132.2529 +            }
132.2530 +
132.2531 +            for (var i = 0, j = value.length; i < j; i++) {
132.2532 +                // Skip destroyed items
132.2533 +                var arrayEntry = value[i];
132.2534 +                if (arrayEntry && arrayEntry['_destroy'] && !includeDestroyed)
132.2535 +                    continue;
132.2536 +
132.2537 +                var option = document.createElement("option");
132.2538 +
132.2539 +                function applyToObject(object, predicate, defaultValue) {
132.2540 +                    var predicateType = typeof predicate;
132.2541 +                    if (predicateType == "function")    // Given a function; run it against the data value
132.2542 +                        return predicate(object);
132.2543 +                    else if (predicateType == "string") // Given a string; treat it as a property name on the data value
132.2544 +                        return object[predicate];
132.2545 +                    else                                // Given no optionsText arg; use the data value itself
132.2546 +                        return defaultValue;
132.2547 +                }
132.2548 +
132.2549 +                // Apply a value to the option element
132.2550 +                var optionValue = applyToObject(arrayEntry, allBindings['optionsValue'], arrayEntry);
132.2551 +                ko.selectExtensions.writeValue(option, ko.utils.unwrapObservable(optionValue));
132.2552 +
132.2553 +                // Apply some text to the option element
132.2554 +                var optionText = applyToObject(arrayEntry, allBindings['optionsText'], optionValue);
132.2555 +                ko.utils.setTextContent(option, optionText);
132.2556 +
132.2557 +                element.appendChild(option);
132.2558 +            }
132.2559 +
132.2560 +            // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
132.2561 +            // That's why we first added them without selection. Now it's time to set the selection.
132.2562 +            var newOptions = element.getElementsByTagName("option");
132.2563 +            var countSelectionsRetained = 0;
132.2564 +            for (var i = 0, j = newOptions.length; i < j; i++) {
132.2565 +                if (ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[i])) >= 0) {
132.2566 +                    ko.utils.setOptionNodeSelectionState(newOptions[i], true);
132.2567 +                    countSelectionsRetained++;
132.2568 +                }
132.2569 +            }
132.2570 +
132.2571 +            element.scrollTop = previousScrollTop;
132.2572 +
132.2573 +            if (selectWasPreviouslyEmpty && ('value' in allBindings)) {
132.2574 +                // Ensure consistency between model value and selected option.
132.2575 +                // If the dropdown is being populated for the first time here (or was otherwise previously empty),
132.2576 +                // the dropdown selection state is meaningless, so we preserve the model value.
132.2577 +                ensureDropdownSelectionIsConsistentWithModelValue(element, ko.utils.peekObservable(allBindings['value']), /* preferModelValue */ true);
132.2578 +            }
132.2579 +
132.2580 +            // Workaround for IE9 bug
132.2581 +            ko.utils.ensureSelectElementIsRenderedCorrectly(element);
132.2582 +        }
132.2583 +    }
132.2584 +};
132.2585 +ko.bindingHandlers['options'].optionValueDomDataKey = '__ko.optionValueDomData__';
132.2586 +ko.bindingHandlers['selectedOptions'] = {
132.2587 +    'init': function (element, valueAccessor, allBindingsAccessor) {
132.2588 +        ko.utils.registerEventHandler(element, "change", function () {
132.2589 +            var value = valueAccessor(), valueToWrite = [];
132.2590 +            ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
132.2591 +                if (node.selected)
132.2592 +                    valueToWrite.push(ko.selectExtensions.readValue(node));
132.2593 +            });
132.2594 +            ko.expressionRewriting.writeValueToProperty(value, allBindingsAccessor, 'value', valueToWrite);
132.2595 +        });
132.2596 +    },
132.2597 +    'update': function (element, valueAccessor) {
132.2598 +        if (ko.utils.tagNameLower(element) != "select")
132.2599 +            throw new Error("values binding applies only to SELECT elements");
132.2600 +
132.2601 +        var newValue = ko.utils.unwrapObservable(valueAccessor());
132.2602 +        if (newValue && typeof newValue.length == "number") {
132.2603 +            ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
132.2604 +                var isSelected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;
132.2605 +                ko.utils.setOptionNodeSelectionState(node, isSelected);
132.2606 +            });
132.2607 +        }
132.2608 +    }
132.2609 +};
132.2610 +ko.bindingHandlers['style'] = {
132.2611 +    'update': function (element, valueAccessor) {
132.2612 +        var value = ko.utils.unwrapObservable(valueAccessor() || {});
132.2613 +        for (var styleName in value) {
132.2614 +            if (typeof styleName == "string") {
132.2615 +                var styleValue = ko.utils.unwrapObservable(value[styleName]);
132.2616 +                element.style[styleName] = styleValue || ""; // Empty string removes the value, whereas null/undefined have no effect
132.2617 +            }
132.2618 +        }
132.2619 +    }
132.2620 +};
132.2621 +ko.bindingHandlers['submit'] = {
132.2622 +    'init': function (element, valueAccessor, allBindingsAccessor, viewModel) {
132.2623 +        if (typeof valueAccessor() != "function")
132.2624 +            throw new Error("The value for a submit binding must be a function");
132.2625 +        ko.utils.registerEventHandler(element, "submit", function (event) {
132.2626 +            var handlerReturnValue;
132.2627 +            var value = valueAccessor();
132.2628 +            try { handlerReturnValue = value.call(viewModel, element); }
132.2629 +            finally {
132.2630 +                if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
132.2631 +                    if (event.preventDefault)
132.2632 +                        event.preventDefault();
132.2633 +                    else
132.2634 +                        event.returnValue = false;
132.2635 +                }
132.2636 +            }
132.2637 +        });
132.2638 +    }
132.2639 +};
132.2640 +ko.bindingHandlers['text'] = {
132.2641 +    'update': function (element, valueAccessor) {
132.2642 +        ko.utils.setTextContent(element, valueAccessor());
132.2643 +    }
132.2644 +};
132.2645 +ko.virtualElements.allowedBindings['text'] = true;
132.2646 +ko.bindingHandlers['uniqueName'] = {
132.2647 +    'init': function (element, valueAccessor) {
132.2648 +        if (valueAccessor()) {
132.2649 +            var name = "ko_unique_" + (++ko.bindingHandlers['uniqueName'].currentIndex);
132.2650 +            ko.utils.setElementName(element, name);
132.2651 +        }
132.2652 +    }
132.2653 +};
132.2654 +ko.bindingHandlers['uniqueName'].currentIndex = 0;
132.2655 +ko.bindingHandlers['value'] = {
132.2656 +    'init': function (element, valueAccessor, allBindingsAccessor) {
132.2657 +        // Always catch "change" event; possibly other events too if asked
132.2658 +        var eventsToCatch = ["change"];
132.2659 +        var requestedEventsToCatch = allBindingsAccessor()["valueUpdate"];
132.2660 +        var propertyChangedFired = false;
132.2661 +        if (requestedEventsToCatch) {
132.2662 +            if (typeof requestedEventsToCatch == "string") // Allow both individual event names, and arrays of event names
132.2663 +                requestedEventsToCatch = [requestedEventsToCatch];
132.2664 +            ko.utils.arrayPushAll(eventsToCatch, requestedEventsToCatch);
132.2665 +            eventsToCatch = ko.utils.arrayGetDistinctValues(eventsToCatch);
132.2666 +        }
132.2667 +
132.2668 +        var valueUpdateHandler = function() {
132.2669 +            propertyChangedFired = false;
132.2670 +            var modelValue = valueAccessor();
132.2671 +            var elementValue = ko.selectExtensions.readValue(element);
132.2672 +            ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'value', elementValue);
132.2673 +        }
132.2674 +
132.2675 +        // Workaround for https://github.com/SteveSanderson/knockout/issues/122
132.2676 +        // IE doesn't fire "change" events on textboxes if the user selects a value from its autocomplete list
132.2677 +        var ieAutoCompleteHackNeeded = ko.utils.ieVersion && element.tagName.toLowerCase() == "input" && element.type == "text"
132.2678 +                                       && element.autocomplete != "off" && (!element.form || element.form.autocomplete != "off");
132.2679 +        if (ieAutoCompleteHackNeeded && ko.utils.arrayIndexOf(eventsToCatch, "propertychange") == -1) {
132.2680 +            ko.utils.registerEventHandler(element, "propertychange", function () { propertyChangedFired = true });
132.2681 +            ko.utils.registerEventHandler(element, "blur", function() {
132.2682 +                if (propertyChangedFired) {
132.2683 +                    valueUpdateHandler();
132.2684 +                }
132.2685 +            });
132.2686 +        }
132.2687 +
132.2688 +        ko.utils.arrayForEach(eventsToCatch, function(eventName) {
132.2689 +            // The syntax "after<eventname>" means "run the handler asynchronously after the event"
132.2690 +            // This is useful, for example, to catch "keydown" events after the browser has updated the control
132.2691 +            // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)
132.2692 +            var handler = valueUpdateHandler;
132.2693 +            if (ko.utils.stringStartsWith(eventName, "after")) {
132.2694 +                handler = function() { setTimeout(valueUpdateHandler, 0) };
132.2695 +                eventName = eventName.substring("after".length);
132.2696 +            }
132.2697 +            ko.utils.registerEventHandler(element, eventName, handler);
132.2698 +        });
132.2699 +    },
132.2700 +    'update': function (element, valueAccessor) {
132.2701 +        var valueIsSelectOption = ko.utils.tagNameLower(element) === "select";
132.2702 +        var newValue = ko.utils.unwrapObservable(valueAccessor());
132.2703 +        var elementValue = ko.selectExtensions.readValue(element);
132.2704 +        var valueHasChanged = (newValue != elementValue);
132.2705 +
132.2706 +        // JavaScript's 0 == "" behavious is unfortunate here as it prevents writing 0 to an empty text box (loose equality suggests the values are the same).
132.2707 +        // We don't want to do a strict equality comparison as that is more confusing for developers in certain cases, so we specifically special case 0 != "" here.
132.2708 +        if ((newValue === 0) && (elementValue !== 0) && (elementValue !== "0"))
132.2709 +            valueHasChanged = true;
132.2710 +
132.2711 +        if (valueHasChanged) {
132.2712 +            var applyValueAction = function () { ko.selectExtensions.writeValue(element, newValue); };
132.2713 +            applyValueAction();
132.2714 +
132.2715 +            // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread
132.2716 +            // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread
132.2717 +            // to apply the value as well.
132.2718 +            var alsoApplyAsynchronously = valueIsSelectOption;
132.2719 +            if (alsoApplyAsynchronously)
132.2720 +                setTimeout(applyValueAction, 0);
132.2721 +        }
132.2722 +
132.2723 +        // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,
132.2724 +        // because you're not allowed to have a model value that disagrees with a visible UI selection.
132.2725 +        if (valueIsSelectOption && (element.length > 0))
132.2726 +            ensureDropdownSelectionIsConsistentWithModelValue(element, newValue, /* preferModelValue */ false);
132.2727 +    }
132.2728 +};
132.2729 +ko.bindingHandlers['visible'] = {
132.2730 +    'update': function (element, valueAccessor) {
132.2731 +        var value = ko.utils.unwrapObservable(valueAccessor());
132.2732 +        var isCurrentlyVisible = !(element.style.display == "none");
132.2733 +        if (value && !isCurrentlyVisible)
132.2734 +            element.style.display = "";
132.2735 +        else if ((!value) && isCurrentlyVisible)
132.2736 +            element.style.display = "none";
132.2737 +    }
132.2738 +};
132.2739 +// 'click' is just a shorthand for the usual full-length event:{click:handler}
132.2740 +makeEventHandlerShortcut('click');
132.2741 +// If you want to make a custom template engine,
132.2742 +//
132.2743 +// [1] Inherit from this class (like ko.nativeTemplateEngine does)
132.2744 +// [2] Override 'renderTemplateSource', supplying a function with this signature:
132.2745 +//
132.2746 +//        function (templateSource, bindingContext, options) {
132.2747 +//            // - templateSource.text() is the text of the template you should render
132.2748 +//            // - bindingContext.$data is the data you should pass into the template
132.2749 +//            //   - you might also want to make bindingContext.$parent, bindingContext.$parents,
132.2750 +//            //     and bindingContext.$root available in the template too
132.2751 +//            // - options gives you access to any other properties set on "data-bind: { template: options }"
132.2752 +//            //
132.2753 +//            // Return value: an array of DOM nodes
132.2754 +//        }
132.2755 +//
132.2756 +// [3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:
132.2757 +//
132.2758 +//        function (script) {
132.2759 +//            // Return value: Whatever syntax means "Evaluate the JavaScript statement 'script' and output the result"
132.2760 +//            //               For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'
132.2761 +//        }
132.2762 +//
132.2763 +//     This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.
132.2764 +//     If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)
132.2765 +//     and then you don't need to override 'createJavaScriptEvaluatorBlock'.
132.2766 +
132.2767 +ko.templateEngine = function () { };
132.2768 +
132.2769 +ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
132.2770 +    throw new Error("Override renderTemplateSource");
132.2771 +};
132.2772 +
132.2773 +ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {
132.2774 +    throw new Error("Override createJavaScriptEvaluatorBlock");
132.2775 +};
132.2776 +
132.2777 +ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {
132.2778 +    // Named template
132.2779 +    if (typeof template == "string") {
132.2780 +        templateDocument = templateDocument || document;
132.2781 +        var elem = templateDocument.getElementById(template);
132.2782 +        if (!elem)
132.2783 +            throw new Error("Cannot find template with ID " + template);
132.2784 +        return new ko.templateSources.domElement(elem);
132.2785 +    } else if ((template.nodeType == 1) || (template.nodeType == 8)) {
132.2786 +        // Anonymous template
132.2787 +        return new ko.templateSources.anonymousTemplate(template);
132.2788 +    } else
132.2789 +        throw new Error("Unknown template type: " + template);
132.2790 +};
132.2791 +
132.2792 +ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {
132.2793 +    var templateSource = this['makeTemplateSource'](template, templateDocument);
132.2794 +    return this['renderTemplateSource'](templateSource, bindingContext, options);
132.2795 +};
132.2796 +
132.2797 +ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {
132.2798 +    // Skip rewriting if requested
132.2799 +    if (this['allowTemplateRewriting'] === false)
132.2800 +        return true;
132.2801 +    return this['makeTemplateSource'](template, templateDocument)['data']("isRewritten");
132.2802 +};
132.2803 +
132.2804 +ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCallback, templateDocument) {
132.2805 +    var templateSource = this['makeTemplateSource'](template, templateDocument);
132.2806 +    var rewritten = rewriterCallback(templateSource['text']());
132.2807 +    templateSource['text'](rewritten);
132.2808 +    templateSource['data']("isRewritten", true);
132.2809 +};
132.2810 +
132.2811 +ko.exportSymbol('templateEngine', ko.templateEngine);
132.2812 +
132.2813 +ko.templateRewriting = (function () {
132.2814 +    var memoizeDataBindingAttributeSyntaxRegex = /(<[a-z]+\d*(\s+(?!data-bind=)[a-z0-9\-]+(=(\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind=(["'])([\s\S]*?)\5/gi;
132.2815 +    var memoizeVirtualContainerBindingSyntaxRegex = /<!--\s*ko\b\s*([\s\S]*?)\s*-->/g;
132.2816 +
132.2817 +    function validateDataBindValuesForRewriting(keyValueArray) {
132.2818 +        var allValidators = ko.expressionRewriting.bindingRewriteValidators;
132.2819 +        for (var i = 0; i < keyValueArray.length; i++) {
132.2820 +            var key = keyValueArray[i]['key'];
132.2821 +            if (allValidators.hasOwnProperty(key)) {
132.2822 +                var validator = allValidators[key];
132.2823 +
132.2824 +                if (typeof validator === "function") {
132.2825 +                    var possibleErrorMessage = validator(keyValueArray[i]['value']);
132.2826 +                    if (possibleErrorMessage)
132.2827 +                        throw new Error(possibleErrorMessage);
132.2828 +                } else if (!validator) {
132.2829 +                    throw new Error("This template engine does not support the '" + key + "' binding within its templates");
132.2830 +                }
132.2831 +            }
132.2832 +        }
132.2833 +    }
132.2834 +
132.2835 +    function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, templateEngine) {
132.2836 +        var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);
132.2837 +        validateDataBindValuesForRewriting(dataBindKeyValueArray);
132.2838 +        var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray);
132.2839 +
132.2840 +        // For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional
132.2841 +        // anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this
132.2842 +        // extra indirection.
132.2843 +        var applyBindingsToNextSiblingScript =
132.2844 +            "ko.__tr_ambtns(function($context,$element){return(function(){return{ " + rewrittenDataBindAttributeValue + " } })()})";
132.2845 +        return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;
132.2846 +    }
132.2847 +
132.2848 +    return {
132.2849 +        ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {
132.2850 +            if (!templateEngine['isTemplateRewritten'](template, templateDocument))
132.2851 +                templateEngine['rewriteTemplate'](template, function (htmlString) {
132.2852 +                    return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);
132.2853 +                }, templateDocument);
132.2854 +        },
132.2855 +
132.2856 +        memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {
132.2857 +            return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {
132.2858 +                return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[6], /* tagToRetain: */ arguments[1], templateEngine);
132.2859 +            }).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {
132.2860 +                return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ "<!-- ko -->", templateEngine);
132.2861 +            });
132.2862 +        },
132.2863 +
132.2864 +        applyMemoizedBindingsToNextSibling: function (bindings) {
132.2865 +            return ko.memoization.memoize(function (domNode, bindingContext) {
132.2866 +                if (domNode.nextSibling)
132.2867 +                    ko.applyBindingsToNode(domNode.nextSibling, bindings, bindingContext);
132.2868 +            });
132.2869 +        }
132.2870 +    }
132.2871 +})();
132.2872 +
132.2873 +
132.2874 +// Exported only because it has to be referenced by string lookup from within rewritten template
132.2875 +ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);
132.2876 +(function() {
132.2877 +    // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving
132.2878 +    // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)
132.2879 +    //
132.2880 +    // Two are provided by default:
132.2881 +    //  1. ko.templateSources.domElement       - reads/writes the text content of an arbitrary DOM element
132.2882 +    //  2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but
132.2883 +    //                                           without reading/writing the actual element text content, since it will be overwritten
132.2884 +    //                                           with the rendered template output.
132.2885 +    // You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.
132.2886 +    // Template sources need to have the following functions:
132.2887 +    //   text() 			- returns the template text from your storage location
132.2888 +    //   text(value)		- writes the supplied template text to your storage location
132.2889 +    //   data(key)			- reads values stored using data(key, value) - see below
132.2890 +    //   data(key, value)	- associates "value" with this template and the key "key". Is used to store information like "isRewritten".
132.2891 +    //
132.2892 +    // Optionally, template sources can also have the following functions:
132.2893 +    //   nodes()            - returns a DOM element containing the nodes of this template, where available
132.2894 +    //   nodes(value)       - writes the given DOM element to your storage location
132.2895 +    // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()
132.2896 +    // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().
132.2897 +    //
132.2898 +    // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were
132.2899 +    // using and overriding "makeTemplateSource" to return an instance of your custom template source.
132.2900 +
132.2901 +    ko.templateSources = {};
132.2902 +
132.2903 +    // ---- ko.templateSources.domElement -----
132.2904 +
132.2905 +    ko.templateSources.domElement = function(element) {
132.2906 +        this.domElement = element;
132.2907 +    }
132.2908 +
132.2909 +    ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {
132.2910 +        var tagNameLower = ko.utils.tagNameLower(this.domElement),
132.2911 +            elemContentsProperty = tagNameLower === "script" ? "text"
132.2912 +                                 : tagNameLower === "textarea" ? "value"
132.2913 +                                 : "innerHTML";
132.2914 +
132.2915 +        if (arguments.length == 0) {
132.2916 +            return this.domElement[elemContentsProperty];
132.2917 +        } else {
132.2918 +            var valueToWrite = arguments[0];
132.2919 +            if (elemContentsProperty === "innerHTML")
132.2920 +                ko.utils.setHtml(this.domElement, valueToWrite);
132.2921 +            else
132.2922 +                this.domElement[elemContentsProperty] = valueToWrite;
132.2923 +        }
132.2924 +    };
132.2925 +
132.2926 +    ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {
132.2927 +        if (arguments.length === 1) {
132.2928 +            return ko.utils.domData.get(this.domElement, "templateSourceData_" + key);
132.2929 +        } else {
132.2930 +            ko.utils.domData.set(this.domElement, "templateSourceData_" + key, arguments[1]);
132.2931 +        }
132.2932 +    };
132.2933 +
132.2934 +    // ---- ko.templateSources.anonymousTemplate -----
132.2935 +    // Anonymous templates are normally saved/retrieved as DOM nodes through "nodes".
132.2936 +    // For compatibility, you can also read "text"; it will be serialized from the nodes on demand.
132.2937 +    // Writing to "text" is still supported, but then the template data will not be available as DOM nodes.
132.2938 +
132.2939 +    var anonymousTemplatesDomDataKey = "__ko_anon_template__";
132.2940 +    ko.templateSources.anonymousTemplate = function(element) {
132.2941 +        this.domElement = element;
132.2942 +    }
132.2943 +    ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();
132.2944 +    ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {
132.2945 +        if (arguments.length == 0) {
132.2946 +            var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
132.2947 +            if (templateData.textData === undefined && templateData.containerData)
132.2948 +                templateData.textData = templateData.containerData.innerHTML;
132.2949 +            return templateData.textData;
132.2950 +        } else {
132.2951 +            var valueToWrite = arguments[0];
132.2952 +            ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {textData: valueToWrite});
132.2953 +        }
132.2954 +    };
132.2955 +    ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {
132.2956 +        if (arguments.length == 0) {
132.2957 +            var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
132.2958 +            return templateData.containerData;
132.2959 +        } else {
132.2960 +            var valueToWrite = arguments[0];
132.2961 +            ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {containerData: valueToWrite});
132.2962 +        }
132.2963 +    };
132.2964 +
132.2965 +    ko.exportSymbol('templateSources', ko.templateSources);
132.2966 +    ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);
132.2967 +    ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);
132.2968 +})();
132.2969 +(function () {
132.2970 +    var _templateEngine;
132.2971 +    ko.setTemplateEngine = function (templateEngine) {
132.2972 +        if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))
132.2973 +            throw new Error("templateEngine must inherit from ko.templateEngine");
132.2974 +        _templateEngine = templateEngine;
132.2975 +    }
132.2976 +
132.2977 +    function invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, action) {
132.2978 +        var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);
132.2979 +        while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {
132.2980 +            nextInQueue = ko.virtualElements.nextSibling(node);
132.2981 +            if (node.nodeType === 1 || node.nodeType === 8)
132.2982 +                action(node);
132.2983 +        }
132.2984 +    }
132.2985 +
132.2986 +    function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext) {
132.2987 +        // To be used on any nodes that have been rendered by a template and have been inserted into some parent element
132.2988 +        // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because
132.2989 +        // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,
132.2990 +        // (1) Does a regular "applyBindings" to associate bindingContext with this node and to activate any non-memoized bindings
132.2991 +        // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)
132.2992 +
132.2993 +        if (continuousNodeArray.length) {
132.2994 +            var firstNode = continuousNodeArray[0], lastNode = continuousNodeArray[continuousNodeArray.length - 1];
132.2995 +
132.2996 +            // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)
132.2997 +            // whereas a regular applyBindings won't introduce new memoized nodes
132.2998 +            invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, function(node) {
132.2999 +                ko.applyBindings(bindingContext, node);
132.3000 +            });
132.3001 +            invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, function(node) {
132.3002 +                ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);
132.3003 +            });
132.3004 +        }
132.3005 +    }
132.3006 +
132.3007 +    function getFirstNodeFromPossibleArray(nodeOrNodeArray) {
132.3008 +        return nodeOrNodeArray.nodeType ? nodeOrNodeArray
132.3009 +                                        : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]
132.3010 +                                        : null;
132.3011 +    }
132.3012 +
132.3013 +    function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {
132.3014 +        options = options || {};
132.3015 +        var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
132.3016 +        var templateDocument = firstTargetNode && firstTargetNode.ownerDocument;
132.3017 +        var templateEngineToUse = (options['templateEngine'] || _templateEngine);
132.3018 +        ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);
132.3019 +        var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);
132.3020 +
132.3021 +        // Loosely check result is an array of DOM nodes
132.3022 +        if ((typeof renderedNodesArray.length != "number") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != "number"))
132.3023 +            throw new Error("Template engine must return an array of DOM nodes");
132.3024 +
132.3025 +        var haveAddedNodesToParent = false;
132.3026 +        switch (renderMode) {
132.3027 +            case "replaceChildren":
132.3028 +                ko.virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);
132.3029 +                haveAddedNodesToParent = true;
132.3030 +                break;
132.3031 +            case "replaceNode":
132.3032 +                ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray);
132.3033 +                haveAddedNodesToParent = true;
132.3034 +                break;
132.3035 +            case "ignoreTargetNode": break;
132.3036 +            default:
132.3037 +                throw new Error("Unknown renderMode: " + renderMode);
132.3038 +        }
132.3039 +
132.3040 +        if (haveAddedNodesToParent) {
132.3041 +            activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);
132.3042 +            if (options['afterRender'])
132.3043 +                ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext['$data']]);
132.3044 +        }
132.3045 +
132.3046 +        return renderedNodesArray;
132.3047 +    }
132.3048 +
132.3049 +    ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {
132.3050 +        options = options || {};
132.3051 +        if ((options['templateEngine'] || _templateEngine) == undefined)
132.3052 +            throw new Error("Set a template engine before calling renderTemplate");
132.3053 +        renderMode = renderMode || "replaceChildren";
132.3054 +
132.3055 +        if (targetNodeOrNodeArray) {
132.3056 +            var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
132.3057 +
132.3058 +            var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)
132.3059 +            var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == "replaceNode") ? firstTargetNode.parentNode : firstTargetNode;
132.3060 +
132.3061 +            return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes
132.3062 +                function () {
132.3063 +                    // Ensure we've got a proper binding context to work with
132.3064 +                    var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))
132.3065 +                        ? dataOrBindingContext
132.3066 +                        : new ko.bindingContext(ko.utils.unwrapObservable(dataOrBindingContext));
132.3067 +
132.3068 +                    // Support selecting template as a function of the data being rendered
132.3069 +                    var templateName = typeof(template) == 'function' ? template(bindingContext['$data'], bindingContext) : template;
132.3070 +
132.3071 +                    var renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);
132.3072 +                    if (renderMode == "replaceNode") {
132.3073 +                        targetNodeOrNodeArray = renderedNodesArray;
132.3074 +                        firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
132.3075 +                    }
132.3076 +                },
132.3077 +                null,
132.3078 +                { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }
132.3079 +            );
132.3080 +        } else {
132.3081 +            // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node
132.3082 +            return ko.memoization.memoize(function (domNode) {
132.3083 +                ko.renderTemplate(template, dataOrBindingContext, options, domNode, "replaceNode");
132.3084 +            });
132.3085 +        }
132.3086 +    };
132.3087 +
132.3088 +    ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {
132.3089 +        // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then
132.3090 +        // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.
132.3091 +        var arrayItemContext;
132.3092 +
132.3093 +        // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode
132.3094 +        var executeTemplateForArrayItem = function (arrayValue, index) {
132.3095 +            // Support selecting template as a function of the data being rendered
132.3096 +            arrayItemContext = parentBindingContext['createChildContext'](ko.utils.unwrapObservable(arrayValue), options['as']);
132.3097 +            arrayItemContext['$index'] = index;
132.3098 +            var templateName = typeof(template) == 'function' ? template(arrayValue, arrayItemContext) : template;
132.3099 +            return executeTemplate(null, "ignoreTargetNode", templateName, arrayItemContext, options);
132.3100 +        }
132.3101 +
132.3102 +        // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode
132.3103 +        var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {
132.3104 +            activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);
132.3105 +            if (options['afterRender'])
132.3106 +                options['afterRender'](addedNodesArray, arrayValue);
132.3107 +        };
132.3108 +
132.3109 +        return ko.dependentObservable(function () {
132.3110 +            var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];
132.3111 +            if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
132.3112 +                unwrappedArray = [unwrappedArray];
132.3113 +
132.3114 +            // Filter out any entries marked as destroyed
132.3115 +            var filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
132.3116 +                return options['includeDestroyed'] || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
132.3117 +            });
132.3118 +
132.3119 +            // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).
132.3120 +            // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.
132.3121 +            ko.dependencyDetection.ignore(ko.utils.setDomNodeChildrenFromArrayMapping, null, [targetNode, filteredArray, executeTemplateForArrayItem, options, activateBindingsCallback]);
132.3122 +
132.3123 +        }, null, { disposeWhenNodeIsRemoved: targetNode });
132.3124 +    };
132.3125 +
132.3126 +    var templateComputedDomDataKey = '__ko__templateComputedDomDataKey__';
132.3127 +    function disposeOldComputedAndStoreNewOne(element, newComputed) {
132.3128 +        var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);
132.3129 +        if (oldComputed && (typeof(oldComputed.dispose) == 'function'))
132.3130 +            oldComputed.dispose();
132.3131 +        ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && newComputed.isActive()) ? newComputed : undefined);
132.3132 +    }
132.3133 +
132.3134 +    ko.bindingHandlers['template'] = {
132.3135 +        'init': function(element, valueAccessor) {
132.3136 +            // Support anonymous templates
132.3137 +            var bindingValue = ko.utils.unwrapObservable(valueAccessor());
132.3138 +            if ((typeof bindingValue != "string") && (!bindingValue['name']) && (element.nodeType == 1 || element.nodeType == 8)) {
132.3139 +                // It's an anonymous template - store the element contents, then clear the element
132.3140 +                var templateNodes = element.nodeType == 1 ? element.childNodes : ko.virtualElements.childNodes(element),
132.3141 +                    container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent
132.3142 +                new ko.templateSources.anonymousTemplate(element)['nodes'](container);
132.3143 +            }
132.3144 +            return { 'controlsDescendantBindings': true };
132.3145 +        },
132.3146 +        'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
132.3147 +            var templateName = ko.utils.unwrapObservable(valueAccessor()),
132.3148 +                options = {},
132.3149 +                shouldDisplay = true,
132.3150 +                dataValue,
132.3151 +                templateComputed = null;
132.3152 +
132.3153 +            if (typeof templateName != "string") {
132.3154 +                options = templateName;
132.3155 +                templateName = options['name'];
132.3156 +
132.3157 +                // Support "if"/"ifnot" conditions
132.3158 +                if ('if' in options)
132.3159 +                    shouldDisplay = ko.utils.unwrapObservable(options['if']);
132.3160 +                if (shouldDisplay && 'ifnot' in options)
132.3161 +                    shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);
132.3162 +
132.3163 +                dataValue = ko.utils.unwrapObservable(options['data']);
132.3164 +            }
132.3165 +
132.3166 +            if ('foreach' in options) {
132.3167 +                // Render once for each data point (treating data set as empty if shouldDisplay==false)
132.3168 +                var dataArray = (shouldDisplay && options['foreach']) || [];
132.3169 +                templateComputed = ko.renderTemplateForEach(templateName || element, dataArray, options, element, bindingContext);
132.3170 +            } else if (!shouldDisplay) {
132.3171 +                ko.virtualElements.emptyNode(element);
132.3172 +            } else {
132.3173 +                // Render once for this single data point (or use the viewModel if no data was provided)
132.3174 +                var innerBindingContext = ('data' in options) ?
132.3175 +                    bindingContext['createChildContext'](dataValue, options['as']) :  // Given an explitit 'data' value, we create a child binding context for it
132.3176 +                    bindingContext;                                                        // Given no explicit 'data' value, we retain the same binding context
132.3177 +                templateComputed = ko.renderTemplate(templateName || element, innerBindingContext, options, element);
132.3178 +            }
132.3179 +
132.3180 +            // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)
132.3181 +            disposeOldComputedAndStoreNewOne(element, templateComputed);
132.3182 +        }
132.3183 +    };
132.3184 +
132.3185 +    // Anonymous templates can't be rewritten. Give a nice error message if you try to do it.
132.3186 +    ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {
132.3187 +        var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);
132.3188 +
132.3189 +        if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])
132.3190 +            return null; // It looks like a string literal, not an object literal, so treat it as a named template (which is allowed for rewriting)
132.3191 +
132.3192 +        if (ko.expressionRewriting.keyValueArrayContainsKey(parsedBindingValue, "name"))
132.3193 +            return null; // Named templates can be rewritten, so return "no error"
132.3194 +        return "This template engine does not support anonymous templates nested within its templates";
132.3195 +    };
132.3196 +
132.3197 +    ko.virtualElements.allowedBindings['template'] = true;
132.3198 +})();
132.3199 +
132.3200 +ko.exportSymbol('setTemplateEngine', ko.setTemplateEngine);
132.3201 +ko.exportSymbol('renderTemplate', ko.renderTemplate);
132.3202 +
132.3203 +ko.utils.compareArrays = (function () {
132.3204 +    var statusNotInOld = 'added', statusNotInNew = 'deleted';
132.3205 +
132.3206 +    // Simple calculation based on Levenshtein distance.
132.3207 +    function compareArrays(oldArray, newArray, dontLimitMoves) {
132.3208 +        oldArray = oldArray || [];
132.3209 +        newArray = newArray || [];
132.3210 +
132.3211 +        if (oldArray.length <= newArray.length)
132.3212 +            return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, dontLimitMoves);
132.3213 +        else
132.3214 +            return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, dontLimitMoves);
132.3215 +    }
132.3216 +
132.3217 +    function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, dontLimitMoves) {
132.3218 +        var myMin = Math.min,
132.3219 +            myMax = Math.max,
132.3220 +            editDistanceMatrix = [],
132.3221 +            smlIndex, smlIndexMax = smlArray.length,
132.3222 +            bigIndex, bigIndexMax = bigArray.length,
132.3223 +            compareRange = (bigIndexMax - smlIndexMax) || 1,
132.3224 +            maxDistance = smlIndexMax + bigIndexMax + 1,
132.3225 +            thisRow, lastRow,
132.3226 +            bigIndexMaxForRow, bigIndexMinForRow;
132.3227 +
132.3228 +        for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {
132.3229 +            lastRow = thisRow;
132.3230 +            editDistanceMatrix.push(thisRow = []);
132.3231 +            bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);
132.3232 +            bigIndexMinForRow = myMax(0, smlIndex - 1);
132.3233 +            for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) {
132.3234 +                if (!bigIndex)
132.3235 +                    thisRow[bigIndex] = smlIndex + 1;
132.3236 +                else if (!smlIndex)  // Top row - transform empty array into new array via additions
132.3237 +                    thisRow[bigIndex] = bigIndex + 1;
132.3238 +                else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])
132.3239 +                    thisRow[bigIndex] = lastRow[bigIndex - 1];                  // copy value (no edit)
132.3240 +                else {
132.3241 +                    var northDistance = lastRow[bigIndex] || maxDistance;       // not in big (deletion)
132.3242 +                    var westDistance = thisRow[bigIndex - 1] || maxDistance;    // not in small (addition)
132.3243 +                    thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;
132.3244 +                }
132.3245 +            }
132.3246 +        }
132.3247 +
132.3248 +        var editScript = [], meMinusOne, notInSml = [], notInBig = [];
132.3249 +        for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {
132.3250 +            meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;
132.3251 +            if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {
132.3252 +                notInSml.push(editScript[editScript.length] = {     // added
132.3253 +                    'status': statusNotInSml,
132.3254 +                    'value': bigArray[--bigIndex],
132.3255 +                    'index': bigIndex });
132.3256 +            } else if (smlIndex && meMinusOne === editDistanceMatrix[smlIndex - 1][bigIndex]) {
132.3257 +                notInBig.push(editScript[editScript.length] = {     // deleted
132.3258 +                    'status': statusNotInBig,
132.3259 +                    'value': smlArray[--smlIndex],
132.3260 +                    'index': smlIndex });
132.3261 +            } else {
132.3262 +                editScript.push({
132.3263 +                    'status': "retained",
132.3264 +                    'value': bigArray[--bigIndex] });
132.3265 +                --smlIndex;
132.3266 +            }
132.3267 +        }
132.3268 +
132.3269 +        if (notInSml.length && notInBig.length) {
132.3270 +            // Set a limit on the number of consecutive non-matching comparisons; having it a multiple of
132.3271 +            // smlIndexMax keeps the time complexity of this algorithm linear.
132.3272 +            var limitFailedCompares = smlIndexMax * 10, failedCompares,
132.3273 +                a, d, notInSmlItem, notInBigItem;
132.3274 +            // Go through the items that have been added and deleted and try to find matches between them.
132.3275 +            for (failedCompares = a = 0; (dontLimitMoves || failedCompares < limitFailedCompares) && (notInSmlItem = notInSml[a]); a++) {
132.3276 +                for (d = 0; notInBigItem = notInBig[d]; d++) {
132.3277 +                    if (notInSmlItem['value'] === notInBigItem['value']) {
132.3278 +                        notInSmlItem['moved'] = notInBigItem['index'];
132.3279 +                        notInBigItem['moved'] = notInSmlItem['index'];
132.3280 +                        notInBig.splice(d,1);       // This item is marked as moved; so remove it from notInBig list
132.3281 +                        failedCompares = d = 0;     // Reset failed compares count because we're checking for consecutive failures
132.3282 +                        break;
132.3283 +                    }
132.3284 +                }
132.3285 +                failedCompares += d;
132.3286 +            }
132.3287 +        }
132.3288 +        return editScript.reverse();
132.3289 +    }
132.3290 +
132.3291 +    return compareArrays;
132.3292 +})();
132.3293 +
132.3294 +ko.exportSymbol('utils.compareArrays', ko.utils.compareArrays);
132.3295 +
132.3296 +(function () {
132.3297 +    // Objective:
132.3298 +    // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,
132.3299 +    //   map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node
132.3300 +    // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node
132.3301 +    //   so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we
132.3302 +    //   previously mapped - retain those nodes, and just insert/delete other ones
132.3303 +
132.3304 +    // "callbackAfterAddingNodes" will be invoked after any "mapping"-generated nodes are inserted into the container node
132.3305 +    // You can use this, for example, to activate bindings on those nodes.
132.3306 +
132.3307 +    function fixUpNodesToBeMovedOrRemoved(contiguousNodeArray) {
132.3308 +        // Before moving, deleting, or replacing a set of nodes that were previously outputted by the "map" function, we have to reconcile
132.3309 +        // them against what is in the DOM right now. It may be that some of the nodes have already been removed from the document,
132.3310 +        // or that new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been
132.3311 +        // leading comment nodes (created by rewritten string-based templates) that have since been removed during binding.
132.3312 +        // So, this function translates the old "map" output array into its best guess of what set of current DOM nodes should be removed.
132.3313 +        //
132.3314 +        // Rules:
132.3315 +        //   [A] Any leading nodes that aren't in the document any more should be ignored
132.3316 +        //       These most likely correspond to memoization nodes that were already removed during binding
132.3317 +        //       See https://github.com/SteveSanderson/knockout/pull/440
132.3318 +        //   [B] We want to output a contiguous series of nodes that are still in the document. So, ignore any nodes that
132.3319 +        //       have already been removed, and include any nodes that have been inserted among the previous collection
132.3320 +
132.3321 +        // Rule [A]
132.3322 +        while (contiguousNodeArray.length && !ko.utils.domNodeIsAttachedToDocument(contiguousNodeArray[0]))
132.3323 +            contiguousNodeArray.splice(0, 1);
132.3324 +
132.3325 +        // Rule [B]
132.3326 +        if (contiguousNodeArray.length > 1) {
132.3327 +            // Build up the actual new contiguous node set
132.3328 +            var current = contiguousNodeArray[0], last = contiguousNodeArray[contiguousNodeArray.length - 1], newContiguousSet = [current];
132.3329 +            while (current !== last) {
132.3330 +                current = current.nextSibling;
132.3331 +                if (!current) // Won't happen, except if the developer has manually removed some DOM elements (then we're in an undefined scenario)
132.3332 +                    return;
132.3333 +                newContiguousSet.push(current);
132.3334 +            }
132.3335 +
132.3336 +            // ... then mutate the input array to match this.
132.3337 +            // (The following line replaces the contents of contiguousNodeArray with newContiguousSet)
132.3338 +            Array.prototype.splice.apply(contiguousNodeArray, [0, contiguousNodeArray.length].concat(newContiguousSet));
132.3339 +        }
132.3340 +        return contiguousNodeArray;
132.3341 +    }
132.3342 +
132.3343 +    function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
132.3344 +        // Map this array value inside a dependentObservable so we re-map when any dependency changes
132.3345 +        var mappedNodes = [];
132.3346 +        var dependentObservable = ko.dependentObservable(function() {
132.3347 +            var newMappedNodes = mapping(valueToMap, index) || [];
132.3348 +
132.3349 +            // On subsequent evaluations, just replace the previously-inserted DOM nodes
132.3350 +            if (mappedNodes.length > 0) {
132.3351 +                ko.utils.replaceDomNodes(fixUpNodesToBeMovedOrRemoved(mappedNodes), newMappedNodes);
132.3352 +                if (callbackAfterAddingNodes)
132.3353 +                    ko.dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);
132.3354 +            }
132.3355 +
132.3356 +            // Replace the contents of the mappedNodes array, thereby updating the record
132.3357 +            // of which nodes would be deleted if valueToMap was itself later removed
132.3358 +            mappedNodes.splice(0, mappedNodes.length);
132.3359 +            ko.utils.arrayPushAll(mappedNodes, newMappedNodes);
132.3360 +        }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return (mappedNodes.length == 0) || !ko.utils.domNodeIsAttachedToDocument(mappedNodes[0]) } });
132.3361 +        return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };
132.3362 +    }
132.3363 +
132.3364 +    var lastMappingResultDomDataKey = "setDomNodeChildrenFromArrayMapping_lastMappingResult";
132.3365 +
132.3366 +    ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes) {
132.3367 +        // Compare the provided array against the previous one
132.3368 +        array = array || [];
132.3369 +        options = options || {};
132.3370 +        var isFirstExecution = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) === undefined;
132.3371 +        var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) || [];
132.3372 +        var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; });
132.3373 +        var editScript = ko.utils.compareArrays(lastArray, array);
132.3374 +
132.3375 +        // Build the new mapping result
132.3376 +        var newMappingResult = [];
132.3377 +        var lastMappingResultIndex = 0;
132.3378 +        var newMappingResultIndex = 0;
132.3379 +
132.3380 +        var nodesToDelete = [];
132.3381 +        var itemsToProcess = [];
132.3382 +        var itemsForBeforeRemoveCallbacks = [];
132.3383 +        var itemsForMoveCallbacks = [];
132.3384 +        var itemsForAfterAddCallbacks = [];
132.3385 +        var mapData;
132.3386 +
132.3387 +        function itemMovedOrRetained(editScriptIndex, oldPosition) {
132.3388 +            mapData = lastMappingResult[oldPosition];
132.3389 +            if (newMappingResultIndex !== oldPosition)
132.3390 +                itemsForMoveCallbacks[editScriptIndex] = mapData;
132.3391 +            // Since updating the index might change the nodes, do so before calling fixUpNodesToBeMovedOrRemoved
132.3392 +            mapData.indexObservable(newMappingResultIndex++);
132.3393 +            fixUpNodesToBeMovedOrRemoved(mapData.mappedNodes);
132.3394 +            newMappingResult.push(mapData);
132.3395 +            itemsToProcess.push(mapData);
132.3396 +        }
132.3397 +
132.3398 +        function callCallback(callback, items) {
132.3399 +            if (callback) {
132.3400 +                for (var i = 0, n = items.length; i < n; i++) {
132.3401 +                    if (items[i]) {
132.3402 +                        ko.utils.arrayForEach(items[i].mappedNodes, function(node) {
132.3403 +                            callback(node, i, items[i].arrayEntry);
132.3404 +                        });
132.3405 +                    }
132.3406 +                }
132.3407 +            }
132.3408 +        }
132.3409 +
132.3410 +        for (var i = 0, editScriptItem, movedIndex; editScriptItem = editScript[i]; i++) {
132.3411 +            movedIndex = editScriptItem['moved'];
132.3412 +            switch (editScriptItem['status']) {
132.3413 +                case "deleted":
132.3414 +                    if (movedIndex === undefined) {
132.3415 +                        mapData = lastMappingResult[lastMappingResultIndex];
132.3416 +
132.3417 +                        // Stop tracking changes to the mapping for these nodes
132.3418 +                        if (mapData.dependentObservable)
132.3419 +                            mapData.dependentObservable.dispose();
132.3420 +
132.3421 +                        // Queue these nodes for later removal
132.3422 +                        nodesToDelete.push.apply(nodesToDelete, fixUpNodesToBeMovedOrRemoved(mapData.mappedNodes));
132.3423 +                        if (options['beforeRemove']) {
132.3424 +                            itemsForBeforeRemoveCallbacks[i] = mapData;
132.3425 +                            itemsToProcess.push(mapData);
132.3426 +                        }
132.3427 +                    }
132.3428 +                    lastMappingResultIndex++;
132.3429 +                    break;
132.3430 +
132.3431 +                case "retained":
132.3432 +                    itemMovedOrRetained(i, lastMappingResultIndex++);
132.3433 +                    break;
132.3434 +
132.3435 +                case "added":
132.3436 +                    if (movedIndex !== undefined) {
132.3437 +                        itemMovedOrRetained(i, movedIndex);
132.3438 +                    } else {
132.3439 +                        mapData = { arrayEntry: editScriptItem['value'], indexObservable: ko.observable(newMappingResultIndex++) };
132.3440 +                        newMappingResult.push(mapData);
132.3441 +                        itemsToProcess.push(mapData);
132.3442 +                        if (!isFirstExecution)
132.3443 +                            itemsForAfterAddCallbacks[i] = mapData;
132.3444 +                    }
132.3445 +                    break;
132.3446 +            }
132.3447 +        }
132.3448 +
132.3449 +        // Call beforeMove first before any changes have been made to the DOM
132.3450 +        callCallback(options['beforeMove'], itemsForMoveCallbacks);
132.3451 +
132.3452 +        // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)
132.3453 +        ko.utils.arrayForEach(nodesToDelete, options['beforeRemove'] ? ko.cleanNode : ko.removeNode);
132.3454 +
132.3455 +        // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)
132.3456 +        for (var i = 0, nextNode = ko.virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[i]; i++) {
132.3457 +            // Get nodes for newly added items
132.3458 +            if (!mapData.mappedNodes)
132.3459 +                ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));
132.3460 +
132.3461 +            // Put nodes in the right place if they aren't there already
132.3462 +            for (var j = 0; node = mapData.mappedNodes[j]; nextNode = node.nextSibling, lastNode = node, j++) {
132.3463 +                if (node !== nextNode)
132.3464 +                    ko.virtualElements.insertAfter(domNode, node, lastNode);
132.3465 +            }
132.3466 +
132.3467 +            // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)
132.3468 +            if (!mapData.initialized && callbackAfterAddingNodes) {
132.3469 +                callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);
132.3470 +                mapData.initialized = true;
132.3471 +            }
132.3472 +        }
132.3473 +
132.3474 +        // If there's a beforeRemove callback, call it after reordering.
132.3475 +        // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using
132.3476 +        // some sort of animation, which is why we first reorder the nodes that will be removed. If the
132.3477 +        // callback instead removes the nodes right away, it would be more efficient to skip reordering them.
132.3478 +        // Perhaps we'll make that change in the future if this scenario becomes more common.
132.3479 +        callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks);
132.3480 +
132.3481 +        // Finally call afterMove and afterAdd callbacks
132.3482 +        callCallback(options['afterMove'], itemsForMoveCallbacks);
132.3483 +        callCallback(options['afterAdd'], itemsForAfterAddCallbacks);
132.3484 +
132.3485 +        // Store a copy of the array items we just considered so we can difference it next time
132.3486 +        ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);
132.3487 +    }
132.3488 +})();
132.3489 +
132.3490 +ko.exportSymbol('utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);
132.3491 +ko.nativeTemplateEngine = function () {
132.3492 +    this['allowTemplateRewriting'] = false;
132.3493 +}
132.3494 +
132.3495 +ko.nativeTemplateEngine.prototype = new ko.templateEngine();
132.3496 +ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
132.3497 +    var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly
132.3498 +        templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,
132.3499 +        templateNodes = templateNodesFunc ? templateSource['nodes']() : null;
132.3500 +
132.3501 +    if (templateNodes) {
132.3502 +        return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);
132.3503 +    } else {
132.3504 +        var templateText = templateSource['text']();
132.3505 +        return ko.utils.parseHtmlFragment(templateText);
132.3506 +    }
132.3507 +};
132.3508 +
132.3509 +ko.nativeTemplateEngine.instance = new ko.nativeTemplateEngine();
132.3510 +ko.setTemplateEngine(ko.nativeTemplateEngine.instance);
132.3511 +
132.3512 +ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);
132.3513 +(function() {
132.3514 +    ko.jqueryTmplTemplateEngine = function () {
132.3515 +        // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl
132.3516 +        // doesn't expose a version number, so we have to infer it.
132.3517 +        // Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,
132.3518 +        // which KO internally refers to as version "2", so older versions are no longer detected.
132.3519 +        var jQueryTmplVersion = this.jQueryTmplVersion = (function() {
132.3520 +            if ((typeof(jQuery) == "undefined") || !(jQuery['tmpl']))
132.3521 +                return 0;
132.3522 +            // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.
132.3523 +            try {
132.3524 +                if (jQuery['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {
132.3525 +                    // Since 1.0.0pre, custom tags should append markup to an array called "__"
132.3526 +                    return 2; // Final version of jquery.tmpl
132.3527 +                }
132.3528 +            } catch(ex) { /* Apparently not the version we were looking for */ }
132.3529 +
132.3530 +            return 1; // Any older version that we don't support
132.3531 +        })();
132.3532 +
132.3533 +        function ensureHasReferencedJQueryTemplates() {
132.3534 +            if (jQueryTmplVersion < 2)
132.3535 +                throw new Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");
132.3536 +        }
132.3537 +
132.3538 +        function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {
132.3539 +            return jQuery['tmpl'](compiledTemplate, data, jQueryTemplateOptions);
132.3540 +        }
132.3541 +
132.3542 +        this['renderTemplateSource'] = function(templateSource, bindingContext, options) {
132.3543 +            options = options || {};
132.3544 +            ensureHasReferencedJQueryTemplates();
132.3545 +
132.3546 +            // Ensure we have stored a precompiled version of this template (don't want to reparse on every render)
132.3547 +            var precompiled = templateSource['data']('precompiled');
132.3548 +            if (!precompiled) {
132.3549 +                var templateText = templateSource['text']() || "";
132.3550 +                // Wrap in "with($whatever.koBindingContext) { ... }"
132.3551 +                templateText = "{{ko_with $item.koBindingContext}}" + templateText + "{{/ko_with}}";
132.3552 +
132.3553 +                precompiled = jQuery['template'](null, templateText);
132.3554 +                templateSource['data']('precompiled', precompiled);
132.3555 +            }
132.3556 +
132.3557 +            var data = [bindingContext['$data']]; // Prewrap the data in an array to stop jquery.tmpl from trying to unwrap any arrays
132.3558 +            var jQueryTemplateOptions = jQuery['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);
132.3559 +
132.3560 +            var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);
132.3561 +            resultNodes['appendTo'](document.createElement("div")); // Using "appendTo" forces jQuery/jQuery.tmpl to perform necessary cleanup work
132.3562 +
132.3563 +            jQuery['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders
132.3564 +            return resultNodes;
132.3565 +        };
132.3566 +
132.3567 +        this['createJavaScriptEvaluatorBlock'] = function(script) {
132.3568 +            return "{{ko_code ((function() { return " + script + " })()) }}";
132.3569 +        };
132.3570 +
132.3571 +        this['addTemplate'] = function(templateName, templateMarkup) {
132.3572 +            document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "</script>");
132.3573 +        };
132.3574 +
132.3575 +        if (jQueryTmplVersion > 0) {
132.3576 +            jQuery['tmpl']['tag']['ko_code'] = {
132.3577 +                open: "__.push($1 || '');"
132.3578 +            };
132.3579 +            jQuery['tmpl']['tag']['ko_with'] = {
132.3580 +                open: "with($1) {",
132.3581 +                close: "} "
132.3582 +            };
132.3583 +        }
132.3584 +    };
132.3585 +
132.3586 +    ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();
132.3587 +
132.3588 +    // Use this one by default *only if jquery.tmpl is referenced*
132.3589 +    var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine();
132.3590 +    if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0)
132.3591 +        ko.setTemplateEngine(jqueryTmplTemplateEngineInstance);
132.3592 +
132.3593 +    ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);
132.3594 +})();
132.3595 +});
132.3596 +})(window,document,navigator,window["jQuery"]);
132.3597 +})();
132.3598 \ No newline at end of file
   133.1 --- a/ko-fx/src/test/java/org/apidesign/html/kofx/DynamicHTTP.java	Mon Dec 16 15:48:09 2013 +0100
   133.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   133.3 @@ -1,259 +0,0 @@
   133.4 -/**
   133.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   133.6 - *
   133.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   133.8 - *
   133.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  133.10 - * Other names may be trademarks of their respective owners.
  133.11 - *
  133.12 - * The contents of this file are subject to the terms of either the GNU
  133.13 - * General Public License Version 2 only ("GPL") or the Common
  133.14 - * Development and Distribution License("CDDL") (collectively, the
  133.15 - * "License"). You may not use this file except in compliance with the
  133.16 - * License. You can obtain a copy of the License at
  133.17 - * http://www.netbeans.org/cddl-gplv2.html
  133.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  133.19 - * specific language governing permissions and limitations under the
  133.20 - * License.  When distributing the software, include this License Header
  133.21 - * Notice in each file and include the License file at
  133.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  133.23 - * particular file as subject to the "Classpath" exception as provided
  133.24 - * by Oracle in the GPL Version 2 section of the License file that
  133.25 - * accompanied this code. If applicable, add the following below the
  133.26 - * License Header, with the fields enclosed by brackets [] replaced by
  133.27 - * your own identifying information:
  133.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  133.29 - *
  133.30 - * Contributor(s):
  133.31 - *
  133.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  133.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  133.34 - *
  133.35 - * If you wish your version of this file to be governed by only the CDDL
  133.36 - * or only the GPL Version 2, indicate your decision by adding
  133.37 - * "[Contributor] elects to include this software in this distribution
  133.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  133.39 - * single choice of license, a recipient has the option to distribute
  133.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  133.41 - * to extend the choice of license to its licensees as provided above.
  133.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  133.43 - * Version 2 license, then the option applies only if the new code is
  133.44 - * made subject to such option by the copyright holder.
  133.45 - */
  133.46 -package org.apidesign.html.kofx;
  133.47 -
  133.48 -import java.io.ByteArrayInputStream;
  133.49 -import java.io.ByteArrayOutputStream;
  133.50 -import java.io.IOException;
  133.51 -import java.io.InputStream;
  133.52 -import java.io.OutputStream;
  133.53 -import java.io.Reader;
  133.54 -import java.net.URI;
  133.55 -import java.net.URISyntaxException;
  133.56 -import java.util.ArrayList;
  133.57 -import java.util.List;
  133.58 -import java.util.logging.Level;
  133.59 -import java.util.logging.Logger;
  133.60 -import org.glassfish.grizzly.PortRange;
  133.61 -import org.glassfish.grizzly.http.server.HttpHandler;
  133.62 -import org.glassfish.grizzly.http.server.HttpServer;
  133.63 -import org.glassfish.grizzly.http.server.NetworkListener;
  133.64 -import org.glassfish.grizzly.http.server.Request;
  133.65 -import org.glassfish.grizzly.http.server.Response;
  133.66 -import org.glassfish.grizzly.http.server.ServerConfiguration;
  133.67 -import org.glassfish.grizzly.websockets.WebSocket;
  133.68 -import org.glassfish.grizzly.websockets.WebSocketAddOn;
  133.69 -import org.glassfish.grizzly.websockets.WebSocketApplication;
  133.70 -import org.glassfish.grizzly.websockets.WebSocketEngine;
  133.71 -
  133.72 -/**
  133.73 - *
  133.74 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  133.75 - */
  133.76 -final class DynamicHTTP extends HttpHandler {
  133.77 -    private static final Logger LOG = Logger.getLogger(DynamicHTTP.class.getName());
  133.78 -    private static int resourcesCount;
  133.79 -    private static List<Resource> resources;
  133.80 -    private static ServerConfiguration conf;
  133.81 -    private static HttpServer server;
  133.82 -    
  133.83 -    private DynamicHTTP() {
  133.84 -    }
  133.85 -    
  133.86 -    static URI initServer() throws Exception {
  133.87 -        server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
  133.88 -        final WebSocketAddOn addon = new WebSocketAddOn();
  133.89 -        for (NetworkListener listener : server.getListeners()) {
  133.90 -            listener.registerAddOn(addon);
  133.91 -        }        
  133.92 -        resources = new ArrayList<Resource>();
  133.93 -
  133.94 -        conf = server.getServerConfiguration();
  133.95 -        final DynamicHTTP dh = new DynamicHTTP();
  133.96 -
  133.97 -        conf.addHttpHandler(dh, "/");
  133.98 -        
  133.99 -        server.start();
 133.100 -
 133.101 -        return pageURL("http", server, "/test.html");
 133.102 -    }
 133.103 -    
 133.104 -    @Override
 133.105 -    public void service(Request request, Response response) throws Exception {
 133.106 -        if ("/test.html".equals(request.getRequestURI())) {
 133.107 -            response.setContentType("text/html");
 133.108 -            final InputStream is = DynamicHTTP.class.getResourceAsStream("test.html");
 133.109 -            copyStream(is, response.getOutputStream(), null);
 133.110 -            return;
 133.111 -        }
 133.112 -        if ("/dynamic".equals(request.getRequestURI())) {
 133.113 -            String mimeType = request.getParameter("mimeType");
 133.114 -            List<String> params = new ArrayList<String>();
 133.115 -            boolean webSocket = false;
 133.116 -            for (int i = 0;; i++) {
 133.117 -                String p = request.getParameter("param" + i);
 133.118 -                if (p == null) {
 133.119 -                    break;
 133.120 -                }
 133.121 -                if ("protocol:ws".equals(p)) {
 133.122 -                    webSocket = true;
 133.123 -                    continue;
 133.124 -                }
 133.125 -                params.add(p);
 133.126 -            }
 133.127 -            final String cnt = request.getParameter("content");
 133.128 -            String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
 133.129 -            ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
 133.130 -            URI url;
 133.131 -            final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
 133.132 -            if (webSocket) {
 133.133 -                url = registerWebSocket(res);
 133.134 -            } else {
 133.135 -                url = registerResource(res);
 133.136 -            }
 133.137 -            response.getWriter().write(url.toString());
 133.138 -            response.getWriter().write("\n");
 133.139 -            return;
 133.140 -        }
 133.141 -
 133.142 -        for (Resource r : resources) {
 133.143 -            if (r.httpPath.equals(request.getRequestURI())) {
 133.144 -                response.setContentType(r.httpType);
 133.145 -                r.httpContent.reset();
 133.146 -                String[] params = null;
 133.147 -                if (r.parameters.length != 0) {
 133.148 -                    params = new String[r.parameters.length];
 133.149 -                    for (int i = 0; i < r.parameters.length; i++) {
 133.150 -                        params[i] = request.getParameter(r.parameters[i]);
 133.151 -                        if (params[i] == null) {
 133.152 -                            if ("http.method".equals(r.parameters[i])) {
 133.153 -                                params[i] = request.getMethod().toString();
 133.154 -                            } else if ("http.requestBody".equals(r.parameters[i])) {
 133.155 -                                Reader rdr = request.getReader();
 133.156 -                                StringBuilder sb = new StringBuilder();
 133.157 -                                for (;;) {
 133.158 -                                    int ch = rdr.read();
 133.159 -                                    if (ch == -1) {
 133.160 -                                        break;
 133.161 -                                    }
 133.162 -                                    sb.append((char) ch);
 133.163 -                                }
 133.164 -                                params[i] = sb.toString();
 133.165 -                            }
 133.166 -                        }
 133.167 -                        if (params[i] == null) {
 133.168 -                            params[i] = "null";
 133.169 -                        }
 133.170 -                    }
 133.171 -                }
 133.172 -
 133.173 -                copyStream(r.httpContent, response.getOutputStream(), null, params);
 133.174 -            }
 133.175 -        }
 133.176 -    }
 133.177 -    
 133.178 -    private URI registerWebSocket(Resource r) {
 133.179 -        WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
 133.180 -        return pageURL("ws", server, r.httpPath);
 133.181 -    }
 133.182 -
 133.183 -    private URI registerResource(Resource r) {
 133.184 -        if (!resources.contains(r)) {
 133.185 -            resources.add(r);
 133.186 -            conf.addHttpHandler(this, r.httpPath);
 133.187 -        }
 133.188 -        return pageURL("http", server, r.httpPath);
 133.189 -    }
 133.190 -    
 133.191 -    private static URI pageURL(String proto, HttpServer server, final String page) {
 133.192 -        NetworkListener listener = server.getListeners().iterator().next();
 133.193 -        int port = listener.getPort();
 133.194 -        try {
 133.195 -            return new URI(proto + "://localhost:" + port + page);
 133.196 -        } catch (URISyntaxException ex) {
 133.197 -            throw new IllegalStateException(ex);
 133.198 -        }
 133.199 -    }
 133.200 -    
 133.201 -    static final class Resource {
 133.202 -
 133.203 -        final InputStream httpContent;
 133.204 -        final String httpType;
 133.205 -        final String httpPath;
 133.206 -        final String[] parameters;
 133.207 -
 133.208 -        Resource(InputStream httpContent, String httpType, String httpPath,
 133.209 -            String[] parameters) {
 133.210 -            httpContent.mark(Integer.MAX_VALUE);
 133.211 -            this.httpContent = httpContent;
 133.212 -            this.httpType = httpType;
 133.213 -            this.httpPath = httpPath;
 133.214 -            this.parameters = parameters;
 133.215 -        }
 133.216 -    }
 133.217 -
 133.218 -    static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
 133.219 -        for (;;) {
 133.220 -            int ch = is.read();
 133.221 -            if (ch == -1) {
 133.222 -                break;
 133.223 -            }
 133.224 -            if (ch == '$' && params.length > 0) {
 133.225 -                int cnt = is.read() - '0';
 133.226 -                if (baseURL != null && cnt == 'U' - '0') {
 133.227 -                    os.write(baseURL.getBytes("UTF-8"));
 133.228 -                } else {
 133.229 -                    if (cnt >= 0 && cnt < params.length) {
 133.230 -                        os.write(params[cnt].getBytes("UTF-8"));
 133.231 -                    } else {
 133.232 -                        os.write('$');
 133.233 -                        os.write(cnt + '0');
 133.234 -                    }
 133.235 -                }
 133.236 -            } else {
 133.237 -                os.write(ch);
 133.238 -            }
 133.239 -        }
 133.240 -    }
 133.241 -    
 133.242 -    private static class WS extends WebSocketApplication {
 133.243 -        private final Resource r;
 133.244 -
 133.245 -        private WS(Resource r) {
 133.246 -            this.r = r;
 133.247 -        }
 133.248 -
 133.249 -        @Override
 133.250 -        public void onMessage(WebSocket socket, String text) {
 133.251 -            try {
 133.252 -                r.httpContent.reset();
 133.253 -                ByteArrayOutputStream out = new ByteArrayOutputStream();
 133.254 -                copyStream(r.httpContent, out, null, text);
 133.255 -                String s = new String(out.toByteArray(), "UTF-8");
 133.256 -                socket.send(s);
 133.257 -            } catch (IOException ex) {
 133.258 -                LOG.log(Level.WARNING, "Error processing message " + text, ex);
 133.259 -            }
 133.260 -        }
 133.261 -    }
 133.262 -}
   134.1 --- a/ko-fx/src/test/java/org/apidesign/html/kofx/KOFx.java	Mon Dec 16 15:48:09 2013 +0100
   134.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   134.3 @@ -1,118 +0,0 @@
   134.4 -/**
   134.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   134.6 - *
   134.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   134.8 - *
   134.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  134.10 - * Other names may be trademarks of their respective owners.
  134.11 - *
  134.12 - * The contents of this file are subject to the terms of either the GNU
  134.13 - * General Public License Version 2 only ("GPL") or the Common
  134.14 - * Development and Distribution License("CDDL") (collectively, the
  134.15 - * "License"). You may not use this file except in compliance with the
  134.16 - * License. You can obtain a copy of the License at
  134.17 - * http://www.netbeans.org/cddl-gplv2.html
  134.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  134.19 - * specific language governing permissions and limitations under the
  134.20 - * License.  When distributing the software, include this License Header
  134.21 - * Notice in each file and include the License file at
  134.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  134.23 - * particular file as subject to the "Classpath" exception as provided
  134.24 - * by Oracle in the GPL Version 2 section of the License file that
  134.25 - * accompanied this code. If applicable, add the following below the
  134.26 - * License Header, with the fields enclosed by brackets [] replaced by
  134.27 - * your own identifying information:
  134.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  134.29 - *
  134.30 - * Contributor(s):
  134.31 - *
  134.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  134.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  134.34 - *
  134.35 - * If you wish your version of this file to be governed by only the CDDL
  134.36 - * or only the GPL Version 2, indicate your decision by adding
  134.37 - * "[Contributor] elects to include this software in this distribution
  134.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  134.39 - * single choice of license, a recipient has the option to distribute
  134.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  134.41 - * to extend the choice of license to its licensees as provided above.
  134.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  134.43 - * Version 2 license, then the option applies only if the new code is
  134.44 - * made subject to such option by the copyright holder.
  134.45 - */
  134.46 -package org.apidesign.html.kofx;
  134.47 -
  134.48 -import java.io.Closeable;
  134.49 -import java.lang.reflect.InvocationTargetException;
  134.50 -import java.lang.reflect.Method;
  134.51 -import javafx.application.Platform;
  134.52 -import org.apidesign.html.boot.spi.Fn;
  134.53 -import org.testng.ITest;
  134.54 -import org.testng.annotations.Test;
  134.55 -
  134.56 -/**
  134.57 - *
  134.58 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  134.59 - */
  134.60 -public final class KOFx implements ITest, Runnable {
  134.61 -    private final Fn.Presenter p;
  134.62 -    private final Method m;
  134.63 -    private Object result;
  134.64 -    private Object inst;
  134.65 -    private int count;
  134.66 -
  134.67 -    KOFx(Fn.Presenter p, Method m) {
  134.68 -        this.p = p;
  134.69 -        this.m = m;
  134.70 -    }
  134.71 -
  134.72 -    @Override
  134.73 -    public String getTestName() {
  134.74 -        return m.getName();
  134.75 -    }
  134.76 -
  134.77 -    @Test
  134.78 -    public synchronized void executeTest() throws Exception {
  134.79 -        if (result == null) {
  134.80 -            Platform.runLater(this);
  134.81 -            wait();
  134.82 -        }
  134.83 -        if (result instanceof Exception) {
  134.84 -            throw (Exception)result;
  134.85 -        }
  134.86 -        if (result instanceof Error) {
  134.87 -            throw (Error)result;
  134.88 -        }
  134.89 -    }
  134.90 -
  134.91 -    @Override
  134.92 -    public synchronized void run() {
  134.93 -        boolean notify = true;
  134.94 -        try (Closeable a = Fn.activate(p)) {
  134.95 -            if (inst == null) {
  134.96 -                inst = m.getDeclaringClass().newInstance();
  134.97 -            }
  134.98 -            result = m.invoke(inst);
  134.99 -            if (result == null) {
 134.100 -                result = this;
 134.101 -            }
 134.102 -        } catch (InvocationTargetException ex) {
 134.103 -            Throwable r = ex.getTargetException();
 134.104 -            if (r instanceof InterruptedException) {
 134.105 -                if (count++ < 10000) {
 134.106 -                    notify = false;
 134.107 -                    Platform.runLater(this);
 134.108 -                    return;
 134.109 -                }
 134.110 -            }
 134.111 -            result = r;
 134.112 -        } catch (Exception ex) {
 134.113 -            result = ex;
 134.114 -        } finally {
 134.115 -            if (notify) {
 134.116 -                notifyAll();
 134.117 -            }
 134.118 -        }
 134.119 -    }
 134.120 -    
 134.121 -}
   135.1 --- a/ko-fx/src/test/java/org/apidesign/html/kofx/KnockoutFXTest.java	Mon Dec 16 15:48:09 2013 +0100
   135.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   135.3 @@ -1,229 +0,0 @@
   135.4 -/**
   135.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   135.6 - *
   135.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   135.8 - *
   135.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  135.10 - * Other names may be trademarks of their respective owners.
  135.11 - *
  135.12 - * The contents of this file are subject to the terms of either the GNU
  135.13 - * General Public License Version 2 only ("GPL") or the Common
  135.14 - * Development and Distribution License("CDDL") (collectively, the
  135.15 - * "License"). You may not use this file except in compliance with the
  135.16 - * License. You can obtain a copy of the License at
  135.17 - * http://www.netbeans.org/cddl-gplv2.html
  135.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  135.19 - * specific language governing permissions and limitations under the
  135.20 - * License.  When distributing the software, include this License Header
  135.21 - * Notice in each file and include the License file at
  135.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  135.23 - * particular file as subject to the "Classpath" exception as provided
  135.24 - * by Oracle in the GPL Version 2 section of the License file that
  135.25 - * accompanied this code. If applicable, add the following below the
  135.26 - * License Header, with the fields enclosed by brackets [] replaced by
  135.27 - * your own identifying information:
  135.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  135.29 - *
  135.30 - * Contributor(s):
  135.31 - *
  135.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  135.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  135.34 - *
  135.35 - * If you wish your version of this file to be governed by only the CDDL
  135.36 - * or only the GPL Version 2, indicate your decision by adding
  135.37 - * "[Contributor] elects to include this software in this distribution
  135.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  135.39 - * single choice of license, a recipient has the option to distribute
  135.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  135.41 - * to extend the choice of license to its licensees as provided above.
  135.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  135.43 - * Version 2 license, then the option applies only if the new code is
  135.44 - * made subject to such option by the copyright holder.
  135.45 - */
  135.46 -package org.apidesign.html.kofx;
  135.47 -
  135.48 -import java.io.BufferedReader;
  135.49 -import java.io.IOException;
  135.50 -import java.io.InputStreamReader;
  135.51 -import java.lang.annotation.Annotation;
  135.52 -import java.lang.reflect.Method;
  135.53 -import java.net.URI;
  135.54 -import java.net.URISyntaxException;
  135.55 -import java.net.URL;
  135.56 -import java.net.URLConnection;
  135.57 -import java.util.ArrayList;
  135.58 -import java.util.List;
  135.59 -import java.util.Map;
  135.60 -import java.util.concurrent.Executors;
  135.61 -import net.java.html.BrwsrCtx;
  135.62 -import net.java.html.boot.BrowserBuilder;
  135.63 -import net.java.html.js.JavaScriptBody;
  135.64 -import org.apidesign.html.boot.impl.FnContext;
  135.65 -import org.apidesign.html.boot.spi.Fn;
  135.66 -import org.apidesign.html.context.spi.Contexts;
  135.67 -import org.apidesign.html.json.spi.Technology;
  135.68 -import org.apidesign.html.json.spi.Transfer;
  135.69 -import org.apidesign.html.json.spi.WSTransfer;
  135.70 -import org.apidesign.html.json.tck.KOTest;
  135.71 -import org.apidesign.html.json.tck.KnockoutTCK;
  135.72 -import org.json.JSONException;
  135.73 -import org.json.JSONObject;
  135.74 -import org.openide.util.lookup.ServiceProvider;
  135.75 -import org.testng.annotations.Factory;
  135.76 -import static org.testng.Assert.*;
  135.77 -
  135.78 -/**
  135.79 - *
  135.80 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  135.81 - */
  135.82 -@ServiceProvider(service = KnockoutTCK.class)
  135.83 -public final class KnockoutFXTest extends KnockoutTCK {
  135.84 -    private static Class<?> browserClass;
  135.85 -    private static Fn.Presenter browserContext;
  135.86 -    
  135.87 -    public KnockoutFXTest() {
  135.88 -    }
  135.89 -    
  135.90 -    @Factory public static Object[] compatibilityTests() throws Exception {
  135.91 -        Class[] arr = testClasses();
  135.92 -        for (int i = 0; i < arr.length; i++) {
  135.93 -            assertEquals(
  135.94 -                arr[i].getClassLoader(),
  135.95 -                KnockoutFXTest.class.getClassLoader(),
  135.96 -                "All classes loaded by the same classloader"
  135.97 -            );
  135.98 -        }
  135.99 -        
 135.100 -        URI uri = DynamicHTTP.initServer();
 135.101 -    
 135.102 -        final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(KnockoutFXTest.class).
 135.103 -            loadPage(uri.toString()).
 135.104 -            invoke("initialized");
 135.105 -        
 135.106 -        Executors.newSingleThreadExecutor().submit(new Runnable() {
 135.107 -            @Override
 135.108 -            public void run() {
 135.109 -                bb.showAndWait();
 135.110 -            }
 135.111 -        });
 135.112 -        
 135.113 -        ClassLoader l = getClassLoader();
 135.114 -        List<Object> res = new ArrayList<Object>();
 135.115 -        for (int i = 0; i < arr.length; i++) {
 135.116 -            Class<?> c = Class.forName(arr[i].getName(), true, l);
 135.117 -            seekKOTests(c, res);
 135.118 -        }
 135.119 -        Class<?> c = Class.forName(LessCallbacksCheck.class.getName(), true, l);
 135.120 -        seekKOTests(c, res);
 135.121 -        return res.toArray();
 135.122 -    }
 135.123 -
 135.124 -    private static void seekKOTests(Class<?> c, List<Object> res) throws SecurityException, ClassNotFoundException {
 135.125 -        Class<? extends Annotation> koTest =
 135.126 -            c.getClassLoader().loadClass(KOTest.class.getName()).
 135.127 -            asSubclass(Annotation.class);
 135.128 -        for (Method m : c.getMethods()) {
 135.129 -            if (m.getAnnotation(koTest) != null) {
 135.130 -                res.add(new KOFx(browserContext, m));
 135.131 -            }
 135.132 -        }
 135.133 -    }
 135.134 -
 135.135 -    static synchronized ClassLoader getClassLoader() throws InterruptedException {
 135.136 -        while (browserClass == null) {
 135.137 -            KnockoutFXTest.class.wait();
 135.138 -        }
 135.139 -        return browserClass.getClassLoader();
 135.140 -    }
 135.141 -    
 135.142 -    public static synchronized void initialized(Class<?> browserCls) throws Exception {
 135.143 -        browserClass = browserCls;
 135.144 -        browserContext = FnContext.currentPresenter();
 135.145 -        KnockoutFXTest.class.notifyAll();
 135.146 -    }
 135.147 -    
 135.148 -    public static void initialized() throws Exception {
 135.149 -        Class<?> classpathClass = ClassLoader.getSystemClassLoader().loadClass(KnockoutFXTest.class.getName());
 135.150 -        Method m = classpathClass.getMethod("initialized", Class.class);
 135.151 -        m.invoke(null, KnockoutFXTest.class);
 135.152 -        browserContext = FnContext.currentPresenter();
 135.153 -    }
 135.154 -    
 135.155 -    @Override
 135.156 -    public BrwsrCtx createContext() {
 135.157 -        FXContext fx = new FXContext(browserContext);
 135.158 -        Contexts.Builder cb = Contexts.newBuilder().
 135.159 -            register(Technology.class, fx, 10).
 135.160 -            register(Transfer.class, fx, 10);
 135.161 -        if (fx.areWebSocketsSupported()) {
 135.162 -            cb.register(WSTransfer.class, fx, 10);
 135.163 -        }
 135.164 -        return cb.build();
 135.165 -    }
 135.166 -
 135.167 -    @Override
 135.168 -    public Object createJSON(Map<String, Object> values) {
 135.169 -        JSONObject json = new JSONObject();
 135.170 -        for (Map.Entry<String, Object> entry : values.entrySet()) {
 135.171 -            try {
 135.172 -                json.put(entry.getKey(), entry.getValue());
 135.173 -            } catch (JSONException ex) {
 135.174 -                throw new IllegalStateException(ex);
 135.175 -            }
 135.176 -        }
 135.177 -        return json;
 135.178 -    }
 135.179 -
 135.180 -    @Override
 135.181 -    @JavaScriptBody(args = { "s", "args" }, body = ""
 135.182 -        + "var f = new Function(s); "
 135.183 -        + "return f.apply(null, args);"
 135.184 -    )
 135.185 -    public native Object executeScript(String script, Object[] arguments);
 135.186 -
 135.187 -    @JavaScriptBody(args = {  }, body = 
 135.188 -          "var h;"
 135.189 -        + "if (!!window && !!window.location && !!window.location.href)\n"
 135.190 -        + "  h = window.location.href;\n"
 135.191 -        + "else "
 135.192 -        + "  h = null;"
 135.193 -        + "return h;\n"
 135.194 -    )
 135.195 -    private static native String findBaseURL();
 135.196 -    
 135.197 -    @Override
 135.198 -    public URI prepareURL(String content, String mimeType, String[] parameters) {
 135.199 -        try {
 135.200 -            final URL baseURL = new URL(findBaseURL());
 135.201 -            StringBuilder sb = new StringBuilder();
 135.202 -            sb.append("/dynamic?mimeType=").append(mimeType);
 135.203 -            for (int i = 0; i < parameters.length; i++) {
 135.204 -                sb.append("&param" + i).append("=").append(parameters[i]);
 135.205 -            }
 135.206 -            String mangle = content.replace("\n", "%0a")
 135.207 -                .replace("\"", "\\\"").replace(" ", "%20");
 135.208 -            sb.append("&content=").append(mangle);
 135.209 -
 135.210 -            URL query = new URL(baseURL, sb.toString());
 135.211 -            URLConnection c = query.openConnection();
 135.212 -            BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
 135.213 -            URI connectTo = new URI(br.readLine());
 135.214 -            return connectTo;
 135.215 -        } catch (IOException ex) {
 135.216 -            throw new IllegalStateException(ex);
 135.217 -        } catch (URISyntaxException ex) {
 135.218 -            throw new IllegalStateException(ex);
 135.219 -        }
 135.220 -    }
 135.221 -
 135.222 -    @Override
 135.223 -    public boolean canFailWebSocketTest() {
 135.224 -        try {
 135.225 -            Class.forName("java.util.function.Function");
 135.226 -            return false;
 135.227 -        } catch (ClassNotFoundException ex) {
 135.228 -            // running on JDK7, FX WebView WebSocket impl does not work
 135.229 -            return true;
 135.230 -        }
 135.231 -    }
 135.232 -}
   136.1 --- a/ko-fx/src/test/java/org/apidesign/html/kofx/LessCallbacksCheck.java	Mon Dec 16 15:48:09 2013 +0100
   136.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   136.3 @@ -1,82 +0,0 @@
   136.4 -/**
   136.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   136.6 - *
   136.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   136.8 - *
   136.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  136.10 - * Other names may be trademarks of their respective owners.
  136.11 - *
  136.12 - * The contents of this file are subject to the terms of either the GNU
  136.13 - * General Public License Version 2 only ("GPL") or the Common
  136.14 - * Development and Distribution License("CDDL") (collectively, the
  136.15 - * "License"). You may not use this file except in compliance with the
  136.16 - * License. You can obtain a copy of the License at
  136.17 - * http://www.netbeans.org/cddl-gplv2.html
  136.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  136.19 - * specific language governing permissions and limitations under the
  136.20 - * License.  When distributing the software, include this License Header
  136.21 - * Notice in each file and include the License file at
  136.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  136.23 - * particular file as subject to the "Classpath" exception as provided
  136.24 - * by Oracle in the GPL Version 2 section of the License file that
  136.25 - * accompanied this code. If applicable, add the following below the
  136.26 - * License Header, with the fields enclosed by brackets [] replaced by
  136.27 - * your own identifying information:
  136.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  136.29 - *
  136.30 - * Contributor(s):
  136.31 - *
  136.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  136.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  136.34 - *
  136.35 - * If you wish your version of this file to be governed by only the CDDL
  136.36 - * or only the GPL Version 2, indicate your decision by adding
  136.37 - * "[Contributor] elects to include this software in this distribution
  136.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  136.39 - * single choice of license, a recipient has the option to distribute
  136.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  136.41 - * to extend the choice of license to its licensees as provided above.
  136.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  136.43 - * Version 2 license, then the option applies only if the new code is
  136.44 - * made subject to such option by the copyright holder.
  136.45 - */
  136.46 -package org.apidesign.html.kofx;
  136.47 -
  136.48 -import java.io.PrintWriter;
  136.49 -import java.io.StringWriter;
  136.50 -import net.java.html.json.ComputedProperty;
  136.51 -import net.java.html.json.Model;
  136.52 -import net.java.html.json.Property;
  136.53 -import org.apidesign.html.json.tck.KOTest;
  136.54 -
  136.55 -/**
  136.56 - *
  136.57 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  136.58 - */
  136.59 -@Model(className = "LessCalls", properties = {
  136.60 -    @Property(name = "value", type = int.class)
  136.61 -})
  136.62 -public class LessCallbacksCheck {
  136.63 -    private static StringWriter sw;
  136.64 -    
  136.65 -    @ComputedProperty static int plusOne(int value) {
  136.66 -        if (sw == null) {
  136.67 -            sw = new StringWriter();
  136.68 -        }
  136.69 -        new Exception("Who calls me?").printStackTrace(
  136.70 -            new PrintWriter(sw)
  136.71 -        );
  136.72 -        return value + 1;
  136.73 -    }
  136.74 -    
  136.75 -    @KOTest public void dontCallForInitialValueBackToJavaVM() {
  136.76 -        LessCalls m = new LessCalls(10).applyBindings();
  136.77 -        assert m.getPlusOne() == 11 : "Expecting 11: " + m.getPlusOne();
  136.78 -        
  136.79 -        assert sw != null : "StringWriter should be initialized: " + sw;
  136.80 -        
  136.81 -        if (sw.toString().contains("$JsCallbacks$")) {
  136.82 -            assert false : "Don't call for initial value via JsCallbacks:\n" + sw;
  136.83 -        }
  136.84 -    }
  136.85 -}
   137.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   137.2 +++ b/ko-fx/src/test/java/org/netbeans/html/kofx/DynamicHTTP.java	Mon Dec 16 16:59:43 2013 +0100
   137.3 @@ -0,0 +1,259 @@
   137.4 +/**
   137.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   137.6 + *
   137.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   137.8 + *
   137.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  137.10 + * Other names may be trademarks of their respective owners.
  137.11 + *
  137.12 + * The contents of this file are subject to the terms of either the GNU
  137.13 + * General Public License Version 2 only ("GPL") or the Common
  137.14 + * Development and Distribution License("CDDL") (collectively, the
  137.15 + * "License"). You may not use this file except in compliance with the
  137.16 + * License. You can obtain a copy of the License at
  137.17 + * http://www.netbeans.org/cddl-gplv2.html
  137.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  137.19 + * specific language governing permissions and limitations under the
  137.20 + * License.  When distributing the software, include this License Header
  137.21 + * Notice in each file and include the License file at
  137.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  137.23 + * particular file as subject to the "Classpath" exception as provided
  137.24 + * by Oracle in the GPL Version 2 section of the License file that
  137.25 + * accompanied this code. If applicable, add the following below the
  137.26 + * License Header, with the fields enclosed by brackets [] replaced by
  137.27 + * your own identifying information:
  137.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  137.29 + *
  137.30 + * Contributor(s):
  137.31 + *
  137.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  137.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  137.34 + *
  137.35 + * If you wish your version of this file to be governed by only the CDDL
  137.36 + * or only the GPL Version 2, indicate your decision by adding
  137.37 + * "[Contributor] elects to include this software in this distribution
  137.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  137.39 + * single choice of license, a recipient has the option to distribute
  137.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  137.41 + * to extend the choice of license to its licensees as provided above.
  137.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  137.43 + * Version 2 license, then the option applies only if the new code is
  137.44 + * made subject to such option by the copyright holder.
  137.45 + */
  137.46 +package org.netbeans.html.kofx;
  137.47 +
  137.48 +import java.io.ByteArrayInputStream;
  137.49 +import java.io.ByteArrayOutputStream;
  137.50 +import java.io.IOException;
  137.51 +import java.io.InputStream;
  137.52 +import java.io.OutputStream;
  137.53 +import java.io.Reader;
  137.54 +import java.net.URI;
  137.55 +import java.net.URISyntaxException;
  137.56 +import java.util.ArrayList;
  137.57 +import java.util.List;
  137.58 +import java.util.logging.Level;
  137.59 +import java.util.logging.Logger;
  137.60 +import org.glassfish.grizzly.PortRange;
  137.61 +import org.glassfish.grizzly.http.server.HttpHandler;
  137.62 +import org.glassfish.grizzly.http.server.HttpServer;
  137.63 +import org.glassfish.grizzly.http.server.NetworkListener;
  137.64 +import org.glassfish.grizzly.http.server.Request;
  137.65 +import org.glassfish.grizzly.http.server.Response;
  137.66 +import org.glassfish.grizzly.http.server.ServerConfiguration;
  137.67 +import org.glassfish.grizzly.websockets.WebSocket;
  137.68 +import org.glassfish.grizzly.websockets.WebSocketAddOn;
  137.69 +import org.glassfish.grizzly.websockets.WebSocketApplication;
  137.70 +import org.glassfish.grizzly.websockets.WebSocketEngine;
  137.71 +
  137.72 +/**
  137.73 + *
  137.74 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  137.75 + */
  137.76 +final class DynamicHTTP extends HttpHandler {
  137.77 +    private static final Logger LOG = Logger.getLogger(DynamicHTTP.class.getName());
  137.78 +    private static int resourcesCount;
  137.79 +    private static List<Resource> resources;
  137.80 +    private static ServerConfiguration conf;
  137.81 +    private static HttpServer server;
  137.82 +    
  137.83 +    private DynamicHTTP() {
  137.84 +    }
  137.85 +    
  137.86 +    static URI initServer() throws Exception {
  137.87 +        server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
  137.88 +        final WebSocketAddOn addon = new WebSocketAddOn();
  137.89 +        for (NetworkListener listener : server.getListeners()) {
  137.90 +            listener.registerAddOn(addon);
  137.91 +        }        
  137.92 +        resources = new ArrayList<Resource>();
  137.93 +
  137.94 +        conf = server.getServerConfiguration();
  137.95 +        final DynamicHTTP dh = new DynamicHTTP();
  137.96 +
  137.97 +        conf.addHttpHandler(dh, "/");
  137.98 +        
  137.99 +        server.start();
 137.100 +
 137.101 +        return pageURL("http", server, "/test.html");
 137.102 +    }
 137.103 +    
 137.104 +    @Override
 137.105 +    public void service(Request request, Response response) throws Exception {
 137.106 +        if ("/test.html".equals(request.getRequestURI())) {
 137.107 +            response.setContentType("text/html");
 137.108 +            final InputStream is = DynamicHTTP.class.getResourceAsStream("test.html");
 137.109 +            copyStream(is, response.getOutputStream(), null);
 137.110 +            return;
 137.111 +        }
 137.112 +        if ("/dynamic".equals(request.getRequestURI())) {
 137.113 +            String mimeType = request.getParameter("mimeType");
 137.114 +            List<String> params = new ArrayList<String>();
 137.115 +            boolean webSocket = false;
 137.116 +            for (int i = 0;; i++) {
 137.117 +                String p = request.getParameter("param" + i);
 137.118 +                if (p == null) {
 137.119 +                    break;
 137.120 +                }
 137.121 +                if ("protocol:ws".equals(p)) {
 137.122 +                    webSocket = true;
 137.123 +                    continue;
 137.124 +                }
 137.125 +                params.add(p);
 137.126 +            }
 137.127 +            final String cnt = request.getParameter("content");
 137.128 +            String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
 137.129 +            ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
 137.130 +            URI url;
 137.131 +            final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
 137.132 +            if (webSocket) {
 137.133 +                url = registerWebSocket(res);
 137.134 +            } else {
 137.135 +                url = registerResource(res);
 137.136 +            }
 137.137 +            response.getWriter().write(url.toString());
 137.138 +            response.getWriter().write("\n");
 137.139 +            return;
 137.140 +        }
 137.141 +
 137.142 +        for (Resource r : resources) {
 137.143 +            if (r.httpPath.equals(request.getRequestURI())) {
 137.144 +                response.setContentType(r.httpType);
 137.145 +                r.httpContent.reset();
 137.146 +                String[] params = null;
 137.147 +                if (r.parameters.length != 0) {
 137.148 +                    params = new String[r.parameters.length];
 137.149 +                    for (int i = 0; i < r.parameters.length; i++) {
 137.150 +                        params[i] = request.getParameter(r.parameters[i]);
 137.151 +                        if (params[i] == null) {
 137.152 +                            if ("http.method".equals(r.parameters[i])) {
 137.153 +                                params[i] = request.getMethod().toString();
 137.154 +                            } else if ("http.requestBody".equals(r.parameters[i])) {
 137.155 +                                Reader rdr = request.getReader();
 137.156 +                                StringBuilder sb = new StringBuilder();
 137.157 +                                for (;;) {
 137.158 +                                    int ch = rdr.read();
 137.159 +                                    if (ch == -1) {
 137.160 +                                        break;
 137.161 +                                    }
 137.162 +                                    sb.append((char) ch);
 137.163 +                                }
 137.164 +                                params[i] = sb.toString();
 137.165 +                            }
 137.166 +                        }
 137.167 +                        if (params[i] == null) {
 137.168 +                            params[i] = "null";
 137.169 +                        }
 137.170 +                    }
 137.171 +                }
 137.172 +
 137.173 +                copyStream(r.httpContent, response.getOutputStream(), null, params);
 137.174 +            }
 137.175 +        }
 137.176 +    }
 137.177 +    
 137.178 +    private URI registerWebSocket(Resource r) {
 137.179 +        WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
 137.180 +        return pageURL("ws", server, r.httpPath);
 137.181 +    }
 137.182 +
 137.183 +    private URI registerResource(Resource r) {
 137.184 +        if (!resources.contains(r)) {
 137.185 +            resources.add(r);
 137.186 +            conf.addHttpHandler(this, r.httpPath);
 137.187 +        }
 137.188 +        return pageURL("http", server, r.httpPath);
 137.189 +    }
 137.190 +    
 137.191 +    private static URI pageURL(String proto, HttpServer server, final String page) {
 137.192 +        NetworkListener listener = server.getListeners().iterator().next();
 137.193 +        int port = listener.getPort();
 137.194 +        try {
 137.195 +            return new URI(proto + "://localhost:" + port + page);
 137.196 +        } catch (URISyntaxException ex) {
 137.197 +            throw new IllegalStateException(ex);
 137.198 +        }
 137.199 +    }
 137.200 +    
 137.201 +    static final class Resource {
 137.202 +
 137.203 +        final InputStream httpContent;
 137.204 +        final String httpType;
 137.205 +        final String httpPath;
 137.206 +        final String[] parameters;
 137.207 +
 137.208 +        Resource(InputStream httpContent, String httpType, String httpPath,
 137.209 +            String[] parameters) {
 137.210 +            httpContent.mark(Integer.MAX_VALUE);
 137.211 +            this.httpContent = httpContent;
 137.212 +            this.httpType = httpType;
 137.213 +            this.httpPath = httpPath;
 137.214 +            this.parameters = parameters;
 137.215 +        }
 137.216 +    }
 137.217 +
 137.218 +    static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
 137.219 +        for (;;) {
 137.220 +            int ch = is.read();
 137.221 +            if (ch == -1) {
 137.222 +                break;
 137.223 +            }
 137.224 +            if (ch == '$' && params.length > 0) {
 137.225 +                int cnt = is.read() - '0';
 137.226 +                if (baseURL != null && cnt == 'U' - '0') {
 137.227 +                    os.write(baseURL.getBytes("UTF-8"));
 137.228 +                } else {
 137.229 +                    if (cnt >= 0 && cnt < params.length) {
 137.230 +                        os.write(params[cnt].getBytes("UTF-8"));
 137.231 +                    } else {
 137.232 +                        os.write('$');
 137.233 +                        os.write(cnt + '0');
 137.234 +                    }
 137.235 +                }
 137.236 +            } else {
 137.237 +                os.write(ch);
 137.238 +            }
 137.239 +        }
 137.240 +    }
 137.241 +    
 137.242 +    private static class WS extends WebSocketApplication {
 137.243 +        private final Resource r;
 137.244 +
 137.245 +        private WS(Resource r) {
 137.246 +            this.r = r;
 137.247 +        }
 137.248 +
 137.249 +        @Override
 137.250 +        public void onMessage(WebSocket socket, String text) {
 137.251 +            try {
 137.252 +                r.httpContent.reset();
 137.253 +                ByteArrayOutputStream out = new ByteArrayOutputStream();
 137.254 +                copyStream(r.httpContent, out, null, text);
 137.255 +                String s = new String(out.toByteArray(), "UTF-8");
 137.256 +                socket.send(s);
 137.257 +            } catch (IOException ex) {
 137.258 +                LOG.log(Level.WARNING, "Error processing message " + text, ex);
 137.259 +            }
 137.260 +        }
 137.261 +    }
 137.262 +}
   138.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   138.2 +++ b/ko-fx/src/test/java/org/netbeans/html/kofx/KOFx.java	Mon Dec 16 16:59:43 2013 +0100
   138.3 @@ -0,0 +1,118 @@
   138.4 +/**
   138.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   138.6 + *
   138.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   138.8 + *
   138.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  138.10 + * Other names may be trademarks of their respective owners.
  138.11 + *
  138.12 + * The contents of this file are subject to the terms of either the GNU
  138.13 + * General Public License Version 2 only ("GPL") or the Common
  138.14 + * Development and Distribution License("CDDL") (collectively, the
  138.15 + * "License"). You may not use this file except in compliance with the
  138.16 + * License. You can obtain a copy of the License at
  138.17 + * http://www.netbeans.org/cddl-gplv2.html
  138.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  138.19 + * specific language governing permissions and limitations under the
  138.20 + * License.  When distributing the software, include this License Header
  138.21 + * Notice in each file and include the License file at
  138.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  138.23 + * particular file as subject to the "Classpath" exception as provided
  138.24 + * by Oracle in the GPL Version 2 section of the License file that
  138.25 + * accompanied this code. If applicable, add the following below the
  138.26 + * License Header, with the fields enclosed by brackets [] replaced by
  138.27 + * your own identifying information:
  138.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  138.29 + *
  138.30 + * Contributor(s):
  138.31 + *
  138.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  138.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  138.34 + *
  138.35 + * If you wish your version of this file to be governed by only the CDDL
  138.36 + * or only the GPL Version 2, indicate your decision by adding
  138.37 + * "[Contributor] elects to include this software in this distribution
  138.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  138.39 + * single choice of license, a recipient has the option to distribute
  138.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  138.41 + * to extend the choice of license to its licensees as provided above.
  138.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  138.43 + * Version 2 license, then the option applies only if the new code is
  138.44 + * made subject to such option by the copyright holder.
  138.45 + */
  138.46 +package org.netbeans.html.kofx;
  138.47 +
  138.48 +import java.io.Closeable;
  138.49 +import java.lang.reflect.InvocationTargetException;
  138.50 +import java.lang.reflect.Method;
  138.51 +import javafx.application.Platform;
  138.52 +import org.apidesign.html.boot.spi.Fn;
  138.53 +import org.testng.ITest;
  138.54 +import org.testng.annotations.Test;
  138.55 +
  138.56 +/**
  138.57 + *
  138.58 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  138.59 + */
  138.60 +public final class KOFx implements ITest, Runnable {
  138.61 +    private final Fn.Presenter p;
  138.62 +    private final Method m;
  138.63 +    private Object result;
  138.64 +    private Object inst;
  138.65 +    private int count;
  138.66 +
  138.67 +    KOFx(Fn.Presenter p, Method m) {
  138.68 +        this.p = p;
  138.69 +        this.m = m;
  138.70 +    }
  138.71 +
  138.72 +    @Override
  138.73 +    public String getTestName() {
  138.74 +        return m.getName();
  138.75 +    }
  138.76 +
  138.77 +    @Test
  138.78 +    public synchronized void executeTest() throws Exception {
  138.79 +        if (result == null) {
  138.80 +            Platform.runLater(this);
  138.81 +            wait();
  138.82 +        }
  138.83 +        if (result instanceof Exception) {
  138.84 +            throw (Exception)result;
  138.85 +        }
  138.86 +        if (result instanceof Error) {
  138.87 +            throw (Error)result;
  138.88 +        }
  138.89 +    }
  138.90 +
  138.91 +    @Override
  138.92 +    public synchronized void run() {
  138.93 +        boolean notify = true;
  138.94 +        try (Closeable a = Fn.activate(p)) {
  138.95 +            if (inst == null) {
  138.96 +                inst = m.getDeclaringClass().newInstance();
  138.97 +            }
  138.98 +            result = m.invoke(inst);
  138.99 +            if (result == null) {
 138.100 +                result = this;
 138.101 +            }
 138.102 +        } catch (InvocationTargetException ex) {
 138.103 +            Throwable r = ex.getTargetException();
 138.104 +            if (r instanceof InterruptedException) {
 138.105 +                if (count++ < 10000) {
 138.106 +                    notify = false;
 138.107 +                    Platform.runLater(this);
 138.108 +                    return;
 138.109 +                }
 138.110 +            }
 138.111 +            result = r;
 138.112 +        } catch (Exception ex) {
 138.113 +            result = ex;
 138.114 +        } finally {
 138.115 +            if (notify) {
 138.116 +                notifyAll();
 138.117 +            }
 138.118 +        }
 138.119 +    }
 138.120 +    
 138.121 +}
   139.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   139.2 +++ b/ko-fx/src/test/java/org/netbeans/html/kofx/KnockoutFXTest.java	Mon Dec 16 16:59:43 2013 +0100
   139.3 @@ -0,0 +1,229 @@
   139.4 +/**
   139.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   139.6 + *
   139.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   139.8 + *
   139.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  139.10 + * Other names may be trademarks of their respective owners.
  139.11 + *
  139.12 + * The contents of this file are subject to the terms of either the GNU
  139.13 + * General Public License Version 2 only ("GPL") or the Common
  139.14 + * Development and Distribution License("CDDL") (collectively, the
  139.15 + * "License"). You may not use this file except in compliance with the
  139.16 + * License. You can obtain a copy of the License at
  139.17 + * http://www.netbeans.org/cddl-gplv2.html
  139.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  139.19 + * specific language governing permissions and limitations under the
  139.20 + * License.  When distributing the software, include this License Header
  139.21 + * Notice in each file and include the License file at
  139.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  139.23 + * particular file as subject to the "Classpath" exception as provided
  139.24 + * by Oracle in the GPL Version 2 section of the License file that
  139.25 + * accompanied this code. If applicable, add the following below the
  139.26 + * License Header, with the fields enclosed by brackets [] replaced by
  139.27 + * your own identifying information:
  139.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  139.29 + *
  139.30 + * Contributor(s):
  139.31 + *
  139.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  139.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  139.34 + *
  139.35 + * If you wish your version of this file to be governed by only the CDDL
  139.36 + * or only the GPL Version 2, indicate your decision by adding
  139.37 + * "[Contributor] elects to include this software in this distribution
  139.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  139.39 + * single choice of license, a recipient has the option to distribute
  139.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  139.41 + * to extend the choice of license to its licensees as provided above.
  139.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  139.43 + * Version 2 license, then the option applies only if the new code is
  139.44 + * made subject to such option by the copyright holder.
  139.45 + */
  139.46 +package org.netbeans.html.kofx;
  139.47 +
  139.48 +import java.io.BufferedReader;
  139.49 +import java.io.IOException;
  139.50 +import java.io.InputStreamReader;
  139.51 +import java.lang.annotation.Annotation;
  139.52 +import java.lang.reflect.Method;
  139.53 +import java.net.URI;
  139.54 +import java.net.URISyntaxException;
  139.55 +import java.net.URL;
  139.56 +import java.net.URLConnection;
  139.57 +import java.util.ArrayList;
  139.58 +import java.util.List;
  139.59 +import java.util.Map;
  139.60 +import java.util.concurrent.Executors;
  139.61 +import net.java.html.BrwsrCtx;
  139.62 +import net.java.html.boot.BrowserBuilder;
  139.63 +import net.java.html.js.JavaScriptBody;
  139.64 +import org.netbeans.html.boot.impl.FnContext;
  139.65 +import org.apidesign.html.boot.spi.Fn;
  139.66 +import org.apidesign.html.context.spi.Contexts;
  139.67 +import org.apidesign.html.json.spi.Technology;
  139.68 +import org.apidesign.html.json.spi.Transfer;
  139.69 +import org.apidesign.html.json.spi.WSTransfer;
  139.70 +import org.apidesign.html.json.tck.KOTest;
  139.71 +import org.apidesign.html.json.tck.KnockoutTCK;
  139.72 +import org.json.JSONException;
  139.73 +import org.json.JSONObject;
  139.74 +import org.openide.util.lookup.ServiceProvider;
  139.75 +import org.testng.annotations.Factory;
  139.76 +import static org.testng.Assert.*;
  139.77 +
  139.78 +/**
  139.79 + *
  139.80 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  139.81 + */
  139.82 +@ServiceProvider(service = KnockoutTCK.class)
  139.83 +public final class KnockoutFXTest extends KnockoutTCK {
  139.84 +    private static Class<?> browserClass;
  139.85 +    private static Fn.Presenter browserContext;
  139.86 +    
  139.87 +    public KnockoutFXTest() {
  139.88 +    }
  139.89 +    
  139.90 +    @Factory public static Object[] compatibilityTests() throws Exception {
  139.91 +        Class[] arr = testClasses();
  139.92 +        for (int i = 0; i < arr.length; i++) {
  139.93 +            assertEquals(
  139.94 +                arr[i].getClassLoader(),
  139.95 +                KnockoutFXTest.class.getClassLoader(),
  139.96 +                "All classes loaded by the same classloader"
  139.97 +            );
  139.98 +        }
  139.99 +        
 139.100 +        URI uri = DynamicHTTP.initServer();
 139.101 +    
 139.102 +        final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(KnockoutFXTest.class).
 139.103 +            loadPage(uri.toString()).
 139.104 +            invoke("initialized");
 139.105 +        
 139.106 +        Executors.newSingleThreadExecutor().submit(new Runnable() {
 139.107 +            @Override
 139.108 +            public void run() {
 139.109 +                bb.showAndWait();
 139.110 +            }
 139.111 +        });
 139.112 +        
 139.113 +        ClassLoader l = getClassLoader();
 139.114 +        List<Object> res = new ArrayList<Object>();
 139.115 +        for (int i = 0; i < arr.length; i++) {
 139.116 +            Class<?> c = Class.forName(arr[i].getName(), true, l);
 139.117 +            seekKOTests(c, res);
 139.118 +        }
 139.119 +        Class<?> c = Class.forName(LessCallbacksCheck.class.getName(), true, l);
 139.120 +        seekKOTests(c, res);
 139.121 +        return res.toArray();
 139.122 +    }
 139.123 +
 139.124 +    private static void seekKOTests(Class<?> c, List<Object> res) throws SecurityException, ClassNotFoundException {
 139.125 +        Class<? extends Annotation> koTest =
 139.126 +            c.getClassLoader().loadClass(KOTest.class.getName()).
 139.127 +            asSubclass(Annotation.class);
 139.128 +        for (Method m : c.getMethods()) {
 139.129 +            if (m.getAnnotation(koTest) != null) {
 139.130 +                res.add(new KOFx(browserContext, m));
 139.131 +            }
 139.132 +        }
 139.133 +    }
 139.134 +
 139.135 +    static synchronized ClassLoader getClassLoader() throws InterruptedException {
 139.136 +        while (browserClass == null) {
 139.137 +            KnockoutFXTest.class.wait();
 139.138 +        }
 139.139 +        return browserClass.getClassLoader();
 139.140 +    }
 139.141 +    
 139.142 +    public static synchronized void initialized(Class<?> browserCls) throws Exception {
 139.143 +        browserClass = browserCls;
 139.144 +        browserContext = FnContext.currentPresenter();
 139.145 +        KnockoutFXTest.class.notifyAll();
 139.146 +    }
 139.147 +    
 139.148 +    public static void initialized() throws Exception {
 139.149 +        Class<?> classpathClass = ClassLoader.getSystemClassLoader().loadClass(KnockoutFXTest.class.getName());
 139.150 +        Method m = classpathClass.getMethod("initialized", Class.class);
 139.151 +        m.invoke(null, KnockoutFXTest.class);
 139.152 +        browserContext = FnContext.currentPresenter();
 139.153 +    }
 139.154 +    
 139.155 +    @Override
 139.156 +    public BrwsrCtx createContext() {
 139.157 +        FXContext fx = new FXContext(browserContext);
 139.158 +        Contexts.Builder cb = Contexts.newBuilder().
 139.159 +            register(Technology.class, fx, 10).
 139.160 +            register(Transfer.class, fx, 10);
 139.161 +        if (fx.areWebSocketsSupported()) {
 139.162 +            cb.register(WSTransfer.class, fx, 10);
 139.163 +        }
 139.164 +        return cb.build();
 139.165 +    }
 139.166 +
 139.167 +    @Override
 139.168 +    public Object createJSON(Map<String, Object> values) {
 139.169 +        JSONObject json = new JSONObject();
 139.170 +        for (Map.Entry<String, Object> entry : values.entrySet()) {
 139.171 +            try {
 139.172 +                json.put(entry.getKey(), entry.getValue());
 139.173 +            } catch (JSONException ex) {
 139.174 +                throw new IllegalStateException(ex);
 139.175 +            }
 139.176 +        }
 139.177 +        return json;
 139.178 +    }
 139.179 +
 139.180 +    @Override
 139.181 +    @JavaScriptBody(args = { "s", "args" }, body = ""
 139.182 +        + "var f = new Function(s); "
 139.183 +        + "return f.apply(null, args);"
 139.184 +    )
 139.185 +    public native Object executeScript(String script, Object[] arguments);
 139.186 +
 139.187 +    @JavaScriptBody(args = {  }, body = 
 139.188 +          "var h;"
 139.189 +        + "if (!!window && !!window.location && !!window.location.href)\n"
 139.190 +        + "  h = window.location.href;\n"
 139.191 +        + "else "
 139.192 +        + "  h = null;"
 139.193 +        + "return h;\n"
 139.194 +    )
 139.195 +    private static native String findBaseURL();
 139.196 +    
 139.197 +    @Override
 139.198 +    public URI prepareURL(String content, String mimeType, String[] parameters) {
 139.199 +        try {
 139.200 +            final URL baseURL = new URL(findBaseURL());
 139.201 +            StringBuilder sb = new StringBuilder();
 139.202 +            sb.append("/dynamic?mimeType=").append(mimeType);
 139.203 +            for (int i = 0; i < parameters.length; i++) {
 139.204 +                sb.append("&param" + i).append("=").append(parameters[i]);
 139.205 +            }
 139.206 +            String mangle = content.replace("\n", "%0a")
 139.207 +                .replace("\"", "\\\"").replace(" ", "%20");
 139.208 +            sb.append("&content=").append(mangle);
 139.209 +
 139.210 +            URL query = new URL(baseURL, sb.toString());
 139.211 +            URLConnection c = query.openConnection();
 139.212 +            BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
 139.213 +            URI connectTo = new URI(br.readLine());
 139.214 +            return connectTo;
 139.215 +        } catch (IOException ex) {
 139.216 +            throw new IllegalStateException(ex);
 139.217 +        } catch (URISyntaxException ex) {
 139.218 +            throw new IllegalStateException(ex);
 139.219 +        }
 139.220 +    }
 139.221 +
 139.222 +    @Override
 139.223 +    public boolean canFailWebSocketTest() {
 139.224 +        try {
 139.225 +            Class.forName("java.util.function.Function");
 139.226 +            return false;
 139.227 +        } catch (ClassNotFoundException ex) {
 139.228 +            // running on JDK7, FX WebView WebSocket impl does not work
 139.229 +            return true;
 139.230 +        }
 139.231 +    }
 139.232 +}
   140.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   140.2 +++ b/ko-fx/src/test/java/org/netbeans/html/kofx/LessCallbacksCheck.java	Mon Dec 16 16:59:43 2013 +0100
   140.3 @@ -0,0 +1,82 @@
   140.4 +/**
   140.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   140.6 + *
   140.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   140.8 + *
   140.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  140.10 + * Other names may be trademarks of their respective owners.
  140.11 + *
  140.12 + * The contents of this file are subject to the terms of either the GNU
  140.13 + * General Public License Version 2 only ("GPL") or the Common
  140.14 + * Development and Distribution License("CDDL") (collectively, the
  140.15 + * "License"). You may not use this file except in compliance with the
  140.16 + * License. You can obtain a copy of the License at
  140.17 + * http://www.netbeans.org/cddl-gplv2.html
  140.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  140.19 + * specific language governing permissions and limitations under the
  140.20 + * License.  When distributing the software, include this License Header
  140.21 + * Notice in each file and include the License file at
  140.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  140.23 + * particular file as subject to the "Classpath" exception as provided
  140.24 + * by Oracle in the GPL Version 2 section of the License file that
  140.25 + * accompanied this code. If applicable, add the following below the
  140.26 + * License Header, with the fields enclosed by brackets [] replaced by
  140.27 + * your own identifying information:
  140.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  140.29 + *
  140.30 + * Contributor(s):
  140.31 + *
  140.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  140.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  140.34 + *
  140.35 + * If you wish your version of this file to be governed by only the CDDL
  140.36 + * or only the GPL Version 2, indicate your decision by adding
  140.37 + * "[Contributor] elects to include this software in this distribution
  140.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  140.39 + * single choice of license, a recipient has the option to distribute
  140.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  140.41 + * to extend the choice of license to its licensees as provided above.
  140.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  140.43 + * Version 2 license, then the option applies only if the new code is
  140.44 + * made subject to such option by the copyright holder.
  140.45 + */
  140.46 +package org.netbeans.html.kofx;
  140.47 +
  140.48 +import java.io.PrintWriter;
  140.49 +import java.io.StringWriter;
  140.50 +import net.java.html.json.ComputedProperty;
  140.51 +import net.java.html.json.Model;
  140.52 +import net.java.html.json.Property;
  140.53 +import org.apidesign.html.json.tck.KOTest;
  140.54 +
  140.55 +/**
  140.56 + *
  140.57 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  140.58 + */
  140.59 +@Model(className = "LessCalls", properties = {
  140.60 +    @Property(name = "value", type = int.class)
  140.61 +})
  140.62 +public class LessCallbacksCheck {
  140.63 +    private static StringWriter sw;
  140.64 +    
  140.65 +    @ComputedProperty static int plusOne(int value) {
  140.66 +        if (sw == null) {
  140.67 +            sw = new StringWriter();
  140.68 +        }
  140.69 +        new Exception("Who calls me?").printStackTrace(
  140.70 +            new PrintWriter(sw)
  140.71 +        );
  140.72 +        return value + 1;
  140.73 +    }
  140.74 +    
  140.75 +    @KOTest public void dontCallForInitialValueBackToJavaVM() {
  140.76 +        LessCalls m = new LessCalls(10).applyBindings();
  140.77 +        assert m.getPlusOne() == 11 : "Expecting 11: " + m.getPlusOne();
  140.78 +        
  140.79 +        assert sw != null : "StringWriter should be initialized: " + sw;
  140.80 +        
  140.81 +        if (sw.toString().contains("$JsCallbacks$")) {
  140.82 +            assert false : "Don't call for initial value via JsCallbacks:\n" + sw;
  140.83 +        }
  140.84 +    }
  140.85 +}
   141.1 --- a/ko-fx/src/test/resources/org/apidesign/html/kofx/test.html	Mon Dec 16 15:48:09 2013 +0100
   141.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   141.3 @@ -1,56 +0,0 @@
   141.4 -<!--
   141.5 -
   141.6 -    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   141.7 -
   141.8 -    Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   141.9 -
  141.10 -    Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  141.11 -    Other names may be trademarks of their respective owners.
  141.12 -
  141.13 -    The contents of this file are subject to the terms of either the GNU
  141.14 -    General Public License Version 2 only ("GPL") or the Common
  141.15 -    Development and Distribution License("CDDL") (collectively, the
  141.16 -    "License"). You may not use this file except in compliance with the
  141.17 -    License. You can obtain a copy of the License at
  141.18 -    http://www.netbeans.org/cddl-gplv2.html
  141.19 -    or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  141.20 -    specific language governing permissions and limitations under the
  141.21 -    License.  When distributing the software, include this License Header
  141.22 -    Notice in each file and include the License file at
  141.23 -    nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  141.24 -    particular file as subject to the "Classpath" exception as provided
  141.25 -    by Oracle in the GPL Version 2 section of the License file that
  141.26 -    accompanied this code. If applicable, add the following below the
  141.27 -    License Header, with the fields enclosed by brackets [] replaced by
  141.28 -    your own identifying information:
  141.29 -    "Portions Copyrighted [year] [name of copyright owner]"
  141.30 -
  141.31 -    Contributor(s):
  141.32 -
  141.33 -    The Original Software is NetBeans. The Initial Developer of the Original
  141.34 -    Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  141.35 -
  141.36 -    If you wish your version of this file to be governed by only the CDDL
  141.37 -    or only the GPL Version 2, indicate your decision by adding
  141.38 -    "[Contributor] elects to include this software in this distribution
  141.39 -    under the [CDDL or GPL Version 2] license." If you do not indicate a
  141.40 -    single choice of license, a recipient has the option to distribute
  141.41 -    your version of this file under either the CDDL, the GPL Version 2 or
  141.42 -    to extend the choice of license to its licensees as provided above.
  141.43 -    However, if you add GPL Version 2 code and therefore, elected the GPL
  141.44 -    Version 2 license, then the option applies only if the new code is
  141.45 -    made subject to such option by the copyright holder.
  141.46 -
  141.47 --->
  141.48 -<!DOCTYPE html>
  141.49 -<html>
  141.50 -    <head>
  141.51 -        <title>Knockout.fx Execution Harness</title>
  141.52 -        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  141.53 -        <meta name="viewport" content="width=device-width">
  141.54 -    </head>
  141.55 -    <body>
  141.56 -        <h1>Knockout.fx Execution Harness</h1>
  141.57 -    </body>
  141.58 -    <script></script>
  141.59 -</html>
   142.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   142.2 +++ b/ko-fx/src/test/resources/org/netbeans/html/kofx/test.html	Mon Dec 16 16:59:43 2013 +0100
   142.3 @@ -0,0 +1,56 @@
   142.4 +<!--
   142.5 +
   142.6 +    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   142.7 +
   142.8 +    Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   142.9 +
  142.10 +    Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  142.11 +    Other names may be trademarks of their respective owners.
  142.12 +
  142.13 +    The contents of this file are subject to the terms of either the GNU
  142.14 +    General Public License Version 2 only ("GPL") or the Common
  142.15 +    Development and Distribution License("CDDL") (collectively, the
  142.16 +    "License"). You may not use this file except in compliance with the
  142.17 +    License. You can obtain a copy of the License at
  142.18 +    http://www.netbeans.org/cddl-gplv2.html
  142.19 +    or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  142.20 +    specific language governing permissions and limitations under the
  142.21 +    License.  When distributing the software, include this License Header
  142.22 +    Notice in each file and include the License file at
  142.23 +    nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  142.24 +    particular file as subject to the "Classpath" exception as provided
  142.25 +    by Oracle in the GPL Version 2 section of the License file that
  142.26 +    accompanied this code. If applicable, add the following below the
  142.27 +    License Header, with the fields enclosed by brackets [] replaced by
  142.28 +    your own identifying information:
  142.29 +    "Portions Copyrighted [year] [name of copyright owner]"
  142.30 +
  142.31 +    Contributor(s):
  142.32 +
  142.33 +    The Original Software is NetBeans. The Initial Developer of the Original
  142.34 +    Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  142.35 +
  142.36 +    If you wish your version of this file to be governed by only the CDDL
  142.37 +    or only the GPL Version 2, indicate your decision by adding
  142.38 +    "[Contributor] elects to include this software in this distribution
  142.39 +    under the [CDDL or GPL Version 2] license." If you do not indicate a
  142.40 +    single choice of license, a recipient has the option to distribute
  142.41 +    your version of this file under either the CDDL, the GPL Version 2 or
  142.42 +    to extend the choice of license to its licensees as provided above.
  142.43 +    However, if you add GPL Version 2 code and therefore, elected the GPL
  142.44 +    Version 2 license, then the option applies only if the new code is
  142.45 +    made subject to such option by the copyright holder.
  142.46 +
  142.47 +-->
  142.48 +<!DOCTYPE html>
  142.49 +<html>
  142.50 +    <head>
  142.51 +        <title>Knockout.fx Execution Harness</title>
  142.52 +        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  142.53 +        <meta name="viewport" content="width=device-width">
  142.54 +    </head>
  142.55 +    <body>
  142.56 +        <h1>Knockout.fx Execution Harness</h1>
  142.57 +    </body>
  142.58 +    <script></script>
  142.59 +</html>
   143.1 --- a/ko-ws-tyrus/src/main/java/org/apidesign/html/wstyrus/TyrusContext.java	Mon Dec 16 15:48:09 2013 +0100
   143.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   143.3 @@ -1,190 +0,0 @@
   143.4 -/**
   143.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   143.6 - *
   143.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   143.8 - *
   143.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  143.10 - * Other names may be trademarks of their respective owners.
  143.11 - *
  143.12 - * The contents of this file are subject to the terms of either the GNU
  143.13 - * General Public License Version 2 only ("GPL") or the Common
  143.14 - * Development and Distribution License("CDDL") (collectively, the
  143.15 - * "License"). You may not use this file except in compliance with the
  143.16 - * License. You can obtain a copy of the License at
  143.17 - * http://www.netbeans.org/cddl-gplv2.html
  143.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  143.19 - * specific language governing permissions and limitations under the
  143.20 - * License.  When distributing the software, include this License Header
  143.21 - * Notice in each file and include the License file at
  143.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  143.23 - * particular file as subject to the "Classpath" exception as provided
  143.24 - * by Oracle in the GPL Version 2 section of the License file that
  143.25 - * accompanied this code. If applicable, add the following below the
  143.26 - * License Header, with the fields enclosed by brackets [] replaced by
  143.27 - * your own identifying information:
  143.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  143.29 - *
  143.30 - * Contributor(s):
  143.31 - *
  143.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  143.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  143.34 - *
  143.35 - * If you wish your version of this file to be governed by only the CDDL
  143.36 - * or only the GPL Version 2, indicate your decision by adding
  143.37 - * "[Contributor] elects to include this software in this distribution
  143.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  143.39 - * single choice of license, a recipient has the option to distribute
  143.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  143.41 - * to extend the choice of license to its licensees as provided above.
  143.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  143.43 - * Version 2 license, then the option applies only if the new code is
  143.44 - * made subject to such option by the copyright holder.
  143.45 - */
  143.46 -package org.apidesign.html.wstyrus;
  143.47 -
  143.48 -import java.io.IOException;
  143.49 -import java.net.URI;
  143.50 -import java.net.URISyntaxException;
  143.51 -import java.util.Iterator;
  143.52 -import javax.websocket.ClientEndpoint;
  143.53 -import javax.websocket.ContainerProvider;
  143.54 -import javax.websocket.DeploymentException;
  143.55 -import javax.websocket.OnClose;
  143.56 -import javax.websocket.OnError;
  143.57 -import javax.websocket.OnMessage;
  143.58 -import javax.websocket.OnOpen;
  143.59 -import javax.websocket.Session;
  143.60 -import javax.websocket.WebSocketContainer;
  143.61 -import net.java.html.json.OnReceive;
  143.62 -import org.apidesign.html.context.spi.Contexts;
  143.63 -import org.apidesign.html.json.spi.JSONCall;
  143.64 -import org.apidesign.html.json.spi.WSTransfer;
  143.65 -import org.apidesign.html.wstyrus.TyrusContext.Comm;
  143.66 -import org.json.JSONArray;
  143.67 -import org.json.JSONException;
  143.68 -import org.json.JSONObject;
  143.69 -import org.json.JSONTokener;
  143.70 -import org.openide.util.lookup.ServiceProvider;
  143.71 -
  143.72 -/** This is an implementation module that provides support for
  143.73 - * WebSocket protocol for {@link OnReceive} communication end point for
  143.74 - * JDK7.
  143.75 - * <p>
  143.76 - * Don't deal with this module directly, rather use the 
  143.77 - * {@link OnReceive @OnReceive(url="ws://...", ...)} API to establish your
  143.78 - * WebSocket connection.
  143.79 - * <p>
  143.80 - * There is no need to include this module in your application if you are
  143.81 - * running on JDK8. JDK8 WebView provides its own implementation of the
  143.82 - * WebSocket API based on WebSocket object inside a browser. This is included
  143.83 - * in the <code>org.apidesign.html:ko-fx:0.5</code> module.
  143.84 - *
  143.85 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  143.86 - */
  143.87 -@ServiceProvider(service = Contexts.Provider.class)
  143.88 -public final class TyrusContext implements Contexts.Provider, WSTransfer<Comm> {
  143.89 -    @Override
  143.90 -    public void fillContext(Contexts.Builder context, Class<?> requestor) {
  143.91 -        // default WebSocket transfer implementation is registered
  143.92 -        // in ko-fx module with 100, provide this one as a fallback only
  143.93 -        context.register(WSTransfer.class, this, 1000);
  143.94 -    }
  143.95 -
  143.96 -    @Override
  143.97 -    public Comm open(String url, JSONCall callback) {
  143.98 -        try {
  143.99 -            return new Comm(new URI(url), callback);
 143.100 -        } catch (URISyntaxException ex) {
 143.101 -            throw new IllegalStateException(ex);
 143.102 -        }
 143.103 -    }
 143.104 -
 143.105 -    @Override
 143.106 -    public void send(Comm socket, JSONCall data) {
 143.107 -        socket.session.getAsyncRemote().sendText(data.getMessage());
 143.108 -    }
 143.109 -
 143.110 -    @Override
 143.111 -    public void close(Comm socket) {
 143.112 -        try {
 143.113 -            final Session s = socket.session;
 143.114 -            if (s != null) {
 143.115 -                s.close();
 143.116 -            }
 143.117 -        } catch (IOException ex) {
 143.118 -            socket.callback.notifyError(ex);
 143.119 -        }
 143.120 -    }
 143.121 -    
 143.122 -    /** Implementation class in an implementation. Represents a {@link ClientEndpoint} of the
 143.123 -     * WebSocket channel. You are unlikely to get on hold of it.
 143.124 -     */
 143.125 -    @ClientEndpoint
 143.126 -    public static final class Comm {
 143.127 -        private final JSONCall callback;
 143.128 -        private Session session;
 143.129 -
 143.130 -        Comm(final URI url, JSONCall callback) {
 143.131 -            this.callback = callback;
 143.132 -            try {
 143.133 -                final WebSocketContainer c = ContainerProvider.getWebSocketContainer();
 143.134 -                c.connectToServer(Comm.this, url);
 143.135 -            } catch (DeploymentException | IOException ex) {
 143.136 -                wasAnError(ex);
 143.137 -            }
 143.138 -        }
 143.139 -
 143.140 -        @OnOpen
 143.141 -        public synchronized void open(Session s) {
 143.142 -            this.session = s;
 143.143 -            callback.notifySuccess(null);
 143.144 -        }
 143.145 -
 143.146 -        @OnClose
 143.147 -        public void close() {
 143.148 -            this.session = null;
 143.149 -            callback.notifyError(null);
 143.150 -        }
 143.151 -
 143.152 -        @OnMessage
 143.153 -        public void message(final String orig, Session s) {
 143.154 -            Object json;
 143.155 -            String data = orig.trim();
 143.156 -            try {
 143.157 -                JSONTokener tok = new JSONTokener(data);
 143.158 -                Object obj = data.startsWith("[") ? new JSONArray(tok) : new JSONObject(tok);
 143.159 -                json = convertToArray(obj);
 143.160 -            } catch (JSONException ex) {
 143.161 -                json = data;
 143.162 -            }
 143.163 -            callback.notifySuccess(json);
 143.164 -        }
 143.165 -
 143.166 -        @OnError
 143.167 -        public void wasAnError(Throwable t) {
 143.168 -            callback.notifyError(t);
 143.169 -        }
 143.170 -
 143.171 -        static Object convertToArray(Object o) throws JSONException {
 143.172 -            if (o instanceof JSONArray) {
 143.173 -                JSONArray ja = (JSONArray) o;
 143.174 -                Object[] arr = new Object[ja.length()];
 143.175 -                for (int i = 0; i < arr.length; i++) {
 143.176 -                    arr[i] = convertToArray(ja.get(i));
 143.177 -                }
 143.178 -                return arr;
 143.179 -            } else if (o instanceof JSONObject) {
 143.180 -                JSONObject obj = (JSONObject) o;
 143.181 -                Iterator it = obj.keys();
 143.182 -                while (it.hasNext()) {
 143.183 -                    String key = (String) it.next();
 143.184 -                    obj.put(key, convertToArray(obj.get(key)));
 143.185 -                }
 143.186 -                return obj;
 143.187 -            } else {
 143.188 -                return o;
 143.189 -            }
 143.190 -        }
 143.191 -        
 143.192 -    } // end of Comm
 143.193 -}
   144.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   144.2 +++ b/ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/TyrusContext.java	Mon Dec 16 16:59:43 2013 +0100
   144.3 @@ -0,0 +1,190 @@
   144.4 +/**
   144.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   144.6 + *
   144.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   144.8 + *
   144.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  144.10 + * Other names may be trademarks of their respective owners.
  144.11 + *
  144.12 + * The contents of this file are subject to the terms of either the GNU
  144.13 + * General Public License Version 2 only ("GPL") or the Common
  144.14 + * Development and Distribution License("CDDL") (collectively, the
  144.15 + * "License"). You may not use this file except in compliance with the
  144.16 + * License. You can obtain a copy of the License at
  144.17 + * http://www.netbeans.org/cddl-gplv2.html
  144.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  144.19 + * specific language governing permissions and limitations under the
  144.20 + * License.  When distributing the software, include this License Header
  144.21 + * Notice in each file and include the License file at
  144.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  144.23 + * particular file as subject to the "Classpath" exception as provided
  144.24 + * by Oracle in the GPL Version 2 section of the License file that
  144.25 + * accompanied this code. If applicable, add the following below the
  144.26 + * License Header, with the fields enclosed by brackets [] replaced by
  144.27 + * your own identifying information:
  144.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  144.29 + *
  144.30 + * Contributor(s):
  144.31 + *
  144.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  144.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  144.34 + *
  144.35 + * If you wish your version of this file to be governed by only the CDDL
  144.36 + * or only the GPL Version 2, indicate your decision by adding
  144.37 + * "[Contributor] elects to include this software in this distribution
  144.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  144.39 + * single choice of license, a recipient has the option to distribute
  144.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  144.41 + * to extend the choice of license to its licensees as provided above.
  144.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  144.43 + * Version 2 license, then the option applies only if the new code is
  144.44 + * made subject to such option by the copyright holder.
  144.45 + */
  144.46 +package org.netbeans.html.wstyrus;
  144.47 +
  144.48 +import java.io.IOException;
  144.49 +import java.net.URI;
  144.50 +import java.net.URISyntaxException;
  144.51 +import java.util.Iterator;
  144.52 +import javax.websocket.ClientEndpoint;
  144.53 +import javax.websocket.ContainerProvider;
  144.54 +import javax.websocket.DeploymentException;
  144.55 +import javax.websocket.OnClose;
  144.56 +import javax.websocket.OnError;
  144.57 +import javax.websocket.OnMessage;
  144.58 +import javax.websocket.OnOpen;
  144.59 +import javax.websocket.Session;
  144.60 +import javax.websocket.WebSocketContainer;
  144.61 +import net.java.html.json.OnReceive;
  144.62 +import org.apidesign.html.context.spi.Contexts;
  144.63 +import org.apidesign.html.json.spi.JSONCall;
  144.64 +import org.apidesign.html.json.spi.WSTransfer;
  144.65 +import org.netbeans.html.wstyrus.TyrusContext.Comm;
  144.66 +import org.json.JSONArray;
  144.67 +import org.json.JSONException;
  144.68 +import org.json.JSONObject;
  144.69 +import org.json.JSONTokener;
  144.70 +import org.openide.util.lookup.ServiceProvider;
  144.71 +
  144.72 +/** This is an implementation module that provides support for
  144.73 + * WebSocket protocol for {@link OnReceive} communication end point for
  144.74 + * JDK7.
  144.75 + * <p>
  144.76 + * Don't deal with this module directly, rather use the 
  144.77 + * {@link OnReceive @OnReceive(url="ws://...", ...)} API to establish your
  144.78 + * WebSocket connection.
  144.79 + * <p>
  144.80 + * There is no need to include this module in your application if you are
  144.81 + * running on JDK8. JDK8 WebView provides its own implementation of the
  144.82 + * WebSocket API based on WebSocket object inside a browser. This is included
  144.83 + * in the <code>org.apidesign.html:ko-fx:0.5</code> module.
  144.84 + *
  144.85 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  144.86 + */
  144.87 +@ServiceProvider(service = Contexts.Provider.class)
  144.88 +public final class TyrusContext implements Contexts.Provider, WSTransfer<Comm> {
  144.89 +    @Override
  144.90 +    public void fillContext(Contexts.Builder context, Class<?> requestor) {
  144.91 +        // default WebSocket transfer implementation is registered
  144.92 +        // in ko-fx module with 100, provide this one as a fallback only
  144.93 +        context.register(WSTransfer.class, this, 1000);
  144.94 +    }
  144.95 +
  144.96 +    @Override
  144.97 +    public Comm open(String url, JSONCall callback) {
  144.98 +        try {
  144.99 +            return new Comm(new URI(url), callback);
 144.100 +        } catch (URISyntaxException ex) {
 144.101 +            throw new IllegalStateException(ex);
 144.102 +        }
 144.103 +    }
 144.104 +
 144.105 +    @Override
 144.106 +    public void send(Comm socket, JSONCall data) {
 144.107 +        socket.session.getAsyncRemote().sendText(data.getMessage());
 144.108 +    }
 144.109 +
 144.110 +    @Override
 144.111 +    public void close(Comm socket) {
 144.112 +        try {
 144.113 +            final Session s = socket.session;
 144.114 +            if (s != null) {
 144.115 +                s.close();
 144.116 +            }
 144.117 +        } catch (IOException ex) {
 144.118 +            socket.callback.notifyError(ex);
 144.119 +        }
 144.120 +    }
 144.121 +    
 144.122 +    /** Implementation class in an implementation. Represents a {@link ClientEndpoint} of the
 144.123 +     * WebSocket channel. You are unlikely to get on hold of it.
 144.124 +     */
 144.125 +    @ClientEndpoint
 144.126 +    public static final class Comm {
 144.127 +        private final JSONCall callback;
 144.128 +        private Session session;
 144.129 +
 144.130 +        Comm(final URI url, JSONCall callback) {
 144.131 +            this.callback = callback;
 144.132 +            try {
 144.133 +                final WebSocketContainer c = ContainerProvider.getWebSocketContainer();
 144.134 +                c.connectToServer(Comm.this, url);
 144.135 +            } catch (DeploymentException | IOException ex) {
 144.136 +                wasAnError(ex);
 144.137 +            }
 144.138 +        }
 144.139 +
 144.140 +        @OnOpen
 144.141 +        public synchronized void open(Session s) {
 144.142 +            this.session = s;
 144.143 +            callback.notifySuccess(null);
 144.144 +        }
 144.145 +
 144.146 +        @OnClose
 144.147 +        public void close() {
 144.148 +            this.session = null;
 144.149 +            callback.notifyError(null);
 144.150 +        }
 144.151 +
 144.152 +        @OnMessage
 144.153 +        public void message(final String orig, Session s) {
 144.154 +            Object json;
 144.155 +            String data = orig.trim();
 144.156 +            try {
 144.157 +                JSONTokener tok = new JSONTokener(data);
 144.158 +                Object obj = data.startsWith("[") ? new JSONArray(tok) : new JSONObject(tok);
 144.159 +                json = convertToArray(obj);
 144.160 +            } catch (JSONException ex) {
 144.161 +                json = data;
 144.162 +            }
 144.163 +            callback.notifySuccess(json);
 144.164 +        }
 144.165 +
 144.166 +        @OnError
 144.167 +        public void wasAnError(Throwable t) {
 144.168 +            callback.notifyError(t);
 144.169 +        }
 144.170 +
 144.171 +        static Object convertToArray(Object o) throws JSONException {
 144.172 +            if (o instanceof JSONArray) {
 144.173 +                JSONArray ja = (JSONArray) o;
 144.174 +                Object[] arr = new Object[ja.length()];
 144.175 +                for (int i = 0; i < arr.length; i++) {
 144.176 +                    arr[i] = convertToArray(ja.get(i));
 144.177 +                }
 144.178 +                return arr;
 144.179 +            } else if (o instanceof JSONObject) {
 144.180 +                JSONObject obj = (JSONObject) o;
 144.181 +                Iterator it = obj.keys();
 144.182 +                while (it.hasNext()) {
 144.183 +                    String key = (String) it.next();
 144.184 +                    obj.put(key, convertToArray(obj.get(key)));
 144.185 +                }
 144.186 +                return obj;
 144.187 +            } else {
 144.188 +                return o;
 144.189 +            }
 144.190 +        }
 144.191 +        
 144.192 +    } // end of Comm
 144.193 +}
   145.1 --- a/ko-ws-tyrus/src/test/java/org/apidesign/html/wstyrus/TyrusDynamicHTTP.java	Mon Dec 16 15:48:09 2013 +0100
   145.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   145.3 @@ -1,260 +0,0 @@
   145.4 -/**
   145.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   145.6 - *
   145.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   145.8 - *
   145.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  145.10 - * Other names may be trademarks of their respective owners.
  145.11 - *
  145.12 - * The contents of this file are subject to the terms of either the GNU
  145.13 - * General Public License Version 2 only ("GPL") or the Common
  145.14 - * Development and Distribution License("CDDL") (collectively, the
  145.15 - * "License"). You may not use this file except in compliance with the
  145.16 - * License. You can obtain a copy of the License at
  145.17 - * http://www.netbeans.org/cddl-gplv2.html
  145.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  145.19 - * specific language governing permissions and limitations under the
  145.20 - * License.  When distributing the software, include this License Header
  145.21 - * Notice in each file and include the License file at
  145.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  145.23 - * particular file as subject to the "Classpath" exception as provided
  145.24 - * by Oracle in the GPL Version 2 section of the License file that
  145.25 - * accompanied this code. If applicable, add the following below the
  145.26 - * License Header, with the fields enclosed by brackets [] replaced by
  145.27 - * your own identifying information:
  145.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  145.29 - *
  145.30 - * Contributor(s):
  145.31 - *
  145.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  145.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  145.34 - *
  145.35 - * If you wish your version of this file to be governed by only the CDDL
  145.36 - * or only the GPL Version 2, indicate your decision by adding
  145.37 - * "[Contributor] elects to include this software in this distribution
  145.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  145.39 - * single choice of license, a recipient has the option to distribute
  145.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  145.41 - * to extend the choice of license to its licensees as provided above.
  145.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  145.43 - * Version 2 license, then the option applies only if the new code is
  145.44 - * made subject to such option by the copyright holder.
  145.45 - */
  145.46 -package org.apidesign.html.wstyrus;
  145.47 -
  145.48 -import java.io.ByteArrayInputStream;
  145.49 -import java.io.ByteArrayOutputStream;
  145.50 -import java.io.IOException;
  145.51 -import java.io.InputStream;
  145.52 -import java.io.OutputStream;
  145.53 -import java.io.Reader;
  145.54 -import java.net.URI;
  145.55 -import java.net.URISyntaxException;
  145.56 -import java.util.ArrayList;
  145.57 -import java.util.List;
  145.58 -import java.util.logging.Level;
  145.59 -import java.util.logging.Logger;
  145.60 -import org.glassfish.grizzly.PortRange;
  145.61 -import org.glassfish.grizzly.http.server.HttpHandler;
  145.62 -import org.glassfish.grizzly.http.server.HttpServer;
  145.63 -import org.glassfish.grizzly.http.server.NetworkListener;
  145.64 -import org.glassfish.grizzly.http.server.Request;
  145.65 -import org.glassfish.grizzly.http.server.Response;
  145.66 -import org.glassfish.grizzly.http.server.ServerConfiguration;
  145.67 -import org.glassfish.grizzly.websockets.WebSocket;
  145.68 -import org.glassfish.grizzly.websockets.WebSocketAddOn;
  145.69 -import org.glassfish.grizzly.websockets.WebSocketApplication;
  145.70 -import org.glassfish.grizzly.websockets.WebSocketEngine;
  145.71 -
  145.72 -/**
  145.73 - *
  145.74 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  145.75 - */
  145.76 -final class TyrusDynamicHTTP extends HttpHandler {
  145.77 -    private static int resourcesCount;
  145.78 -    private static List<Resource> resources;
  145.79 -    private static ServerConfiguration conf;
  145.80 -    private static HttpServer server;
  145.81 -    
  145.82 -    private TyrusDynamicHTTP() {
  145.83 -    }
  145.84 -    
  145.85 -    static URI initServer() throws Exception {
  145.86 -        server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
  145.87 -        final WebSocketAddOn addon = new WebSocketAddOn();
  145.88 -        for (NetworkListener listener : server.getListeners()) {
  145.89 -            listener.registerAddOn(addon);
  145.90 -        }        
  145.91 -        resources = new ArrayList<Resource>();
  145.92 -
  145.93 -        conf = server.getServerConfiguration();
  145.94 -        final TyrusDynamicHTTP dh = new TyrusDynamicHTTP();
  145.95 -
  145.96 -        conf.addHttpHandler(dh, "/");
  145.97 -        
  145.98 -        server.start();
  145.99 -
 145.100 -        return pageURL("http", server, "/test.html");
 145.101 -    }
 145.102 -    
 145.103 -    @Override
 145.104 -    public void service(Request request, Response response) throws Exception {
 145.105 -        if ("/test.html".equals(request.getRequestURI())) {
 145.106 -            response.setContentType("text/html");
 145.107 -            final InputStream is = TyrusDynamicHTTP.class.getResourceAsStream("test.html");
 145.108 -            copyStream(is, response.getOutputStream(), null);
 145.109 -            return;
 145.110 -        }
 145.111 -        if ("/dynamic".equals(request.getRequestURI())) {
 145.112 -            String mimeType = request.getParameter("mimeType");
 145.113 -            List<String> params = new ArrayList<String>();
 145.114 -            boolean webSocket = false;
 145.115 -            for (int i = 0;; i++) {
 145.116 -                String p = request.getParameter("param" + i);
 145.117 -                if (p == null) {
 145.118 -                    break;
 145.119 -                }
 145.120 -                if ("protocol:ws".equals(p)) {
 145.121 -                    webSocket = true;
 145.122 -                    continue;
 145.123 -                }
 145.124 -                params.add(p);
 145.125 -            }
 145.126 -            final String cnt = request.getParameter("content");
 145.127 -            String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
 145.128 -            ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
 145.129 -            URI url;
 145.130 -            final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
 145.131 -            if (webSocket) {
 145.132 -                url = registerWebSocket(res);
 145.133 -            } else {
 145.134 -                url = registerResource(res);
 145.135 -            }
 145.136 -            response.getWriter().write(url.toString());
 145.137 -            response.getWriter().write("\n");
 145.138 -            return;
 145.139 -        }
 145.140 -
 145.141 -        for (Resource r : resources) {
 145.142 -            if (r.httpPath.equals(request.getRequestURI())) {
 145.143 -                response.setContentType(r.httpType);
 145.144 -                r.httpContent.reset();
 145.145 -                String[] params = null;
 145.146 -                if (r.parameters.length != 0) {
 145.147 -                    params = new String[r.parameters.length];
 145.148 -                    for (int i = 0; i < r.parameters.length; i++) {
 145.149 -                        params[i] = request.getParameter(r.parameters[i]);
 145.150 -                        if (params[i] == null) {
 145.151 -                            if ("http.method".equals(r.parameters[i])) {
 145.152 -                                params[i] = request.getMethod().toString();
 145.153 -                            } else if ("http.requestBody".equals(r.parameters[i])) {
 145.154 -                                Reader rdr = request.getReader();
 145.155 -                                StringBuilder sb = new StringBuilder();
 145.156 -                                for (;;) {
 145.157 -                                    int ch = rdr.read();
 145.158 -                                    if (ch == -1) {
 145.159 -                                        break;
 145.160 -                                    }
 145.161 -                                    sb.append((char) ch);
 145.162 -                                }
 145.163 -                                params[i] = sb.toString();
 145.164 -                            }
 145.165 -                        }
 145.166 -                        if (params[i] == null) {
 145.167 -                            params[i] = "null";
 145.168 -                        }
 145.169 -                    }
 145.170 -                }
 145.171 -
 145.172 -                copyStream(r.httpContent, response.getOutputStream(), null, params);
 145.173 -            }
 145.174 -        }
 145.175 -    }
 145.176 -    
 145.177 -    private URI registerWebSocket(Resource r) {
 145.178 -        WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
 145.179 -        return pageURL("ws", server, r.httpPath);
 145.180 -    }
 145.181 -
 145.182 -    private URI registerResource(Resource r) {
 145.183 -        if (!resources.contains(r)) {
 145.184 -            resources.add(r);
 145.185 -            conf.addHttpHandler(this, r.httpPath);
 145.186 -        }
 145.187 -        return pageURL("http", server, r.httpPath);
 145.188 -    }
 145.189 -    
 145.190 -    private static URI pageURL(String proto, HttpServer server, final String page) {
 145.191 -        NetworkListener listener = server.getListeners().iterator().next();
 145.192 -        int port = listener.getPort();
 145.193 -        try {
 145.194 -            return new URI(proto + "://localhost:" + port + page);
 145.195 -        } catch (URISyntaxException ex) {
 145.196 -            throw new IllegalStateException(ex);
 145.197 -        }
 145.198 -    }
 145.199 -    
 145.200 -    static final class Resource {
 145.201 -
 145.202 -        final InputStream httpContent;
 145.203 -        final String httpType;
 145.204 -        final String httpPath;
 145.205 -        final String[] parameters;
 145.206 -
 145.207 -        Resource(InputStream httpContent, String httpType, String httpPath,
 145.208 -            String[] parameters) {
 145.209 -            httpContent.mark(Integer.MAX_VALUE);
 145.210 -            this.httpContent = httpContent;
 145.211 -            this.httpType = httpType;
 145.212 -            this.httpPath = httpPath;
 145.213 -            this.parameters = parameters;
 145.214 -        }
 145.215 -    }
 145.216 -
 145.217 -    static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
 145.218 -        for (;;) {
 145.219 -            int ch = is.read();
 145.220 -            if (ch == -1) {
 145.221 -                break;
 145.222 -            }
 145.223 -            if (ch == '$' && params.length > 0) {
 145.224 -                int cnt = is.read() - '0';
 145.225 -                if (baseURL != null && cnt == 'U' - '0') {
 145.226 -                    os.write(baseURL.getBytes("UTF-8"));
 145.227 -                } else {
 145.228 -                    if (cnt >= 0 && cnt < params.length) {
 145.229 -                        os.write(params[cnt].getBytes("UTF-8"));
 145.230 -                    } else {
 145.231 -                        os.write('$');
 145.232 -                        os.write(cnt + '0');
 145.233 -                    }
 145.234 -                }
 145.235 -            } else {
 145.236 -                os.write(ch);
 145.237 -            }
 145.238 -        }
 145.239 -    }
 145.240 -    
 145.241 -    private static class WS extends WebSocketApplication {
 145.242 -        private final Resource r;
 145.243 -
 145.244 -        private WS(Resource r) {
 145.245 -            this.r = r;
 145.246 -        }
 145.247 -
 145.248 -        @Override
 145.249 -        public void onMessage(WebSocket socket, String text) {
 145.250 -            try {
 145.251 -                r.httpContent.reset();
 145.252 -                ByteArrayOutputStream out = new ByteArrayOutputStream();
 145.253 -                copyStream(r.httpContent, out, null, text);
 145.254 -                String s = new String(out.toByteArray(), "UTF-8");
 145.255 -                socket.send(s);
 145.256 -            } catch (IOException ex) {
 145.257 -                LOG.log(Level.WARNING, null, ex);
 145.258 -            }
 145.259 -        }
 145.260 -        private static final Logger LOG = Logger.getLogger(WS.class.getName());
 145.261 -        
 145.262 -    }
 145.263 -}
   146.1 --- a/ko-ws-tyrus/src/test/java/org/apidesign/html/wstyrus/TyrusFX.java	Mon Dec 16 15:48:09 2013 +0100
   146.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   146.3 @@ -1,120 +0,0 @@
   146.4 -/**
   146.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   146.6 - *
   146.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   146.8 - *
   146.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  146.10 - * Other names may be trademarks of their respective owners.
  146.11 - *
  146.12 - * The contents of this file are subject to the terms of either the GNU
  146.13 - * General Public License Version 2 only ("GPL") or the Common
  146.14 - * Development and Distribution License("CDDL") (collectively, the
  146.15 - * "License"). You may not use this file except in compliance with the
  146.16 - * License. You can obtain a copy of the License at
  146.17 - * http://www.netbeans.org/cddl-gplv2.html
  146.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  146.19 - * specific language governing permissions and limitations under the
  146.20 - * License.  When distributing the software, include this License Header
  146.21 - * Notice in each file and include the License file at
  146.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  146.23 - * particular file as subject to the "Classpath" exception as provided
  146.24 - * by Oracle in the GPL Version 2 section of the License file that
  146.25 - * accompanied this code. If applicable, add the following below the
  146.26 - * License Header, with the fields enclosed by brackets [] replaced by
  146.27 - * your own identifying information:
  146.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  146.29 - *
  146.30 - * Contributor(s):
  146.31 - *
  146.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  146.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  146.34 - *
  146.35 - * If you wish your version of this file to be governed by only the CDDL
  146.36 - * or only the GPL Version 2, indicate your decision by adding
  146.37 - * "[Contributor] elects to include this software in this distribution
  146.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  146.39 - * single choice of license, a recipient has the option to distribute
  146.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  146.41 - * to extend the choice of license to its licensees as provided above.
  146.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  146.43 - * Version 2 license, then the option applies only if the new code is
  146.44 - * made subject to such option by the copyright holder.
  146.45 - */
  146.46 -package org.apidesign.html.wstyrus;
  146.47 -
  146.48 -import java.lang.reflect.InvocationTargetException;
  146.49 -import java.lang.reflect.Method;
  146.50 -import javafx.application.Platform;
  146.51 -import org.apidesign.html.boot.impl.FnContext;
  146.52 -import org.apidesign.html.boot.spi.Fn;
  146.53 -import org.testng.ITest;
  146.54 -import org.testng.annotations.Test;
  146.55 -
  146.56 -/**
  146.57 - *
  146.58 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  146.59 - */
  146.60 -public final class TyrusFX implements ITest, Runnable {
  146.61 -    private final Fn.Presenter p;
  146.62 -    private final Method m;
  146.63 -    private Object result;
  146.64 -    private Object inst;
  146.65 -    private int count;
  146.66 -
  146.67 -    TyrusFX(Fn.Presenter p, Method m) {
  146.68 -        this.p = p;
  146.69 -        this.m = m;
  146.70 -    }
  146.71 -
  146.72 -    @Override
  146.73 -    public String getTestName() {
  146.74 -        return m.getName();
  146.75 -    }
  146.76 -
  146.77 -    @Test
  146.78 -    public synchronized void executeTest() throws Exception {
  146.79 -        if (result == null) {
  146.80 -            Platform.runLater(this);
  146.81 -            wait();
  146.82 -        }
  146.83 -        if (result instanceof Exception) {
  146.84 -            throw (Exception)result;
  146.85 -        }
  146.86 -        if (result instanceof Error) {
  146.87 -            throw (Error)result;
  146.88 -        }
  146.89 -    }
  146.90 -
  146.91 -    @Override
  146.92 -    public synchronized void run() {
  146.93 -        boolean notify = true;
  146.94 -        try {
  146.95 -            FnContext.currentPresenter(p);
  146.96 -            if (inst == null) {
  146.97 -                inst = m.getDeclaringClass().newInstance();
  146.98 -            }
  146.99 -            result = m.invoke(inst);
 146.100 -            if (result == null) {
 146.101 -                result = this;
 146.102 -            }
 146.103 -        } catch (InvocationTargetException ex) {
 146.104 -            Throwable r = ex.getTargetException();
 146.105 -            if (r instanceof InterruptedException) {
 146.106 -                if (count++ < 10000) {
 146.107 -                    notify = false;
 146.108 -                    Platform.runLater(this);
 146.109 -                    return;
 146.110 -                }
 146.111 -            }
 146.112 -            result = r;
 146.113 -        } catch (Exception ex) {
 146.114 -            result = ex;
 146.115 -        } finally {
 146.116 -            if (notify) {
 146.117 -                notifyAll();
 146.118 -            }
 146.119 -            FnContext.currentPresenter(null);
 146.120 -        }
 146.121 -    }
 146.122 -    
 146.123 -}
   147.1 --- a/ko-ws-tyrus/src/test/java/org/apidesign/html/wstyrus/TyrusKnockoutTest.java	Mon Dec 16 15:48:09 2013 +0100
   147.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   147.3 @@ -1,213 +0,0 @@
   147.4 -/**
   147.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   147.6 - *
   147.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   147.8 - *
   147.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  147.10 - * Other names may be trademarks of their respective owners.
  147.11 - *
  147.12 - * The contents of this file are subject to the terms of either the GNU
  147.13 - * General Public License Version 2 only ("GPL") or the Common
  147.14 - * Development and Distribution License("CDDL") (collectively, the
  147.15 - * "License"). You may not use this file except in compliance with the
  147.16 - * License. You can obtain a copy of the License at
  147.17 - * http://www.netbeans.org/cddl-gplv2.html
  147.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  147.19 - * specific language governing permissions and limitations under the
  147.20 - * License.  When distributing the software, include this License Header
  147.21 - * Notice in each file and include the License file at
  147.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  147.23 - * particular file as subject to the "Classpath" exception as provided
  147.24 - * by Oracle in the GPL Version 2 section of the License file that
  147.25 - * accompanied this code. If applicable, add the following below the
  147.26 - * License Header, with the fields enclosed by brackets [] replaced by
  147.27 - * your own identifying information:
  147.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  147.29 - *
  147.30 - * Contributor(s):
  147.31 - *
  147.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  147.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  147.34 - *
  147.35 - * If you wish your version of this file to be governed by only the CDDL
  147.36 - * or only the GPL Version 2, indicate your decision by adding
  147.37 - * "[Contributor] elects to include this software in this distribution
  147.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  147.39 - * single choice of license, a recipient has the option to distribute
  147.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  147.41 - * to extend the choice of license to its licensees as provided above.
  147.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  147.43 - * Version 2 license, then the option applies only if the new code is
  147.44 - * made subject to such option by the copyright holder.
  147.45 - */
  147.46 -package org.apidesign.html.wstyrus;
  147.47 -
  147.48 -import java.io.BufferedReader;
  147.49 -import java.io.IOException;
  147.50 -import java.io.InputStreamReader;
  147.51 -import java.lang.annotation.Annotation;
  147.52 -import java.lang.reflect.Method;
  147.53 -import java.net.URI;
  147.54 -import java.net.URISyntaxException;
  147.55 -import java.net.URL;
  147.56 -import java.net.URLConnection;
  147.57 -import java.util.ArrayList;
  147.58 -import java.util.List;
  147.59 -import java.util.Map;
  147.60 -import java.util.concurrent.Executors;
  147.61 -import net.java.html.BrwsrCtx;
  147.62 -import net.java.html.boot.BrowserBuilder;
  147.63 -import net.java.html.js.JavaScriptBody;
  147.64 -import org.apidesign.html.boot.impl.FnContext;
  147.65 -import org.apidesign.html.boot.impl.FnUtils;
  147.66 -import org.apidesign.html.boot.spi.Fn;
  147.67 -import org.apidesign.html.context.spi.Contexts;
  147.68 -import org.apidesign.html.json.spi.Technology;
  147.69 -import org.apidesign.html.json.spi.Transfer;
  147.70 -import org.apidesign.html.json.spi.WSTransfer;
  147.71 -import org.apidesign.html.json.tck.KOTest;
  147.72 -import org.apidesign.html.json.tck.KnockoutTCK;
  147.73 -import org.apidesign.html.kofx.FXContext;
  147.74 -import org.json.JSONException;
  147.75 -import org.json.JSONObject;
  147.76 -import org.openide.util.lookup.ServiceProvider;
  147.77 -import org.testng.annotations.Factory;
  147.78 -import static org.testng.Assert.*;
  147.79 -
  147.80 -/**
  147.81 - *
  147.82 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  147.83 - */
  147.84 -@ServiceProvider(service = KnockoutTCK.class)
  147.85 -public final class TyrusKnockoutTest extends KnockoutTCK {
  147.86 -    private static Class<?> browserClass;
  147.87 -    private static Fn.Presenter browserContext;
  147.88 -    
  147.89 -    public TyrusKnockoutTest() {
  147.90 -    }
  147.91 -    
  147.92 -    @Factory public static Object[] compatibilityTests() throws Exception {
  147.93 -        Class[] arr = testClasses();
  147.94 -        for (int i = 0; i < arr.length; i++) {
  147.95 -            assertEquals(
  147.96 -                arr[i].getClassLoader(),
  147.97 -                TyrusKnockoutTest.class.getClassLoader(),
  147.98 -                "All classes loaded by the same classloader"
  147.99 -            );
 147.100 -        }
 147.101 -        
 147.102 -        URI uri = TyrusDynamicHTTP.initServer();
 147.103 -    
 147.104 -        final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(TyrusKnockoutTest.class).
 147.105 -            loadPage(uri.toString()).
 147.106 -            invoke("initialized");
 147.107 -        
 147.108 -        Executors.newSingleThreadExecutor().submit(new Runnable() {
 147.109 -            @Override
 147.110 -            public void run() {
 147.111 -                bb.showAndWait();
 147.112 -            }
 147.113 -        });
 147.114 -        
 147.115 -        ClassLoader l = getClassLoader();
 147.116 -        List<Object> res = new ArrayList<Object>();
 147.117 -        for (int i = 0; i < arr.length; i++) {
 147.118 -            Class<?> c = Class.forName(arr[i].getName(), true, l);
 147.119 -            Class<? extends Annotation> koTest = 
 147.120 -                c.getClassLoader().loadClass(KOTest.class.getName()).
 147.121 -                asSubclass(Annotation.class);
 147.122 -            for (Method m : c.getMethods()) {
 147.123 -                if (m.getAnnotation(koTest) != null) {
 147.124 -                    res.add(new TyrusFX(browserContext, m));
 147.125 -                }
 147.126 -            }
 147.127 -        }
 147.128 -        return res.toArray();
 147.129 -    }
 147.130 -
 147.131 -    static synchronized ClassLoader getClassLoader() throws InterruptedException {
 147.132 -        while (browserClass == null) {
 147.133 -            TyrusKnockoutTest.class.wait();
 147.134 -        }
 147.135 -        return browserClass.getClassLoader();
 147.136 -    }
 147.137 -    
 147.138 -    public static synchronized void initialized(Class<?> browserCls) throws Exception {
 147.139 -        browserClass = browserCls;
 147.140 -        browserContext = FnContext.currentPresenter();
 147.141 -        TyrusKnockoutTest.class.notifyAll();
 147.142 -    }
 147.143 -    
 147.144 -    public static void initialized() throws Exception {
 147.145 -        Class<?> classpathClass = ClassLoader.getSystemClassLoader().loadClass(TyrusKnockoutTest.class.getName());
 147.146 -        Method m = classpathClass.getMethod("initialized", Class.class);
 147.147 -        m.invoke(null, TyrusKnockoutTest.class);
 147.148 -        browserContext = FnContext.currentPresenter();
 147.149 -    }
 147.150 -    
 147.151 -    @Override
 147.152 -    public BrwsrCtx createContext() {
 147.153 -        FXContext fx = new FXContext(browserContext);
 147.154 -        TyrusContext tc = new TyrusContext();
 147.155 -        Contexts.Builder cb = Contexts.newBuilder().
 147.156 -            register(Technology.class, fx, 10).
 147.157 -            register(Transfer.class, fx, 10).
 147.158 -            register(WSTransfer.class, tc, 10);
 147.159 -        return cb.build();
 147.160 -    }
 147.161 -
 147.162 -    @Override
 147.163 -    public Object createJSON(Map<String, Object> values) {
 147.164 -        JSONObject json = new JSONObject();
 147.165 -        for (Map.Entry<String, Object> entry : values.entrySet()) {
 147.166 -            try {
 147.167 -                json.put(entry.getKey(), entry.getValue());
 147.168 -            } catch (JSONException ex) {
 147.169 -                throw new IllegalStateException(ex);
 147.170 -            }
 147.171 -        }
 147.172 -        return json;
 147.173 -    }
 147.174 -
 147.175 -    @Override
 147.176 -    @JavaScriptBody(args = { "s", "args" }, body = ""
 147.177 -        + "var f = new Function(s); "
 147.178 -        + "return f.apply(null, args);"
 147.179 -    )
 147.180 -    public native Object executeScript(String script, Object[] arguments);
 147.181 -
 147.182 -    @JavaScriptBody(args = {  }, body = 
 147.183 -          "var h;"
 147.184 -        + "if (!!window && !!window.location && !!window.location.href)\n"
 147.185 -        + "  h = window.location.href;\n"
 147.186 -        + "else "
 147.187 -        + "  h = null;"
 147.188 -        + "return h;\n"
 147.189 -    )
 147.190 -    private static native String findBaseURL();
 147.191 -    
 147.192 -    @Override
 147.193 -    public URI prepareURL(String content, String mimeType, String[] parameters) {
 147.194 -        try {
 147.195 -            final URL baseURL = new URL(findBaseURL());
 147.196 -            StringBuilder sb = new StringBuilder();
 147.197 -            sb.append("/dynamic?mimeType=").append(mimeType);
 147.198 -            for (int i = 0; i < parameters.length; i++) {
 147.199 -                sb.append("&param" + i).append("=").append(parameters[i]);
 147.200 -            }
 147.201 -            String mangle = content.replace("\n", "%0a")
 147.202 -                .replace("\"", "\\\"").replace(" ", "%20");
 147.203 -            sb.append("&content=").append(mangle);
 147.204 -
 147.205 -            URL query = new URL(baseURL, sb.toString());
 147.206 -            URLConnection c = query.openConnection();
 147.207 -            BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
 147.208 -            URI connectTo = new URI(br.readLine());
 147.209 -            return connectTo;
 147.210 -        } catch (IOException ex) {
 147.211 -            throw new IllegalStateException(ex);
 147.212 -        } catch (URISyntaxException ex) {
 147.213 -            throw new IllegalStateException(ex);
 147.214 -        }
 147.215 -    }
 147.216 -}
   148.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   148.2 +++ b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusDynamicHTTP.java	Mon Dec 16 16:59:43 2013 +0100
   148.3 @@ -0,0 +1,260 @@
   148.4 +/**
   148.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   148.6 + *
   148.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   148.8 + *
   148.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  148.10 + * Other names may be trademarks of their respective owners.
  148.11 + *
  148.12 + * The contents of this file are subject to the terms of either the GNU
  148.13 + * General Public License Version 2 only ("GPL") or the Common
  148.14 + * Development and Distribution License("CDDL") (collectively, the
  148.15 + * "License"). You may not use this file except in compliance with the
  148.16 + * License. You can obtain a copy of the License at
  148.17 + * http://www.netbeans.org/cddl-gplv2.html
  148.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  148.19 + * specific language governing permissions and limitations under the
  148.20 + * License.  When distributing the software, include this License Header
  148.21 + * Notice in each file and include the License file at
  148.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  148.23 + * particular file as subject to the "Classpath" exception as provided
  148.24 + * by Oracle in the GPL Version 2 section of the License file that
  148.25 + * accompanied this code. If applicable, add the following below the
  148.26 + * License Header, with the fields enclosed by brackets [] replaced by
  148.27 + * your own identifying information:
  148.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  148.29 + *
  148.30 + * Contributor(s):
  148.31 + *
  148.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  148.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  148.34 + *
  148.35 + * If you wish your version of this file to be governed by only the CDDL
  148.36 + * or only the GPL Version 2, indicate your decision by adding
  148.37 + * "[Contributor] elects to include this software in this distribution
  148.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  148.39 + * single choice of license, a recipient has the option to distribute
  148.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  148.41 + * to extend the choice of license to its licensees as provided above.
  148.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  148.43 + * Version 2 license, then the option applies only if the new code is
  148.44 + * made subject to such option by the copyright holder.
  148.45 + */
  148.46 +package org.netbeans.html.wstyrus;
  148.47 +
  148.48 +import java.io.ByteArrayInputStream;
  148.49 +import java.io.ByteArrayOutputStream;
  148.50 +import java.io.IOException;
  148.51 +import java.io.InputStream;
  148.52 +import java.io.OutputStream;
  148.53 +import java.io.Reader;
  148.54 +import java.net.URI;
  148.55 +import java.net.URISyntaxException;
  148.56 +import java.util.ArrayList;
  148.57 +import java.util.List;
  148.58 +import java.util.logging.Level;
  148.59 +import java.util.logging.Logger;
  148.60 +import org.glassfish.grizzly.PortRange;
  148.61 +import org.glassfish.grizzly.http.server.HttpHandler;
  148.62 +import org.glassfish.grizzly.http.server.HttpServer;
  148.63 +import org.glassfish.grizzly.http.server.NetworkListener;
  148.64 +import org.glassfish.grizzly.http.server.Request;
  148.65 +import org.glassfish.grizzly.http.server.Response;
  148.66 +import org.glassfish.grizzly.http.server.ServerConfiguration;
  148.67 +import org.glassfish.grizzly.websockets.WebSocket;
  148.68 +import org.glassfish.grizzly.websockets.WebSocketAddOn;
  148.69 +import org.glassfish.grizzly.websockets.WebSocketApplication;
  148.70 +import org.glassfish.grizzly.websockets.WebSocketEngine;
  148.71 +
  148.72 +/**
  148.73 + *
  148.74 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  148.75 + */
  148.76 +final class TyrusDynamicHTTP extends HttpHandler {
  148.77 +    private static int resourcesCount;
  148.78 +    private static List<Resource> resources;
  148.79 +    private static ServerConfiguration conf;
  148.80 +    private static HttpServer server;
  148.81 +    
  148.82 +    private TyrusDynamicHTTP() {
  148.83 +    }
  148.84 +    
  148.85 +    static URI initServer() throws Exception {
  148.86 +        server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
  148.87 +        final WebSocketAddOn addon = new WebSocketAddOn();
  148.88 +        for (NetworkListener listener : server.getListeners()) {
  148.89 +            listener.registerAddOn(addon);
  148.90 +        }        
  148.91 +        resources = new ArrayList<Resource>();
  148.92 +
  148.93 +        conf = server.getServerConfiguration();
  148.94 +        final TyrusDynamicHTTP dh = new TyrusDynamicHTTP();
  148.95 +
  148.96 +        conf.addHttpHandler(dh, "/");
  148.97 +        
  148.98 +        server.start();
  148.99 +
 148.100 +        return pageURL("http", server, "/test.html");
 148.101 +    }
 148.102 +    
 148.103 +    @Override
 148.104 +    public void service(Request request, Response response) throws Exception {
 148.105 +        if ("/test.html".equals(request.getRequestURI())) {
 148.106 +            response.setContentType("text/html");
 148.107 +            final InputStream is = TyrusDynamicHTTP.class.getResourceAsStream("test.html");
 148.108 +            copyStream(is, response.getOutputStream(), null);
 148.109 +            return;
 148.110 +        }
 148.111 +        if ("/dynamic".equals(request.getRequestURI())) {
 148.112 +            String mimeType = request.getParameter("mimeType");
 148.113 +            List<String> params = new ArrayList<String>();
 148.114 +            boolean webSocket = false;
 148.115 +            for (int i = 0;; i++) {
 148.116 +                String p = request.getParameter("param" + i);
 148.117 +                if (p == null) {
 148.118 +                    break;
 148.119 +                }
 148.120 +                if ("protocol:ws".equals(p)) {
 148.121 +                    webSocket = true;
 148.122 +                    continue;
 148.123 +                }
 148.124 +                params.add(p);
 148.125 +            }
 148.126 +            final String cnt = request.getParameter("content");
 148.127 +            String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
 148.128 +            ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
 148.129 +            URI url;
 148.130 +            final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
 148.131 +            if (webSocket) {
 148.132 +                url = registerWebSocket(res);
 148.133 +            } else {
 148.134 +                url = registerResource(res);
 148.135 +            }
 148.136 +            response.getWriter().write(url.toString());
 148.137 +            response.getWriter().write("\n");
 148.138 +            return;
 148.139 +        }
 148.140 +
 148.141 +        for (Resource r : resources) {
 148.142 +            if (r.httpPath.equals(request.getRequestURI())) {
 148.143 +                response.setContentType(r.httpType);
 148.144 +                r.httpContent.reset();
 148.145 +                String[] params = null;
 148.146 +                if (r.parameters.length != 0) {
 148.147 +                    params = new String[r.parameters.length];
 148.148 +                    for (int i = 0; i < r.parameters.length; i++) {
 148.149 +                        params[i] = request.getParameter(r.parameters[i]);
 148.150 +                        if (params[i] == null) {
 148.151 +                            if ("http.method".equals(r.parameters[i])) {
 148.152 +                                params[i] = request.getMethod().toString();
 148.153 +                            } else if ("http.requestBody".equals(r.parameters[i])) {
 148.154 +                                Reader rdr = request.getReader();
 148.155 +                                StringBuilder sb = new StringBuilder();
 148.156 +                                for (;;) {
 148.157 +                                    int ch = rdr.read();
 148.158 +                                    if (ch == -1) {
 148.159 +                                        break;
 148.160 +                                    }
 148.161 +                                    sb.append((char) ch);
 148.162 +                                }
 148.163 +                                params[i] = sb.toString();
 148.164 +                            }
 148.165 +                        }
 148.166 +                        if (params[i] == null) {
 148.167 +                            params[i] = "null";
 148.168 +                        }
 148.169 +                    }
 148.170 +                }
 148.171 +
 148.172 +                copyStream(r.httpContent, response.getOutputStream(), null, params);
 148.173 +            }
 148.174 +        }
 148.175 +    }
 148.176 +    
 148.177 +    private URI registerWebSocket(Resource r) {
 148.178 +        WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
 148.179 +        return pageURL("ws", server, r.httpPath);
 148.180 +    }
 148.181 +
 148.182 +    private URI registerResource(Resource r) {
 148.183 +        if (!resources.contains(r)) {
 148.184 +            resources.add(r);
 148.185 +            conf.addHttpHandler(this, r.httpPath);
 148.186 +        }
 148.187 +        return pageURL("http", server, r.httpPath);
 148.188 +    }
 148.189 +    
 148.190 +    private static URI pageURL(String proto, HttpServer server, final String page) {
 148.191 +        NetworkListener listener = server.getListeners().iterator().next();
 148.192 +        int port = listener.getPort();
 148.193 +        try {
 148.194 +            return new URI(proto + "://localhost:" + port + page);
 148.195 +        } catch (URISyntaxException ex) {
 148.196 +            throw new IllegalStateException(ex);
 148.197 +        }
 148.198 +    }
 148.199 +    
 148.200 +    static final class Resource {
 148.201 +
 148.202 +        final InputStream httpContent;
 148.203 +        final String httpType;
 148.204 +        final String httpPath;
 148.205 +        final String[] parameters;
 148.206 +
 148.207 +        Resource(InputStream httpContent, String httpType, String httpPath,
 148.208 +            String[] parameters) {
 148.209 +            httpContent.mark(Integer.MAX_VALUE);
 148.210 +            this.httpContent = httpContent;
 148.211 +            this.httpType = httpType;
 148.212 +            this.httpPath = httpPath;
 148.213 +            this.parameters = parameters;
 148.214 +        }
 148.215 +    }
 148.216 +
 148.217 +    static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
 148.218 +        for (;;) {
 148.219 +            int ch = is.read();
 148.220 +            if (ch == -1) {
 148.221 +                break;
 148.222 +            }
 148.223 +            if (ch == '$' && params.length > 0) {
 148.224 +                int cnt = is.read() - '0';
 148.225 +                if (baseURL != null && cnt == 'U' - '0') {
 148.226 +                    os.write(baseURL.getBytes("UTF-8"));
 148.227 +                } else {
 148.228 +                    if (cnt >= 0 && cnt < params.length) {
 148.229 +                        os.write(params[cnt].getBytes("UTF-8"));
 148.230 +                    } else {
 148.231 +                        os.write('$');
 148.232 +                        os.write(cnt + '0');
 148.233 +                    }
 148.234 +                }
 148.235 +            } else {
 148.236 +                os.write(ch);
 148.237 +            }
 148.238 +        }
 148.239 +    }
 148.240 +    
 148.241 +    private static class WS extends WebSocketApplication {
 148.242 +        private final Resource r;
 148.243 +
 148.244 +        private WS(Resource r) {
 148.245 +            this.r = r;
 148.246 +        }
 148.247 +
 148.248 +        @Override
 148.249 +        public void onMessage(WebSocket socket, String text) {
 148.250 +            try {
 148.251 +                r.httpContent.reset();
 148.252 +                ByteArrayOutputStream out = new ByteArrayOutputStream();
 148.253 +                copyStream(r.httpContent, out, null, text);
 148.254 +                String s = new String(out.toByteArray(), "UTF-8");
 148.255 +                socket.send(s);
 148.256 +            } catch (IOException ex) {
 148.257 +                LOG.log(Level.WARNING, null, ex);
 148.258 +            }
 148.259 +        }
 148.260 +        private static final Logger LOG = Logger.getLogger(WS.class.getName());
 148.261 +        
 148.262 +    }
 148.263 +}
   149.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   149.2 +++ b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusFX.java	Mon Dec 16 16:59:43 2013 +0100
   149.3 @@ -0,0 +1,120 @@
   149.4 +/**
   149.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   149.6 + *
   149.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   149.8 + *
   149.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  149.10 + * Other names may be trademarks of their respective owners.
  149.11 + *
  149.12 + * The contents of this file are subject to the terms of either the GNU
  149.13 + * General Public License Version 2 only ("GPL") or the Common
  149.14 + * Development and Distribution License("CDDL") (collectively, the
  149.15 + * "License"). You may not use this file except in compliance with the
  149.16 + * License. You can obtain a copy of the License at
  149.17 + * http://www.netbeans.org/cddl-gplv2.html
  149.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  149.19 + * specific language governing permissions and limitations under the
  149.20 + * License.  When distributing the software, include this License Header
  149.21 + * Notice in each file and include the License file at
  149.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  149.23 + * particular file as subject to the "Classpath" exception as provided
  149.24 + * by Oracle in the GPL Version 2 section of the License file that
  149.25 + * accompanied this code. If applicable, add the following below the
  149.26 + * License Header, with the fields enclosed by brackets [] replaced by
  149.27 + * your own identifying information:
  149.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  149.29 + *
  149.30 + * Contributor(s):
  149.31 + *
  149.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  149.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  149.34 + *
  149.35 + * If you wish your version of this file to be governed by only the CDDL
  149.36 + * or only the GPL Version 2, indicate your decision by adding
  149.37 + * "[Contributor] elects to include this software in this distribution
  149.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  149.39 + * single choice of license, a recipient has the option to distribute
  149.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  149.41 + * to extend the choice of license to its licensees as provided above.
  149.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  149.43 + * Version 2 license, then the option applies only if the new code is
  149.44 + * made subject to such option by the copyright holder.
  149.45 + */
  149.46 +package org.netbeans.html.wstyrus;
  149.47 +
  149.48 +import java.lang.reflect.InvocationTargetException;
  149.49 +import java.lang.reflect.Method;
  149.50 +import javafx.application.Platform;
  149.51 +import org.netbeans.html.boot.impl.FnContext;
  149.52 +import org.apidesign.html.boot.spi.Fn;
  149.53 +import org.testng.ITest;
  149.54 +import org.testng.annotations.Test;
  149.55 +
  149.56 +/**
  149.57 + *
  149.58 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  149.59 + */
  149.60 +public final class TyrusFX implements ITest, Runnable {
  149.61 +    private final Fn.Presenter p;
  149.62 +    private final Method m;
  149.63 +    private Object result;
  149.64 +    private Object inst;
  149.65 +    private int count;
  149.66 +
  149.67 +    TyrusFX(Fn.Presenter p, Method m) {
  149.68 +        this.p = p;
  149.69 +        this.m = m;
  149.70 +    }
  149.71 +
  149.72 +    @Override
  149.73 +    public String getTestName() {
  149.74 +        return m.getName();
  149.75 +    }
  149.76 +
  149.77 +    @Test
  149.78 +    public synchronized void executeTest() throws Exception {
  149.79 +        if (result == null) {
  149.80 +            Platform.runLater(this);
  149.81 +            wait();
  149.82 +        }
  149.83 +        if (result instanceof Exception) {
  149.84 +            throw (Exception)result;
  149.85 +        }
  149.86 +        if (result instanceof Error) {
  149.87 +            throw (Error)result;
  149.88 +        }
  149.89 +    }
  149.90 +
  149.91 +    @Override
  149.92 +    public synchronized void run() {
  149.93 +        boolean notify = true;
  149.94 +        try {
  149.95 +            FnContext.currentPresenter(p);
  149.96 +            if (inst == null) {
  149.97 +                inst = m.getDeclaringClass().newInstance();
  149.98 +            }
  149.99 +            result = m.invoke(inst);
 149.100 +            if (result == null) {
 149.101 +                result = this;
 149.102 +            }
 149.103 +        } catch (InvocationTargetException ex) {
 149.104 +            Throwable r = ex.getTargetException();
 149.105 +            if (r instanceof InterruptedException) {
 149.106 +                if (count++ < 10000) {
 149.107 +                    notify = false;
 149.108 +                    Platform.runLater(this);
 149.109 +                    return;
 149.110 +                }
 149.111 +            }
 149.112 +            result = r;
 149.113 +        } catch (Exception ex) {
 149.114 +            result = ex;
 149.115 +        } finally {
 149.116 +            if (notify) {
 149.117 +                notifyAll();
 149.118 +            }
 149.119 +            FnContext.currentPresenter(null);
 149.120 +        }
 149.121 +    }
 149.122 +    
 149.123 +}
   150.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   150.2 +++ b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusKnockoutTest.java	Mon Dec 16 16:59:43 2013 +0100
   150.3 @@ -0,0 +1,212 @@
   150.4 +/**
   150.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   150.6 + *
   150.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   150.8 + *
   150.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  150.10 + * Other names may be trademarks of their respective owners.
  150.11 + *
  150.12 + * The contents of this file are subject to the terms of either the GNU
  150.13 + * General Public License Version 2 only ("GPL") or the Common
  150.14 + * Development and Distribution License("CDDL") (collectively, the
  150.15 + * "License"). You may not use this file except in compliance with the
  150.16 + * License. You can obtain a copy of the License at
  150.17 + * http://www.netbeans.org/cddl-gplv2.html
  150.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  150.19 + * specific language governing permissions and limitations under the
  150.20 + * License.  When distributing the software, include this License Header
  150.21 + * Notice in each file and include the License file at
  150.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  150.23 + * particular file as subject to the "Classpath" exception as provided
  150.24 + * by Oracle in the GPL Version 2 section of the License file that
  150.25 + * accompanied this code. If applicable, add the following below the
  150.26 + * License Header, with the fields enclosed by brackets [] replaced by
  150.27 + * your own identifying information:
  150.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  150.29 + *
  150.30 + * Contributor(s):
  150.31 + *
  150.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  150.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  150.34 + *
  150.35 + * If you wish your version of this file to be governed by only the CDDL
  150.36 + * or only the GPL Version 2, indicate your decision by adding
  150.37 + * "[Contributor] elects to include this software in this distribution
  150.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  150.39 + * single choice of license, a recipient has the option to distribute
  150.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  150.41 + * to extend the choice of license to its licensees as provided above.
  150.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  150.43 + * Version 2 license, then the option applies only if the new code is
  150.44 + * made subject to such option by the copyright holder.
  150.45 + */
  150.46 +package org.netbeans.html.wstyrus;
  150.47 +
  150.48 +import java.io.BufferedReader;
  150.49 +import java.io.IOException;
  150.50 +import java.io.InputStreamReader;
  150.51 +import java.lang.annotation.Annotation;
  150.52 +import java.lang.reflect.Method;
  150.53 +import java.net.URI;
  150.54 +import java.net.URISyntaxException;
  150.55 +import java.net.URL;
  150.56 +import java.net.URLConnection;
  150.57 +import java.util.ArrayList;
  150.58 +import java.util.List;
  150.59 +import java.util.Map;
  150.60 +import java.util.concurrent.Executors;
  150.61 +import net.java.html.BrwsrCtx;
  150.62 +import net.java.html.boot.BrowserBuilder;
  150.63 +import net.java.html.js.JavaScriptBody;
  150.64 +import org.netbeans.html.boot.impl.FnContext;
  150.65 +import org.apidesign.html.boot.spi.Fn;
  150.66 +import org.apidesign.html.context.spi.Contexts;
  150.67 +import org.apidesign.html.json.spi.Technology;
  150.68 +import org.apidesign.html.json.spi.Transfer;
  150.69 +import org.apidesign.html.json.spi.WSTransfer;
  150.70 +import org.apidesign.html.json.tck.KOTest;
  150.71 +import org.apidesign.html.json.tck.KnockoutTCK;
  150.72 +import org.json.JSONException;
  150.73 +import org.json.JSONObject;
  150.74 +import org.netbeans.html.kofx.FXContext;
  150.75 +import org.openide.util.lookup.ServiceProvider;
  150.76 +import org.testng.annotations.Factory;
  150.77 +import static org.testng.Assert.*;
  150.78 +
  150.79 +/**
  150.80 + *
  150.81 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  150.82 + */
  150.83 +@ServiceProvider(service = KnockoutTCK.class)
  150.84 +public final class TyrusKnockoutTest extends KnockoutTCK {
  150.85 +    private static Class<?> browserClass;
  150.86 +    private static Fn.Presenter browserContext;
  150.87 +    
  150.88 +    public TyrusKnockoutTest() {
  150.89 +    }
  150.90 +    
  150.91 +    @Factory public static Object[] compatibilityTests() throws Exception {
  150.92 +        Class[] arr = testClasses();
  150.93 +        for (int i = 0; i < arr.length; i++) {
  150.94 +            assertEquals(
  150.95 +                arr[i].getClassLoader(),
  150.96 +                TyrusKnockoutTest.class.getClassLoader(),
  150.97 +                "All classes loaded by the same classloader"
  150.98 +            );
  150.99 +        }
 150.100 +        
 150.101 +        URI uri = TyrusDynamicHTTP.initServer();
 150.102 +    
 150.103 +        final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(TyrusKnockoutTest.class).
 150.104 +            loadPage(uri.toString()).
 150.105 +            invoke("initialized");
 150.106 +        
 150.107 +        Executors.newSingleThreadExecutor().submit(new Runnable() {
 150.108 +            @Override
 150.109 +            public void run() {
 150.110 +                bb.showAndWait();
 150.111 +            }
 150.112 +        });
 150.113 +        
 150.114 +        ClassLoader l = getClassLoader();
 150.115 +        List<Object> res = new ArrayList<Object>();
 150.116 +        for (int i = 0; i < arr.length; i++) {
 150.117 +            Class<?> c = Class.forName(arr[i].getName(), true, l);
 150.118 +            Class<? extends Annotation> koTest = 
 150.119 +                c.getClassLoader().loadClass(KOTest.class.getName()).
 150.120 +                asSubclass(Annotation.class);
 150.121 +            for (Method m : c.getMethods()) {
 150.122 +                if (m.getAnnotation(koTest) != null) {
 150.123 +                    res.add(new TyrusFX(browserContext, m));
 150.124 +                }
 150.125 +            }
 150.126 +        }
 150.127 +        return res.toArray();
 150.128 +    }
 150.129 +
 150.130 +    static synchronized ClassLoader getClassLoader() throws InterruptedException {
 150.131 +        while (browserClass == null) {
 150.132 +            TyrusKnockoutTest.class.wait();
 150.133 +        }
 150.134 +        return browserClass.getClassLoader();
 150.135 +    }
 150.136 +    
 150.137 +    public static synchronized void initialized(Class<?> browserCls) throws Exception {
 150.138 +        browserClass = browserCls;
 150.139 +        browserContext = FnContext.currentPresenter();
 150.140 +        TyrusKnockoutTest.class.notifyAll();
 150.141 +    }
 150.142 +    
 150.143 +    public static void initialized() throws Exception {
 150.144 +        Class<?> classpathClass = ClassLoader.getSystemClassLoader().loadClass(TyrusKnockoutTest.class.getName());
 150.145 +        Method m = classpathClass.getMethod("initialized", Class.class);
 150.146 +        m.invoke(null, TyrusKnockoutTest.class);
 150.147 +        browserContext = FnContext.currentPresenter();
 150.148 +    }
 150.149 +    
 150.150 +    @Override
 150.151 +    public BrwsrCtx createContext() {
 150.152 +        FXContext fx = new FXContext(browserContext);
 150.153 +        TyrusContext tc = new TyrusContext();
 150.154 +        Contexts.Builder cb = Contexts.newBuilder().
 150.155 +            register(Technology.class, fx, 10).
 150.156 +            register(Transfer.class, fx, 10).
 150.157 +            register(WSTransfer.class, tc, 10);
 150.158 +        return cb.build();
 150.159 +    }
 150.160 +
 150.161 +    @Override
 150.162 +    public Object createJSON(Map<String, Object> values) {
 150.163 +        JSONObject json = new JSONObject();
 150.164 +        for (Map.Entry<String, Object> entry : values.entrySet()) {
 150.165 +            try {
 150.166 +                json.put(entry.getKey(), entry.getValue());
 150.167 +            } catch (JSONException ex) {
 150.168 +                throw new IllegalStateException(ex);
 150.169 +            }
 150.170 +        }
 150.171 +        return json;
 150.172 +    }
 150.173 +
 150.174 +    @Override
 150.175 +    @JavaScriptBody(args = { "s", "args" }, body = ""
 150.176 +        + "var f = new Function(s); "
 150.177 +        + "return f.apply(null, args);"
 150.178 +    )
 150.179 +    public native Object executeScript(String script, Object[] arguments);
 150.180 +
 150.181 +    @JavaScriptBody(args = {  }, body = 
 150.182 +          "var h;"
 150.183 +        + "if (!!window && !!window.location && !!window.location.href)\n"
 150.184 +        + "  h = window.location.href;\n"
 150.185 +        + "else "
 150.186 +        + "  h = null;"
 150.187 +        + "return h;\n"
 150.188 +    )
 150.189 +    private static native String findBaseURL();
 150.190 +    
 150.191 +    @Override
 150.192 +    public URI prepareURL(String content, String mimeType, String[] parameters) {
 150.193 +        try {
 150.194 +            final URL baseURL = new URL(findBaseURL());
 150.195 +            StringBuilder sb = new StringBuilder();
 150.196 +            sb.append("/dynamic?mimeType=").append(mimeType);
 150.197 +            for (int i = 0; i < parameters.length; i++) {
 150.198 +                sb.append("&param" + i).append("=").append(parameters[i]);
 150.199 +            }
 150.200 +            String mangle = content.replace("\n", "%0a")
 150.201 +                .replace("\"", "\\\"").replace(" ", "%20");
 150.202 +            sb.append("&content=").append(mangle);
 150.203 +
 150.204 +            URL query = new URL(baseURL, sb.toString());
 150.205 +            URLConnection c = query.openConnection();
 150.206 +            BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
 150.207 +            URI connectTo = new URI(br.readLine());
 150.208 +            return connectTo;
 150.209 +        } catch (IOException ex) {
 150.210 +            throw new IllegalStateException(ex);
 150.211 +        } catch (URISyntaxException ex) {
 150.212 +            throw new IllegalStateException(ex);
 150.213 +        }
 150.214 +    }
 150.215 +}
   151.1 --- a/ko-ws-tyrus/src/test/resources/org/apidesign/html/wstyrus/test.html	Mon Dec 16 15:48:09 2013 +0100
   151.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   151.3 @@ -1,56 +0,0 @@
   151.4 -<!--
   151.5 -
   151.6 -    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   151.7 -
   151.8 -    Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   151.9 -
  151.10 -    Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  151.11 -    Other names may be trademarks of their respective owners.
  151.12 -
  151.13 -    The contents of this file are subject to the terms of either the GNU
  151.14 -    General Public License Version 2 only ("GPL") or the Common
  151.15 -    Development and Distribution License("CDDL") (collectively, the
  151.16 -    "License"). You may not use this file except in compliance with the
  151.17 -    License. You can obtain a copy of the License at
  151.18 -    http://www.netbeans.org/cddl-gplv2.html
  151.19 -    or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  151.20 -    specific language governing permissions and limitations under the
  151.21 -    License.  When distributing the software, include this License Header
  151.22 -    Notice in each file and include the License file at
  151.23 -    nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  151.24 -    particular file as subject to the "Classpath" exception as provided
  151.25 -    by Oracle in the GPL Version 2 section of the License file that
  151.26 -    accompanied this code. If applicable, add the following below the
  151.27 -    License Header, with the fields enclosed by brackets [] replaced by
  151.28 -    your own identifying information:
  151.29 -    "Portions Copyrighted [year] [name of copyright owner]"
  151.30 -
  151.31 -    Contributor(s):
  151.32 -
  151.33 -    The Original Software is NetBeans. The Initial Developer of the Original
  151.34 -    Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  151.35 -
  151.36 -    If you wish your version of this file to be governed by only the CDDL
  151.37 -    or only the GPL Version 2, indicate your decision by adding
  151.38 -    "[Contributor] elects to include this software in this distribution
  151.39 -    under the [CDDL or GPL Version 2] license." If you do not indicate a
  151.40 -    single choice of license, a recipient has the option to distribute
  151.41 -    your version of this file under either the CDDL, the GPL Version 2 or
  151.42 -    to extend the choice of license to its licensees as provided above.
  151.43 -    However, if you add GPL Version 2 code and therefore, elected the GPL
  151.44 -    Version 2 license, then the option applies only if the new code is
  151.45 -    made subject to such option by the copyright holder.
  151.46 -
  151.47 --->
  151.48 -<!DOCTYPE html>
  151.49 -<html>
  151.50 -    <head>
  151.51 -        <title>Tyrus WebSockets Execution Harness</title>
  151.52 -        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  151.53 -        <meta name="viewport" content="width=device-width">
  151.54 -    </head>
  151.55 -    <body>
  151.56 -        <h1>Tyrus WebSockets Execution Harness</h1>
  151.57 -    </body>
  151.58 -    <script></script>
  151.59 -</html>
   152.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   152.2 +++ b/ko-ws-tyrus/src/test/resources/org/netbeans/html/wstyrus/test.html	Mon Dec 16 16:59:43 2013 +0100
   152.3 @@ -0,0 +1,56 @@
   152.4 +<!--
   152.5 +
   152.6 +    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   152.7 +
   152.8 +    Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   152.9 +
  152.10 +    Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  152.11 +    Other names may be trademarks of their respective owners.
  152.12 +
  152.13 +    The contents of this file are subject to the terms of either the GNU
  152.14 +    General Public License Version 2 only ("GPL") or the Common
  152.15 +    Development and Distribution License("CDDL") (collectively, the
  152.16 +    "License"). You may not use this file except in compliance with the
  152.17 +    License. You can obtain a copy of the License at
  152.18 +    http://www.netbeans.org/cddl-gplv2.html
  152.19 +    or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  152.20 +    specific language governing permissions and limitations under the
  152.21 +    License.  When distributing the software, include this License Header
  152.22 +    Notice in each file and include the License file at
  152.23 +    nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  152.24 +    particular file as subject to the "Classpath" exception as provided
  152.25 +    by Oracle in the GPL Version 2 section of the License file that
  152.26 +    accompanied this code. If applicable, add the following below the
  152.27 +    License Header, with the fields enclosed by brackets [] replaced by
  152.28 +    your own identifying information:
  152.29 +    "Portions Copyrighted [year] [name of copyright owner]"
  152.30 +
  152.31 +    Contributor(s):
  152.32 +
  152.33 +    The Original Software is NetBeans. The Initial Developer of the Original
  152.34 +    Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  152.35 +
  152.36 +    If you wish your version of this file to be governed by only the CDDL
  152.37 +    or only the GPL Version 2, indicate your decision by adding
  152.38 +    "[Contributor] elects to include this software in this distribution
  152.39 +    under the [CDDL or GPL Version 2] license." If you do not indicate a
  152.40 +    single choice of license, a recipient has the option to distribute
  152.41 +    your version of this file under either the CDDL, the GPL Version 2 or
  152.42 +    to extend the choice of license to its licensees as provided above.
  152.43 +    However, if you add GPL Version 2 code and therefore, elected the GPL
  152.44 +    Version 2 license, then the option applies only if the new code is
  152.45 +    made subject to such option by the copyright holder.
  152.46 +
  152.47 +-->
  152.48 +<!DOCTYPE html>
  152.49 +<html>
  152.50 +    <head>
  152.51 +        <title>Tyrus WebSockets Execution Harness</title>
  152.52 +        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  152.53 +        <meta name="viewport" content="width=device-width">
  152.54 +    </head>
  152.55 +    <body>
  152.56 +        <h1>Tyrus WebSockets Execution Harness</h1>
  152.57 +    </body>
  152.58 +    <script></script>
  152.59 +</html>
   153.1 --- a/pom.xml	Mon Dec 16 15:48:09 2013 +0100
   153.2 +++ b/pom.xml	Mon Dec 16 16:59:43 2013 +0100
   153.3 @@ -92,7 +92,7 @@
   153.4                         <exclude>*</exclude>
   153.5                         <exclude>.*/**</exclude>
   153.6                         <exclude>ko-archetype/src/main/resources/**</exclude>
   153.7 -                       <exclude>ko-fx/src/main/resources/org/apidesign/html/kofx/knockout*.js</exclude>
   153.8 +                       <exclude>ko-fx/src/main/resources/org/netbeans/html/kofx/knockout*.js</exclude>
   153.9                    </excludes>
  153.10                </configuration>
  153.11            </plugin>
   154.1 --- a/sound/src/main/java/org/apidesign/html/sound/impl/BrowserAudioEnv.java	Mon Dec 16 15:48:09 2013 +0100
   154.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
   154.3 @@ -1,81 +0,0 @@
   154.4 -/**
   154.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   154.6 - *
   154.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   154.8 - *
   154.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  154.10 - * Other names may be trademarks of their respective owners.
  154.11 - *
  154.12 - * The contents of this file are subject to the terms of either the GNU
  154.13 - * General Public License Version 2 only ("GPL") or the Common
  154.14 - * Development and Distribution License("CDDL") (collectively, the
  154.15 - * "License"). You may not use this file except in compliance with the
  154.16 - * License. You can obtain a copy of the License at
  154.17 - * http://www.netbeans.org/cddl-gplv2.html
  154.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  154.19 - * specific language governing permissions and limitations under the
  154.20 - * License.  When distributing the software, include this License Header
  154.21 - * Notice in each file and include the License file at
  154.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  154.23 - * particular file as subject to the "Classpath" exception as provided
  154.24 - * by Oracle in the GPL Version 2 section of the License file that
  154.25 - * accompanied this code. If applicable, add the following below the
  154.26 - * License Header, with the fields enclosed by brackets [] replaced by
  154.27 - * your own identifying information:
  154.28 - * "Portions Copyrighted [year] [name of copyright owner]"
  154.29 - *
  154.30 - * Contributor(s):
  154.31 - *
  154.32 - * The Original Software is NetBeans. The Initial Developer of the Original
  154.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  154.34 - *
  154.35 - * If you wish your version of this file to be governed by only the CDDL
  154.36 - * or only the GPL Version 2, indicate your decision by adding
  154.37 - * "[Contributor] elects to include this software in this distribution
  154.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
  154.39 - * single choice of license, a recipient has the option to distribute
  154.40 - * your version of this file under either the CDDL, the GPL Version 2 or
  154.41 - * to extend the choice of license to its licensees as provided above.
  154.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
  154.43 - * Version 2 license, then the option applies only if the new code is
  154.44 - * made subject to such option by the copyright holder.
  154.45 - */
  154.46 -package org.apidesign.html.sound.impl;
  154.47 -
  154.48 -import net.java.html.js.JavaScriptBody;
  154.49 -import org.apidesign.html.sound.spi.AudioEnvironment;
  154.50 -import org.openide.util.lookup.ServiceProvider;
  154.51 -
  154.52 -/** Registers an audio provider that delegates to HTML5 Audio tag.
  154.53 - *
  154.54 - * @author Jaroslav Tulach <jtulach@netbeans.org>
  154.55 - */
  154.56 -@ServiceProvider(service = AudioEnvironment.class, position = 100)
  154.57 -public final class BrowserAudioEnv implements AudioEnvironment<Object> {
  154.58 -    @Override
  154.59 -    @JavaScriptBody(args = { "src" }, body = ""
  154.60 -        + "if (!Audio) return null;"
  154.61 -        + "return new Audio(src);")
  154.62 -    public Object create(String src) {
  154.63 -        // null if not running in browser
  154.64 -        return null;
  154.65 -    }
  154.66 -
  154.67 -    @Override @JavaScriptBody(args = { "a" }, body = "a.play();")
  154.68 -    public void play(Object a) {
  154.69 -    }
  154.70 -
  154.71 -    @Override @JavaScriptBody(args = { "a" }, body = "a.pause();")
  154.72 -    public void pause(Object a) {
  154.73 -    }
  154.74 -
  154.75 -    @Override @JavaScriptBody(args = { "a", "volume" }, body = "a.setVolume(volume);")
  154.76 -    public void setVolume(Object a, double volume) {
  154.77 -    }
  154.78 -
  154.79 -    @Override
  154.80 -    @JavaScriptBody(args = "a", body = "return true;")
  154.81 -    public boolean isSupported(Object a) {
  154.82 -        return false;
  154.83 -    }
  154.84 -}
   155.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
   155.2 +++ b/sound/src/main/java/org/netbeans/html/sound/impl/BrowserAudioEnv.java	Mon Dec 16 16:59:43 2013 +0100
   155.3 @@ -0,0 +1,81 @@
   155.4 +/**
   155.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   155.6 + *
   155.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
   155.8 + *
   155.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  155.10 + * Other names may be trademarks of their respective owners.
  155.11 + *
  155.12 + * The contents of this file are subject to the terms of either the GNU
  155.13 + * General Public License Version 2 only ("GPL") or the Common
  155.14 + * Development and Distribution License("CDDL") (collectively, the
  155.15 + * "License"). You may not use this file except in compliance with the
  155.16 + * License. You can obtain a copy of the License at
  155.17 + * http://www.netbeans.org/cddl-gplv2.html
  155.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  155.19 + * specific language governing permissions and limitations under the
  155.20 + * License.  When distributing the software, include this License Header
  155.21 + * Notice in each file and include the License file at
  155.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
  155.23 + * particular file as subject to the "Classpath" exception as provided
  155.24 + * by Oracle in the GPL Version 2 section of the License file that
  155.25 + * accompanied this code. If applicable, add the following below the
  155.26 + * License Header, with the fields enclosed by brackets [] replaced by
  155.27 + * your own identifying information:
  155.28 + * "Portions Copyrighted [year] [name of copyright owner]"
  155.29 + *
  155.30 + * Contributor(s):
  155.31 + *
  155.32 + * The Original Software is NetBeans. The Initial Developer of the Original
  155.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
  155.34 + *
  155.35 + * If you wish your version of this file to be governed by only the CDDL
  155.36 + * or only the GPL Version 2, indicate your decision by adding
  155.37 + * "[Contributor] elects to include this software in this distribution
  155.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
  155.39 + * single choice of license, a recipient has the option to distribute
  155.40 + * your version of this file under either the CDDL, the GPL Version 2 or
  155.41 + * to extend the choice of license to its licensees as provided above.
  155.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
  155.43 + * Version 2 license, then the option applies only if the new code is
  155.44 + * made subject to such option by the copyright holder.
  155.45 + */
  155.46 +package org.netbeans.html.sound.impl;
  155.47 +
  155.48 +import net.java.html.js.JavaScriptBody;
  155.49 +import org.apidesign.html.sound.spi.AudioEnvironment;
  155.50 +import org.openide.util.lookup.ServiceProvider;
  155.51 +
  155.52 +/** Registers an audio provider that delegates to HTML5 Audio tag.
  155.53 + *
  155.54 + * @author Jaroslav Tulach <jtulach@netbeans.org>
  155.55 + */
  155.56 +@ServiceProvider(service = AudioEnvironment.class, position = 100)
  155.57 +public final class BrowserAudioEnv implements AudioEnvironment<Object> {
  155.58 +    @Override
  155.59 +    @JavaScriptBody(args = { "src" }, body = ""
  155.60 +        + "if (!Audio) return null;"
  155.61 +        + "return new Audio(src);")
  155.62 +    public Object create(String src) {
  155.63 +        // null if not running in browser
  155.64 +        return null;
  155.65 +    }
  155.66 +
  155.67 +    @Override @JavaScriptBody(args = { "a" }, body = "a.play();")
  155.68 +    public void play(Object a) {
  155.69 +    }
  155.70 +
  155.71 +    @Override @JavaScriptBody(args = { "a" }, body = "a.pause();")
  155.72 +    public void pause(Object a) {
  155.73 +    }
  155.74 +
  155.75 +    @Override @JavaScriptBody(args = { "a", "volume" }, body = "a.setVolume(volume);")
  155.76 +    public void setVolume(Object a, double volume) {
  155.77 +    }
  155.78 +
  155.79 +    @Override
  155.80 +    @JavaScriptBody(args = "a", body = "return true;")
  155.81 +    public boolean isSupported(Object a) {
  155.82 +        return false;
  155.83 +    }
  155.84 +}