You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by jt...@apache.org on 2017/09/09 07:00:57 UTC

incubator-netbeans-html4j git commit: Removing dependency on Java collection classes implementations. Providing simpler replacements. Avoiding usage of WeakReferences unless requested.

Repository: incubator-netbeans-html4j
Updated Branches:
  refs/heads/master 7ddcc5f1a -> ee703cfd4


Removing dependency on Java collection classes implementations. Providing simpler replacements. Avoiding usage of WeakReferences unless requested.


Project: http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/commit/ee703cfd
Tree: http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/tree/ee703cfd
Diff: http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/diff/ee703cfd

Branch: refs/heads/master
Commit: ee703cfd4703009437267c98e5ef0e9dac99abef
Parents: 7ddcc5f
Author: Jaroslav Tulach <ja...@oracle.com>
Authored: Sat Sep 9 09:00:39 2017 +0200
Committer: Jaroslav Tulach <ja...@oracle.com>
Committed: Sat Sep 9 09:00:39 2017 +0200

----------------------------------------------------------------------
 .../org/netbeans/html/boot/impl/FnContext.java  |   3 +-
 .../java/org/netbeans/html/boot/spi/Fn.java     |   6 +-
 .../src/main/java/net/java/html/BrwsrCtx.java   |   3 -
 .../org/netbeans/html/context/impl/CtxImpl.java |  50 +-
 .../org/netbeans/html/context/spi/Contexts.java |  26 +-
 .../java/html/js/tests/JavaScriptBodyTest.java  |   4 +-
 .../java/html/json/tests/ConvertTypesTest.java  |  12 +-
 .../java/net/java/html/json/tests/JSONTest.java |  37 +-
 .../net/java/html/json/tests/KnockoutTest.java  |  15 +-
 .../net/java/html/json/tests/MinesTest.java     |  68 +-
 .../net/java/html/json/tests/PairModel.java     |   4 +-
 .../net/java/html/json/tests/SimpleMap.java     | 266 ++++++++
 .../java/net/java/html/json/tests/Utils.java    |  26 +-
 .../org/netbeans/html/json/tck/KnockoutTCK.java |  32 +-
 .../main/java/net/java/html/json/Models.java    |  13 +
 .../org/netbeans/html/json/impl/Bindings.java   |  10 -
 .../java/org/netbeans/html/json/impl/JSON.java  |  19 +-
 .../org/netbeans/html/json/impl/JSONList.java   |  14 +-
 .../org/netbeans/html/json/impl/SimpleList.java | 658 +++++++++++++++++++
 .../netbeans/html/json/spi/FunctionBinding.java |   7 +-
 .../org/netbeans/html/json/spi/Observers.java   |  29 +-
 .../netbeans/html/json/spi/PropertyBinding.java |  16 +-
 .../java/org/netbeans/html/json/spi/Proto.java  |   4 +-
 .../netbeans/html/json/impl/SimpleListTest.java | 123 ++++
 .../main/java/org/netbeans/html/ko4j/KO4J.java  |   2 -
 .../java/org/netbeans/html/ko4j/KOTech.java     |   7 +-
 .../java/org/netbeans/html/ko4j/KOTransfer.java |   6 +-
 .../java/org/netbeans/html/ko4j/Knockout.java   |  20 +-
 .../test/java/org/netbeans/html/ko4j/KOFx.java  |   2 -
 .../org/netbeans/html/ko4j/KnockoutFXTest.java  |   8 +-
 src/main/javadoc/overview.html                  |   5 +
 31 files changed, 1333 insertions(+), 162 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java
----------------------------------------------------------------------
diff --git a/boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java b/boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java
index ee7f077..74af344 100644
--- a/boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java
+++ b/boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java
@@ -36,7 +36,6 @@ import org.netbeans.html.boot.spi.Fn;
  * @author Jaroslav Tulach
  */
 public final class FnContext implements Closeable {
-    private static final Logger LOG = Logger.getLogger(FnContext.class.getName());
     private static final FnContext DUMMY;
     static {
         DUMMY = new FnContext(null, null);
@@ -84,7 +83,7 @@ public final class FnContext implements Closeable {
         }
         pw.println("Cannot initialize asm-5.0.jar!");
         pw.flush();
-        LOG.log(Level.SEVERE, w.toString(), t);
+        Logger.getLogger(FnContext.class.getName()).log(Level.SEVERE, w.toString(), t);
         return null;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java
----------------------------------------------------------------------
diff --git a/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java b/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java
index 57187a6..e70ad91 100644
--- a/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java
+++ b/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java
@@ -38,6 +38,7 @@ import org.netbeans.html.boot.impl.FnContext;
  * @author Jaroslav Tulach
  */
 public abstract class Fn {
+    private static Map<String, Set<Presenter>> LOADED;
     private final Presenter presenter;
     
     /**
@@ -126,8 +127,6 @@ public abstract class Fn {
         return p.defineFn(code, names);
     }
     
-    private static final Map<String,Set<Presenter>> LOADED = new HashMap<String, Set<Presenter>>();
-    
     /** Wraps function to ensure that the script represented by <code>resource</code>
      * gets loaded into the browser environment before the function <code>fn</code>
      * is executed.
@@ -164,6 +163,9 @@ public abstract class Fn {
                     p = FnContext.currentPresenter(false);
                 }
                 if (p != null) {
+                    if (LOADED == null) {
+                        LOADED = new HashMap<String, Set<Presenter>>();
+                    }
                     Set<Presenter> there = LOADED.get(resource);
                     if (there == null) {
                         there = new HashSet<Presenter>();

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/context/src/main/java/net/java/html/BrwsrCtx.java
----------------------------------------------------------------------
diff --git a/context/src/main/java/net/java/html/BrwsrCtx.java b/context/src/main/java/net/java/html/BrwsrCtx.java
index 37ac048..50bcfa4 100644
--- a/context/src/main/java/net/java/html/BrwsrCtx.java
+++ b/context/src/main/java/net/java/html/BrwsrCtx.java
@@ -19,7 +19,6 @@
 package net.java.html;
 
 import java.util.concurrent.Executor;
-import java.util.logging.Logger;
 import org.netbeans.html.context.impl.CtxAccssr;
 import org.netbeans.html.context.impl.CtxImpl;
 import org.netbeans.html.context.spi.Contexts;
@@ -41,7 +40,6 @@ import org.netbeans.html.context.spi.Contexts.Id;
  * @author Jaroslav Tulach
  */
 public final class BrwsrCtx implements Executor {
-    private static final Logger LOG = Logger.getLogger(BrwsrCtx.class.getName());
     private final CtxImpl impl;
     private BrwsrCtx(CtxImpl impl) {
         this.impl = impl;
@@ -88,7 +86,6 @@ public final class BrwsrCtx implements Executor {
         org.netbeans.html.context.spi.Contexts.Builder cb = Contexts.newBuilder();
         boolean found = Contexts.fillInByProviders(requestor, cb);
         if (!found) {
-            LOG.config("No browser context found. Returning empty technology!");
             return EMPTY;
         }
         return cb.build();

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java
----------------------------------------------------------------------
diff --git a/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java b/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java
index 093d9cc..2088e98 100644
--- a/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java
+++ b/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java
@@ -18,10 +18,6 @@
  */
 package org.netbeans.html.context.impl;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
 import net.java.html.BrwsrCtx;
 import org.netbeans.html.context.spi.Contexts;
 
@@ -31,14 +27,14 @@ import org.netbeans.html.context.spi.Contexts;
  * @author Jaroslav Tulach
  */
 public final class CtxImpl {
-    private final List<Bind<?>> techs;
+    private Bind<?>[] techs;
     private final Object[] context;
     
     public CtxImpl(Object[] context) {
-        this(context, new ArrayList<Bind<?>>());
+        this(context, new Bind<?>[0]);
     }
     
-    private CtxImpl(Object[] context, List<Bind<?>> techs) {
+    private CtxImpl(Object[] context, Bind<?>[] techs) {
         this.techs = techs;
         this.context = context;
     }
@@ -54,15 +50,14 @@ public final class CtxImpl {
     }
 
     public BrwsrCtx build() {
-        Collections.sort(techs, new BindCompare());
-        final List<Bind<?>> arr = Collections.unmodifiableList(techs);
-        CtxImpl impl = new CtxImpl(context, arr);
+        new BindCompare().sort(techs);
+        CtxImpl impl = new CtxImpl(context, techs.clone());
         BrwsrCtx ctx = CtxAccssr.getDefault().newContext(impl);
         return ctx;
     }
 
     public <Tech> void register(Class<Tech> type, Tech impl, int priority) {
-        techs.add(new Bind<Tech>(type, impl, priority));
+        techs = new BindCompare().add(techs, new Bind<Tech>(type, impl, priority));
     }
     
     private static final class Bind<Tech> {
@@ -82,8 +77,34 @@ public final class CtxImpl {
         }
     }
     
-    private final class BindCompare implements Comparator<Bind<?>> {
-        boolean isPrefered(Bind<?> b) {
+    private final class BindCompare {
+
+        void sort(Bind<?>[] techs) {
+            for (int i = 0; i < techs.length; i++) {
+                Bind<?> min = techs[i];
+                int minIndex = i;
+                for  (int j = i + 1; j < techs.length; j++) {
+                    if (compare(min, techs[j]) > 0) {
+                        min = techs[j];
+                        minIndex = j;
+                    }
+                }
+                if (minIndex != i) {
+                    techs[minIndex] = techs[i];
+                    techs[i] = min;
+                }
+            }
+        }
+
+        private <Tech> Bind<?>[] add(Bind<?>[] techs, Bind<Tech> bind) {
+            Bind<?>[] newArr = new Bind<?>[techs.length + 1];
+            for (int i = 0; i < techs.length; i++) {
+                newArr[i] = techs[i];
+            }
+            newArr[techs.length] = bind;
+            return newArr;
+        }
+        private boolean isPrefered(Bind<?> b) {
             final Class<?> implClazz = b.impl.getClass();
             Contexts.Id id = implClazz.getAnnotation(Contexts.Id.class);
             if (id == null) {
@@ -99,8 +120,7 @@ public final class CtxImpl {
             return false;
         }
         
-        @Override
-        public int compare(Bind<?> o1, Bind<?> o2) {
+        private int compare(Bind<?> o1, Bind<?> o2) {
             boolean p1 = isPrefered(o1);
             boolean p2 = isPrefered(o2);
             if (p1 != p2) {

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/context/src/main/java/org/netbeans/html/context/spi/Contexts.java
----------------------------------------------------------------------
diff --git a/context/src/main/java/org/netbeans/html/context/spi/Contexts.java b/context/src/main/java/org/netbeans/html/context/spi/Contexts.java
index e10e223..224be02 100644
--- a/context/src/main/java/org/netbeans/html/context/spi/Contexts.java
+++ b/context/src/main/java/org/netbeans/html/context/spi/Contexts.java
@@ -23,9 +23,7 @@ import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.util.HashSet;
 import java.util.ServiceLoader;
-import java.util.Set;
 import net.java.html.BrwsrCtx;
 import org.netbeans.html.context.impl.CtxImpl;
 
@@ -91,7 +89,7 @@ public final class Contexts {
         } catch (SecurityException ex) {
             l = null;
         }
-        Set<Class<?>> classes = new HashSet<Class<?>>();
+        ClassSet classes = new ClassSet(null);
         for (Provider cp : ServiceLoader.load(Provider.class, l)) {
             if (!classes.add(cp.getClass())) {
                 continue;
@@ -123,6 +121,28 @@ public final class Contexts {
         }
         return found;
     }
+
+    private static class ClassSet {
+        private final Class<?> clazz;
+        private ClassSet next;
+
+        public ClassSet(Class<?> clazz) {
+            this.clazz = clazz;
+        }
+
+
+        boolean add(Class<?> c) {
+            if (clazz == c) {
+                return false;
+            }
+            if (next == null) {
+                next = new ClassSet(c);
+                return true;
+            } else {
+                return next.add(c);
+            }
+        }
+    }
     
     /** Identifies the technologies passed to {@link Builder context builder}
      * by a name. Each implementation of a technology 

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json-tck/src/main/java/net/java/html/js/tests/JavaScriptBodyTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/js/tests/JavaScriptBodyTest.java b/json-tck/src/main/java/net/java/html/js/tests/JavaScriptBodyTest.java
index 08ad1a5..e79d47b 100644
--- a/json-tck/src/main/java/net/java/html/js/tests/JavaScriptBodyTest.java
+++ b/json-tck/src/main/java/net/java/html/js/tests/JavaScriptBodyTest.java
@@ -19,8 +19,8 @@
 package net.java.html.js.tests;
 
 import java.io.StringReader;
-import java.util.Arrays;
 import java.util.concurrent.Callable;
+import net.java.html.json.Models;
 import org.netbeans.html.boot.spi.Fn;
 import org.netbeans.html.json.tck.KOTest;
 
@@ -264,7 +264,7 @@ public class JavaScriptBodyTest {
         Object b = Bodies.callbackAndPush(a, "Worl\nd!");
         assertTrue(b instanceof Object[], "Returns an array: " + b);
         Object[] arr = (Object[]) b;
-        String str = Arrays.toString(arr);
+        String str = Models.asList(arr).toString();
         assertEquals(arr.length, 2, "Size is two " + str);
         assertEquals("He\nllo", arr[0], "Hello expected: " + arr[0]);
         assertEquals("Worl\nd!", arr[1], "World! expected: " + arr[1]);

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java b/json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java
index f39f8d0..af3e0e2 100644
--- a/json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java
+++ b/json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java
@@ -22,8 +22,6 @@ import java.io.ByteArrayInputStream;
 import java.io.EOFException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import net.java.html.BrwsrCtx;
@@ -75,7 +73,7 @@ public final class ConvertTypesTest {
     }
     private static Object createJSON(boolean includeSex) 
     throws UnsupportedEncodingException {
-        Map<String,Object> map = new HashMap<String,Object>();
+        Map<String,Object> map = SimpleMap.empty();
         map.put("firstName", "son");
         map.put("lastName", "dj");
         if (includeSex) {
@@ -126,7 +124,7 @@ public final class ConvertTypesTest {
         final BrwsrCtx c = newContext();
         final InputStream o = createIS(null, true, true, -1, null);
         
-        List<Person> arr = new ArrayList<Person>();
+        List<Person> arr = Models.asList();
         Models.parse(c, Person.class, o, arr);
         
         assertEquals(arr.size(), 1, "There is one item in " + arr);
@@ -163,7 +161,7 @@ public final class ConvertTypesTest {
         sb.append("  \"lastName\" : null } ]\n");  
         
         final ByteArrayInputStream is = new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
-        List<Person> arr = new ArrayList<Person>();
+        List<Person> arr = Models.asList();
         Models.parse(c, Person.class, is, arr);
         
         assertEquals(arr.size(), 2, "There are two items in " + arr);
@@ -237,7 +235,7 @@ public final class ConvertTypesTest {
         final BrwsrCtx c = newContext();
         final InputStream o = createIS(null, false, false, 5, null);
         
-        List<Person> res = new ArrayList<Person>();
+        List<Person> res = Models.asList();
         Models.parse(c, Person.class, o, res);
         
         assertEquals(res.size(), 5, "Five elements found" + res);
@@ -262,7 +260,7 @@ public final class ConvertTypesTest {
         final BrwsrCtx c = newContext();
         final InputStream o = createIS("{ \"info\" : ", false, false, array, "}");
 
-        List<People> res = new ArrayList<People>();
+        List<People> res = Models.asList();
         Models.parse(c, People.class, o, res);
 
         assertEquals(res.size(), 1, "One people" + res);

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java b/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java
index ed15526..19e989f 100644
--- a/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java
+++ b/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java
@@ -21,6 +21,8 @@ package net.java.html.json.tests;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
+import java.lang.reflect.Field;
+import java.nio.charset.Charset;
 import net.java.html.BrwsrCtx;
 import net.java.html.json.Model;
 import net.java.html.json.ModelOperation;
@@ -48,6 +50,18 @@ public final class JSONTest {
     private Integer orig;
     private String url;
 
+    static {
+        try {
+            System.setProperty("file.encoding", "windows-1251");
+            Field f = Charset.class.getDeclaredField("defaultCharset");
+            f.setAccessible(true);
+            f.set(null, null);
+            assertEquals(Charset.defaultCharset().toString(), "windows-1251", "Encoding has been changed");
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+    }
+
     @ModelOperation static void assignFetched(JSONik m, Person p) {
         m.setFetched(p);
     }
@@ -56,8 +70,8 @@ public final class JSONTest {
     @KOTest public void toJSONInABrowser() throws Throwable {
         Person p = Models.bind(new Person(), newContext());
         p.setSex(Sex.MALE);
-        p.setFirstName("Jarda");
-        p.setLastName("Tulach");
+        p.setFirstName("Jára");
+        p.setLastName("Tulachů");
 
         Object json;
         try {
@@ -72,6 +86,20 @@ public final class JSONTest {
             "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName());
     }
 
+    @KOTest public void fromJsonWithUTF8() throws Throwable {
+        final BrwsrCtx c = newContext();
+        Person p = Models.bind(new Person(), c);
+        p.setSex(Sex.MALE);
+        p.setFirstName("Jára");
+        p.setLastName("Tulachů");
+
+        byte[] arr = p.toString().getBytes("UTF-8");
+        Person p2 = Models.parse(c, Person.class, new ByteArrayInputStream(arr));
+
+        assertEquals(p2.getFirstName(), p.getFirstName(),
+            "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName());
+    }
+
     @KOTest public void toJSONWithEscapeCharactersInABrowser() throws Throwable {
         Person p = Models.bind(new Person(), newContext());
         p.setSex(Sex.MALE);
@@ -580,10 +608,7 @@ public final class JSONTest {
         try {
             prev = System.err;
             System.setErr(new PrintStream(err));
-        } catch (SecurityException e) {
-            err = null;
-            prev = null;
-        } catch (LinkageError e) {
+        } catch (Throwable e) {
             err = null;
             prev = null;
         }

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java b/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java
index d628907..e4cd463 100644
--- a/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java
+++ b/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java
@@ -18,10 +18,7 @@
  */
 package net.java.html.json.tests;
 
-import java.util.Arrays;
 import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
 import net.java.html.BrwsrCtx;
 import net.java.html.json.ComputedProperty;
 import net.java.html.json.Function;
@@ -62,7 +59,7 @@ public final class KnockoutTest {
         for (int i = 0; i < arr.length; i++) {
             arr[i] = results.get(i).length();
         }
-        return Arrays.asList(arr);
+        return Models.asList(arr);
     }
 
     @KOTest public void modifyValueAssertChangeInModelOnEnum() throws Throwable {
@@ -366,13 +363,12 @@ public final class KnockoutTest {
             String v = getSetInput("input", null);
             assertEquals("Kukuc", v, "Value is really kukuc: " + v);
 
-            Timer t = new Timer("Set to Jardo");
-            t.schedule(new TimerTask() {
+            Utils.scheduleLater(1, new Runnable() {
                 @Override
                 public void run() {
                     js.setName("Jardo");
                 }
-            }, 1);
+            });
         }
 
         String v = getSetInput("input", null);
@@ -525,13 +521,12 @@ public final class KnockoutTest {
             int cnt = Utils.countChildren(KnockoutTest.class, "ul");
             assertEquals(cnt, 1, "One child, but was " + cnt);
 
-            Timer t = new Timer("add to array");
-            t.schedule(new TimerTask() {
+            Utils.scheduleLater(1, new Runnable() {
                 @Override
                 public void run() {
                     js.getResults().add("Hi");
                 }
-            }, 1);
+            });
         }
 
 

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json-tck/src/main/java/net/java/html/json/tests/MinesTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/MinesTest.java b/json-tck/src/main/java/net/java/html/json/tests/MinesTest.java
index fcb8664..55c5ce3 100644
--- a/json-tck/src/main/java/net/java/html/json/tests/MinesTest.java
+++ b/json-tck/src/main/java/net/java/html/json/tests/MinesTest.java
@@ -18,9 +18,7 @@
  */
 package net.java.html.json.tests;
 
-import java.util.ArrayList;
 import java.util.List;
-import java.util.Random;
 import net.java.html.BrwsrCtx;
 import net.java.html.json.ComputedProperty;
 import net.java.html.json.Function;
@@ -42,7 +40,7 @@ public final class MinesTest {
     @KOTest public void paintTheGridOnClick() throws Throwable {
         if (m == null) {
             BrwsrCtx ctx = Utils.newContext(MinesTest.class);
-            Object exp = Utils.exposeHTML(MinesTest.class, 
+            Object exp = Utils.exposeHTML(MinesTest.class,
     "            <button id='init' data-bind='click: normalSize'></button>\n" +
     "            <table>\n" +
     "                <tbody id='table'>\n" +
@@ -72,21 +70,21 @@ public final class MinesTest {
             throw new InterruptedException();
         }
         assertEquals(cnt, 10, "There is ten rows in the table now: " + cnt);
-        
+
         Utils.exposeHTML(MinesTest.class, "");
     }
-    
+
     @KOTest public void countAround() throws Exception {
         Mines mines = new Mines();
         mines.init(5, 5, 0);
         mines.getRows().get(0).getColumns().get(0).setMine(true);
         mines.getRows().get(1).getColumns().get(0).setMine(true);
         mines.getRows().get(0).getColumns().get(1).setMine(true);
-        
+
         int cnt = around(mines, 1, 1);
         assertEquals(cnt, 3, "There are three mines around. Was: " + cnt);
     }
-    
+
     private static void scheduleClick(String id, int delay) throws Exception {
         String s = "var id = arguments[0]; var delay = arguments[1];"
             + "var e = window.document.getElementById(id);\n "
@@ -100,11 +98,11 @@ public final class MinesTest {
             MinesTest.class,
             s, id, delay);
     }
-    
+
     enum GameState {
         IN_PROGRESS, WON, LOST;
     }
-    
+
     @Model(className = "Row", properties = {
         @Property(name = "columns", type = Square.class, array = true)
     })
@@ -121,21 +119,21 @@ public final class MinesTest {
             switch (state) {
                 case EXPLOSION: return "&#x2717;";
                 case UNKNOWN: return "&nbsp;";
-                case DISCOVERED: return "&#x2714;";  
+                case DISCOVERED: return "&#x2714;";
                 case N_0: return "&nbsp;";
             }
             return "&#x278" + (state.ordinal() - 1);
         }
-        
+
         @ComputedProperty static String style(SquareType state) {
             return state == null ? null : state.toString();
         }
     }
-    
+
     enum SquareType {
         N_0, N_1, N_2, N_3, N_4, N_5, N_6, N_7, N_8,
         UNKNOWN, EXPLOSION, DISCOVERED;
-        
+
         final boolean isVisible() {
             return name().startsWith("N_");
         }
@@ -151,17 +149,26 @@ public final class MinesTest {
             return values()[ordinal() + 1];
         }
     }
-    
+
     @ComputedProperty static boolean fieldShowing(GameState state) {
         return state != null;
     }
-    
+
     @Function static void normalSize(Mines m) {
         m.init(10, 10, 10);
     }
-    
+
+    private static int randIndex;
+    private static int[] RANDOM = {
+        4, 5, 8, 1, 3, 9, 2, 7, 7, 3, 8, 5, 4, 0,
+        2, 7, 5, 3, 2, 9, 8, 8, 5, 3, 5, 8, 1, 5
+    };
+    private static int random() {
+        return RANDOM[randIndex++ % RANDOM.length];
+    }
+
     @ModelOperation static void init(Mines model, int width, int height, int mines) {
-        List<Row> rows = new ArrayList<Row>(height);
+        List<Row> rows = Models.asList();
         for (int y = 0; y < height; y++) {
             Square[] columns = new Square[width];
             for (int x = 0; x < width; x++) {
@@ -169,11 +176,10 @@ public final class MinesTest {
             }
             rows.add(new Row(columns));
         }
-        
-        Random r = new Random();
+
         while (mines > 0) {
-            int x = r.nextInt(width);
-            int y = r.nextInt(height);
+            int x = random() % width;
+            int y = random() % height;
             final Square s = rows.get(y).getColumns().get(x);
             if (s.isMine()) {
                 continue;
@@ -186,10 +192,10 @@ public final class MinesTest {
         model.getRows().clear();
         model.getRows().addAll(rows);
     }
-    
+
     @ModelOperation static void computeMines(Mines model) {
-        List<Integer> xBombs = new ArrayList<Integer>();
-        List<Integer> yBombs = new ArrayList<Integer>();
+        List<Integer> xBombs = Models.asList();
+        List<Integer> yBombs = Models.asList();
         final List<Row> rows = model.getRows();
         boolean emptyHidden = false;
         SquareType[][] arr = new SquareType[rows.size()][];
@@ -214,7 +220,7 @@ public final class MinesTest {
         for (int i = 0; i < xBombs.size(); i++) {
             int x = xBombs.get(i);
             int y = yBombs.get(i);
-            
+
             incrementAround(arr, x, y);
         }
         for (int y = 0; y < rows.size(); y++) {
@@ -227,13 +233,13 @@ public final class MinesTest {
                 }
             }
         }
-        
+
         if (!emptyHidden) {
             model.setState(GameState.WON);
             showAllBombs(model, SquareType.DISCOVERED);
         }
     }
-    
+
     private static void incrementAround(SquareType[][] arr, int x, int y) {
         incrementAt(arr, x - 1, y - 1);
         incrementAt(arr, x - 1, y);
@@ -242,11 +248,11 @@ public final class MinesTest {
         incrementAt(arr, x + 1, y - 1);
         incrementAt(arr, x + 1, y);
         incrementAt(arr, x + 1, y + 1);
-        
+
         incrementAt(arr, x, y - 1);
         incrementAt(arr, x, y + 1);
     }
-    
+
     private static void incrementAt(SquareType[][] arr, int x, int y) {
         if (y >= 0 && y < arr.length) {
             SquareType[] r = arr[y];
@@ -258,7 +264,7 @@ public final class MinesTest {
             }
         }
     }
-    
+
     static void showAllBombs(Mines model, SquareType state) {
         for (Row row : model.getRows()) {
             for (Square square : row.getColumns()) {
@@ -268,7 +274,7 @@ public final class MinesTest {
             }
         }
     }
-    
+
     private static void expandKnown(Mines model, Square data) {
         final List<Row> rows = model.getRows();
         for (int y = 0; y < rows.size(); y++) {

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json-tck/src/main/java/net/java/html/json/tests/PairModel.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/PairModel.java b/json-tck/src/main/java/net/java/html/json/tests/PairModel.java
index 35e0905..ef74c38 100644
--- a/json-tck/src/main/java/net/java/html/json/tests/PairModel.java
+++ b/json-tck/src/main/java/net/java/html/json/tests/PairModel.java
@@ -18,12 +18,12 @@
  */
 package net.java.html.json.tests;
 
-import java.util.Arrays;
 import java.util.List;
 import net.java.html.BrwsrCtx;
 import net.java.html.json.ComputedProperty;
 import net.java.html.json.Function;
 import net.java.html.json.Model;
+import net.java.html.json.Models;
 import net.java.html.json.Property;
 
 /**
@@ -40,7 +40,7 @@ class PairModel {
     
     @ComputedProperty 
     static List<String> bothNames(String firstName, String lastName) {
-        return Arrays.asList(firstName, lastName);
+        return Models.asList(firstName, lastName);
     }
     
     @ComputedProperty

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json-tck/src/main/java/net/java/html/json/tests/SimpleMap.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/SimpleMap.java b/json-tck/src/main/java/net/java/html/json/tests/SimpleMap.java
new file mode 100644
index 0000000..7394bdd
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/json/tests/SimpleMap.java
@@ -0,0 +1,266 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package net.java.html.json.tests;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import net.java.html.json.Models;
+
+final class SimpleMap<K,V> implements Map<K,V> {
+    private final List<E<K,V>> entries;
+
+    private SimpleMap() {
+        this.entries = Models.asList();
+    }
+
+    public static <K,V> Map<K,V> empty() {
+        return new SimpleMap<K,V>();
+    }
+
+    @Override
+    public int size() {
+        return entries.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return entries.isEmpty();
+    }
+
+    private int indexOf(Object obj, int index) {
+        for (int i = 0; i < entries.size(); i++) {
+            E<K,V> arr = entries.get(i);
+            if (equals(index == 0 ? arr.key : arr.value, obj)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private static boolean equals(Object obj1, Object obj2) {
+        if (obj1 == null) {
+            return obj2 == null;
+        }
+        return obj1.equals(obj2);
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+        return indexOf(key, 0) != -1;
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+        return indexOf(value, 1) != -1;
+    }
+
+    @Override
+    public V get(Object key) {
+        int at = indexOf(key, 0);
+        return at == -1 ? null : entries.get(at).value;
+    }
+
+    @Override
+    public V put(K key, V value) {
+        int at = indexOf(key, 0);
+        if (at == -1) {
+            entries.add(new E<K,V>(key, value));
+            return null;
+        } else {
+            E<K,V> arr = entries.get(at);
+            return arr.setValue(value);
+        }
+    }
+
+    @Override
+    public V remove(Object key) {
+        int at = indexOf(key, 0);
+        if (at == -1) {
+            return null;
+        }
+        return entries.remove(at).value;
+    }
+
+    @Override
+    public void putAll(Map<? extends K, ? extends V> m) {
+        throw new UnsupportedOperationException("");
+    }
+
+    @Override
+    public void clear() {
+        entries.clear();
+    }
+
+    @Override
+    public Set<K> keySet() {
+        List<K> keys = Models.asList();
+        for (E<K, V> entry : entries) {
+            keys.add(entry.key);
+        }
+        return new ROSet<K>(keys);
+    }
+
+    @Override
+    public Collection<V> values() {
+        List<V> values = Models.asList();
+        for (E<K, V> entry : entries) {
+            values.add(entry.value);
+        }
+        return values;
+    }
+
+    @Override
+    public Set<Entry<K, V>> entrySet() {
+        return new ROSet<Entry<K, V>>(entries);
+    }
+
+    private static final class E<K,V> implements Entry<K,V> {
+        final K key;
+        V value;
+
+        E(K key, V v) {
+            this.key = key;
+            this.value = v;
+        }
+
+        @Override
+        public K getKey() {
+            return key;
+        }
+
+        @Override
+        public V getValue() {
+            return value;
+        }
+
+        @Override
+        public V setValue(V value) {
+            V prev = this.value;
+            this.value = value;
+            return prev;
+        }
+    }
+
+    private static final class ROSet<T> implements Set<T> {
+        private final Collection<? extends T> delegate;
+
+        ROSet(Collection<? extends T> delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public int size() {
+            return delegate.size();
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return delegate.isEmpty();
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return delegate.contains(o);
+        }
+
+        @Override
+        public Iterator<T> iterator() {
+            final Iterator<? extends T> it = delegate.iterator();
+            return new Iterator<T>() {
+                @Override
+                public boolean hasNext() {
+                    return it.hasNext();
+                }
+
+                @Override
+                public T next() {
+                    return it.next();
+                }
+
+                @Override
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+            };
+        }
+
+        @Override
+        public Object[] toArray() {
+            return delegate.toArray();
+        }
+
+        @Override
+        public <T> T[] toArray(T[] a) {
+            return delegate.toArray(a);
+        }
+
+        @Override
+        public boolean add(T e) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean remove(Object o) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean containsAll(Collection<?> c) {
+            return delegate.containsAll(c);
+        }
+
+        @Override
+        public boolean addAll(Collection<? extends T> c) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean removeAll(Collection<?> c) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean retainAll(Collection<?> c) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void clear() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            return delegate.equals(o);
+        }
+
+        @Override
+        public int hashCode() {
+            return delegate.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return delegate.toString();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json-tck/src/main/java/net/java/html/json/tests/Utils.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/Utils.java b/json-tck/src/main/java/net/java/html/json/tests/Utils.java
index dddb98a..486b507 100644
--- a/json-tck/src/main/java/net/java/html/json/tests/Utils.java
+++ b/json-tck/src/main/java/net/java/html/json/tests/Utils.java
@@ -18,10 +18,11 @@
  */
 package net.java.html.json.tests;
 
-import java.net.URI;
-import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.ServiceLoader;
+import java.util.Timer;
+import java.util.TimerTask;
 import net.java.html.BrwsrCtx;
 import org.netbeans.html.json.tck.KnockoutTCK;
 
@@ -48,6 +49,21 @@ public final class Utils {
         return false;
     }
 
+    static void scheduleLater(int delay, final Runnable r) {
+        for (KnockoutTCK tck : tcks(r.getClass())) {
+            if (tck.scheduleLater(delay, r)) {
+                return;
+            }
+        }
+        Timer t = new Timer("Running later");
+        t.schedule(new TimerTask() {
+            @Override
+            public void run() {
+                r.run();
+            }
+        }, delay);
+    }
+
     private Utils() {
     }
     
@@ -84,7 +100,9 @@ public final class Utils {
 
     private static Iterable<KnockoutTCK> tcks(Class<?> clazz) {
         if (instantiatedTCK != null) {
-            return Collections.singleton(instantiatedTCK);
+            List<KnockoutTCK> l = (List<KnockoutTCK>)(Object)new People().getInfo();
+            l.add(instantiatedTCK);
+            return l;
         }
         return ServiceLoader.load(KnockoutTCK.class, cl(clazz));
     }
@@ -135,7 +153,7 @@ public final class Utils {
     static String prepareURL(
         Class<?> clazz, String content, String mimeType, String... parameters) {
         for (KnockoutTCK tck : tcks(clazz)) {
-            URI o = tck.prepareURL(content, mimeType, parameters);
+            String o = tck.prepareWebResource(content, mimeType, parameters);
             if (o != null) {
                 return o.toString();
             }

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json-tck/src/main/java/org/netbeans/html/json/tck/KnockoutTCK.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/org/netbeans/html/json/tck/KnockoutTCK.java b/json-tck/src/main/java/org/netbeans/html/json/tck/KnockoutTCK.java
index b5e4424..c3c02e0 100644
--- a/json-tck/src/main/java/org/netbeans/html/json/tck/KnockoutTCK.java
+++ b/json-tck/src/main/java/org/netbeans/html/json/tck/KnockoutTCK.java
@@ -19,6 +19,7 @@
 package org.netbeans.html.json.tck;
 
 import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.Map;
 import net.java.html.BrwsrCtx;
 import net.java.html.json.tests.ConvertTypesTest;
@@ -85,9 +86,25 @@ public abstract class KnockoutTCK {
      *   <code>$1</code> to reference <code>parameters</code> by their position
      * @param mimeType the type of the resource
      * @param parameters names of parameters as reference by <code>content</code>
-     * @return URI the test can connect to to obtain the (processed) content
+     * @return URL the test can connect to to obtain the (processed) content
+     * @since 1.5
      */
-    public abstract URI prepareURL(String content, String mimeType, String[] parameters);
+    public String prepareWebResource(String content, String mimeType, String[] parameters) {
+        return prepareURL(content, mimeType, parameters).toString();
+    }
+
+    /**
+     * @deprecated provide {@link #prepareWebResource(java.lang.String, java.lang.String, java.lang.String[])}
+     *    implementation instead since post 1.4 version of HTML/Java API.
+     */
+    @Deprecated
+    public URI prepareURL(String content, String mimeType, String[] parameters) {
+        try {
+            return new URI(prepareWebResource(content, mimeType, parameters));
+        } catch (URISyntaxException ex) {
+            throw new IllegalStateException();
+        }
+    }
     
     /** Gives you list of classes included in the TCK. Their test methods
      * are annotated by {@link KOTest} annotation. The methods are public
@@ -116,5 +133,16 @@ public abstract class KnockoutTCK {
         return false;
     }
 
+    /** Schedules the given runnable to run later.
+     *
+     * @param delay the delay in milliseconds
+     * @param r the runnable to run
+     * @return <code>true</code> if the runnable was really scheduled,
+     *   <code>false</code> otherwise
+     * @since 1.5 version
+     */
+    public boolean scheduleLater(int delay, Runnable r) {
+        return false;
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json/src/main/java/net/java/html/json/Models.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/net/java/html/json/Models.java b/json/src/main/java/net/java/html/json/Models.java
index 776ca78..ad76792 100644
--- a/json/src/main/java/net/java/html/json/Models.java
+++ b/json/src/main/java/net/java/html/json/Models.java
@@ -22,7 +22,9 @@ import net.java.html.BrwsrCtx;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Collection;
+import java.util.List;
 import org.netbeans.html.json.impl.JSON;
+import org.netbeans.html.json.impl.SimpleList;
 import org.netbeans.html.json.spi.Technology;
 
 /** Information about and 
@@ -164,4 +166,15 @@ public final class Models {
     public static void applyBindings(Object model, String targetId) {
         JSON.applyBindings(model, targetId);
     }
+
+    /** Wrap provided values into mutable list.
+     *
+     * @param <T> type of the values and resulting list
+     * @param values the values, if any
+     * @return full features implementation of mutable and extendable list
+     * @since 1.5
+     */
+    public static <T> List<T> asList(T... values) {
+        return SimpleList.asList(values);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json/src/main/java/org/netbeans/html/json/impl/Bindings.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/impl/Bindings.java b/json/src/main/java/org/netbeans/html/json/impl/Bindings.java
index 02c101a..fdd1b57 100644
--- a/json/src/main/java/org/netbeans/html/json/impl/Bindings.java
+++ b/json/src/main/java/org/netbeans/html/json/impl/Bindings.java
@@ -18,8 +18,6 @@
  */
 package org.netbeans.html.json.impl;
 
-import java.util.logging.Level;
-import java.util.logging.Logger;
 import net.java.html.BrwsrCtx;
 import org.netbeans.html.json.spi.FunctionBinding;
 import org.netbeans.html.json.spi.PropertyBinding;
@@ -31,8 +29,6 @@ import org.netbeans.html.json.spi.Technology;
  * @author Jaroslav Tulach
  */
 public final class Bindings<Data> {
-    private static final Logger LOG = Logger.getLogger(Bindings.class.getName()); 
-    
     private Data data;
     private final Technology<Data> bp;
 
@@ -94,12 +90,6 @@ public final class Bindings<Data> {
             ai.applyBindings(id, data);
             return;
         }
-        if (id != null) {
-            LOG.log(Level.WARNING, 
-                "Technology {0} does not implement ApplyId extension. Can't apply to {1}. Applying globally.", 
-                new Object[]{bp, id}
-            );
-        }
         bp.applyBindings(data);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json/src/main/java/org/netbeans/html/json/impl/JSON.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/impl/JSON.java b/json/src/main/java/org/netbeans/html/json/impl/JSON.java
index 0d1bb1a..f9cc31b 100644
--- a/json/src/main/java/org/netbeans/html/json/impl/JSON.java
+++ b/json/src/main/java/org/netbeans/html/json/impl/JSON.java
@@ -22,8 +22,6 @@ import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
 import net.java.html.BrwsrCtx;
 import org.netbeans.html.context.spi.Contexts;
 import org.netbeans.html.json.spi.FunctionBinding;
@@ -344,12 +342,17 @@ public final class JSON {
 
     }
 
-    private static final Map<Class,Proto.Type<?>> modelTypes;
-    static {
-        modelTypes = new HashMap<Class, Proto.Type<?>>();
+    private static final class ModelTypes extends ClassValue<Proto.Type[]> {
+        static final ModelTypes MODELS = new ModelTypes();
+
+        @Override
+        protected Proto.Type[] computeValue(Class<?> type) {
+            return new Proto.Type<?>[1];
+        }
     }
+
     public static void register(Class c, Proto.Type<?> type) {
-        modelTypes.put(c, type);
+        ModelTypes.MODELS.get(c)[0]= type;
     }
 
     public static boolean isModel(Class<?> clazz) {
@@ -358,7 +361,7 @@ public final class JSON {
 
     static Proto.Type<?> findType(Class<?> clazz) {
         for (int i = 0; i < 2; i++) {
-            Proto.Type<?> from = modelTypes.get(clazz);
+            Proto.Type<?> from = ModelTypes.MODELS.get(clazz)[0];
             if (from == null) {
                 initClass(clazz);
             } else {
@@ -407,7 +410,7 @@ public final class JSON {
             return modelClazz.cast(data.toString());
         }
         for (int i = 0; i < 2; i++) {
-            Proto.Type<?> from = modelTypes.get(modelClazz);
+            Proto.Type<?> from = ModelTypes.MODELS.get(modelClazz)[0];
             if (from == null) {
                 initClass(modelClazz);
             } else {

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json/src/main/java/org/netbeans/html/json/impl/JSONList.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/impl/JSONList.java b/json/src/main/java/org/netbeans/html/json/impl/JSONList.java
index 6988c81..4bbd80a 100644
--- a/json/src/main/java/org/netbeans/html/json/impl/JSONList.java
+++ b/json/src/main/java/org/netbeans/html/json/impl/JSONList.java
@@ -19,8 +19,6 @@
 package org.netbeans.html.json.impl;
 
 import java.lang.reflect.Array;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Iterator;
@@ -30,7 +28,7 @@ import org.netbeans.html.json.spi.Proto;
  *
  * @author Jaroslav Tulach
  */
-public final class JSONList<T> extends ArrayList<T> {
+public final class JSONList<T> extends SimpleList<T> {
     private final Proto proto;
     private final String name;
     private final String[] deps;
@@ -119,11 +117,7 @@ public final class JSONList<T> extends ArrayList<T> {
     }
 
     public void sort(Comparator<? super T> c) {
-        Object[] arr = this.toArray();
-        Arrays.sort(arr, (Comparator<Object>) c);
-        for (int i = 0; i < arr.length; i++) {
-            super.set(i, (T) arr[i]);
-        }
+        super.sort(c);
         notifyChange();
     }
 
@@ -159,8 +153,8 @@ public final class JSONList<T> extends ArrayList<T> {
     }
 
     @Override
-    protected void removeRange(int fromIndex, int toIndex) {
-        super.removeRange(fromIndex, toIndex);
+    void clearImpl(int from, int to) {
+        super.clearImpl(from, to);
         notifyChange();
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json/src/main/java/org/netbeans/html/json/impl/SimpleList.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/impl/SimpleList.java b/json/src/main/java/org/netbeans/html/json/impl/SimpleList.java
new file mode 100644
index 0000000..0950c7e
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/impl/SimpleList.java
@@ -0,0 +1,658 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.html.json.impl;
+
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+public class SimpleList<E> implements List<E> {
+    private Object[] arr;
+    private int size;
+
+    public SimpleList() {
+    }
+
+    private SimpleList(Object[] data) {
+        arr = data.clone();
+        size = data.length;
+    }
+
+    public static <T> List<T> asList(T... arr) {
+        return new SimpleList<T>(arr);
+    }
+
+    @Override
+    public int size() {
+        return size;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    @Override
+    public boolean contains(Object o) {
+        return containsImpl(o, 0, size);
+    }
+
+    final boolean containsImpl(Object o, int from, int to) {
+        for (int i = from; i < to; i++) {
+            if (equals(o, arr[i])) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+        return new LI(0, size);
+    }
+
+    @Override
+    public Object[] toArray() {
+        return toArrayImpl(0, size);
+    }
+
+    final Object[] toArrayImpl(int from, int to) {
+        Object[] ret = new Object[to - from];
+        for (int i = 0; i < ret.length; i++) {
+            ret[i] = arr[i + from];
+        }
+        return ret;
+    }
+
+    @Override
+    public <T> T[] toArray(T[] a) {
+        return toArrayImpl(a, 0, size);
+    }
+
+    final <T> T[] toArrayImpl(T[] a, int from, int to) {
+        if (a.length < to - from) {
+            a = newArr(a, to - from);
+        }
+        for (int i = 0; i < size; i++) {
+            a[i] = (T) arr[i + from];
+        }
+        return a;
+    }
+
+    @Override
+    public boolean add(E e) {
+        return addImpl(e);
+    }
+
+    private boolean addImpl(E e) {
+        ensureAccess(size + 1);
+        arr[size++] = e;
+        return true;
+    }
+
+    @Override
+    public boolean remove(Object o) {
+        return removeImpl(o, 0, size);
+    }
+
+    private boolean removeImpl(Object o, int from, int to) {
+        boolean found = false;
+        for (int i = from; i < to; i++) {
+            if (found) {
+                arr[i - 1] = arr[i];
+            } else {
+                if (equals(o, arr[i])) {
+                    found = true;
+                }
+            }
+        }
+        if (found) {
+            arr[--size] = null;
+        }
+        return found;
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> c) {
+        for (Object o : c) {
+            if (!contains(o)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends E> c) {
+        ensureAccess(size + c.size());
+        for (E o : c) {
+            addImpl(o);
+        }
+        return !c.isEmpty();
+    }
+
+    @Override
+    public boolean addAll(int index, Collection<? extends E> c) {
+        return addImpl(index, c);
+    }
+
+    private boolean addImpl(int index, Collection<? extends E> c) {
+        final int toAdd = c.size();
+        if (toAdd == 0) {
+            return false;
+        }
+        int nowSize = size;
+        ensureAccess(nowSize + toAdd);
+        for (int i = nowSize - 1; i >= index; i--) {
+            arr[i + toAdd] = arr[i];
+        }
+        for (Object o : c) {
+            arr[index++] = o;
+        }
+        size += toAdd;
+        return true;
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> c) {
+        int prev = size;
+        for (Object o : c) {
+            remove(o);
+        }
+        return prev != size;
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> c) {
+        return retainImpl(this, c);
+    }
+
+    public void sort(Comparator<? super E> c) {
+        sortImpl(c, 0, size);
+    }
+
+    final void sortImpl(Comparator<? super E> c, int from, int to) {
+        for (int i = from; i < to; i++) {
+            Object min = arr[i];
+            int minIndex = i;
+            for (int j = i + 1; j < to; j++) {
+                final int compare;
+                if (c == null) {
+                    compare = ((Comparable<Object>)min).compareTo(arr[j]);
+                } else {
+                    compare = c.compare((E)min, (E)arr[j]);
+                }
+                if (compare > 0) {
+                    min = arr[j];
+                    minIndex = j;
+                }
+            }
+            if (i != minIndex) {
+                arr[minIndex] = arr[i];
+                arr[i] = min;
+            }
+        }
+    }
+
+    @Override
+    public void clear() {
+        size = 0;
+    }
+
+    void  clearImpl(int from, int to) {
+        for (int i = 0; i + from < size; i++) {
+            arr[from + i] = arr[to + i];
+        }
+        size += from;
+        size -= to;
+    }
+
+    @Override
+    public E get(int index) {
+        checkAccess(index);
+        return (E) arr[index];
+    }
+
+    private void checkAccess(int index) throws ArrayIndexOutOfBoundsException {
+        if (index < 0 || index >= size) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+    }
+
+    private void ensureAccess(int reqSize) {
+        if (reqSize < size) {
+            return;
+        }
+
+        int newSize = arr == null ? 0 : arr.length;
+        if (newSize < 4) {
+            newSize = 4;
+        }
+        while (newSize < reqSize) {
+            newSize *= 2;
+        }
+        Object[] newArr = new Object[newSize];
+        for (int i = 0; i < size; i++) {
+            newArr[i] = arr[i];
+        }
+
+        arr = newArr;
+    }
+
+    @Override
+    public E set(int index, E element) {
+        checkAccess(index);
+        E prev = (E) arr[index];
+        arr[index] = element;
+        return prev;
+    }
+
+    @Override
+    public void add(int index, E element) {
+        addImpl(index, asList(element));
+    }
+
+    @Override
+    public E remove(int index) {
+        checkAccess(index);
+        E prev = (E) arr[index];
+        for (int i = index + 1; i < size; i++) {
+            arr[i - 1] = arr[i];
+        }
+        arr[--size] = null;
+        return prev;
+    }
+
+    @Override
+    public int indexOf(Object o) {
+        return indexOfImpl(o, 0, size);
+    }
+
+    final int indexOfImpl(Object o, int from, int to) {
+        for (int i = from; i < to; i++) {
+            if (equals(o, arr[i])) {
+                return i - from;
+            }
+        }
+        return -1;
+    }
+
+    @Override
+    public int lastIndexOf(Object o) {
+        return lastIndexOfImpl(o, 0, size);
+    }
+
+    public int lastIndexOfImpl(Object o, int from, int to) {
+        for (int i = to - 1; i >= from; i--) {
+            if (equals(o, arr[i])) {
+                return i - from;
+            }
+        }
+        return -1;
+    }
+
+    @Override
+    public ListIterator<E> listIterator() {
+        return new LI(0, size);
+    }
+
+    @Override
+    public ListIterator<E> listIterator(int index) {
+        return new LI(index, 0, size);
+    }
+
+    @Override
+    public List<E> subList(int fromIndex, int toIndex) {
+        return new Sub(fromIndex, toIndex);
+    }
+
+    private static boolean equals(Object o1, Object o2) {
+        if (o1 == null) {
+            return o2 == null;
+        } else {
+            return o1.equals(o2);
+        }
+    }
+
+    private static <T> T[] newArr(T[] a, int size) {
+        return (T[]) Array.newInstance(a.getClass().getComponentType(), size);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return equalsList(this, obj);
+    }
+
+    @Override
+    public int hashCode() {
+        return hashList(this);
+    }
+
+    @Override
+    public String toString() {
+        return toStringList(this);
+    }
+
+    boolean retainImpl(Collection<?> thiz, Collection<?> c) {
+        boolean changed = false;
+        Iterator<?> it = thiz.iterator();
+        while (it.hasNext()) {
+            Object obj = it.next();
+            if (!c.contains(obj)) {
+                it.remove();
+                changed = true;
+            }
+        }
+        return changed;
+    }
+
+    static boolean equalsList(List<?> thiz, Object obj) {
+        if (obj == thiz) return true;
+        if (obj instanceof List) {
+            List<?> list = (List<?>) obj;
+            if (thiz.size() != list.size()) {
+                return false;
+            }
+            for (int i = 0; i < thiz.size(); i++) {
+                if (!equals(thiz.get(i), list.get(i))) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    static int hashList(List<?> thiz) {
+        int hashCode = 1;
+        for (Object e : thiz) {
+            hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
+        }
+        return hashCode;
+    }
+
+    static String toStringList(List<?> thiz) {
+        StringBuilder sb = new StringBuilder();
+        sb.append('[');
+        String sep = "";
+        for (Object e : thiz) {
+            sb.append(sep);
+            sb.append(e);
+            sep = ", ";
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+
+
+    private final class Sub implements List<E> {
+        private final int from;
+        private int to;
+
+        Sub(int from, int to) {
+            this.from = from;
+            this.to = to;
+        }
+
+        @Override
+        public int size() {
+            return to - from;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return to <= from;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return containsImpl(o, from, to);
+        }
+
+        @Override
+        public Object[] toArray() {
+            return toArrayImpl(from, to);
+        }
+
+        @Override
+        public <T> T[] toArray(T[] a) {
+            return toArrayImpl(a, from, to);
+        }
+
+        @Override
+        public boolean add(E e) {
+            SimpleList.this.add(to++, e);
+            return true;
+        }
+
+        @Override
+        public boolean remove(Object o) {
+            if (removeImpl(o, from, to)) {
+                to--;
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean containsAll(Collection<?> c) {
+            for (Object o : c) {
+                if (!contains(o)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public boolean addAll(Collection<? extends E> c) {
+            SimpleList.this.addAll(to, c);
+            to += c.size();
+            return true;
+        }
+
+        @Override
+        public boolean addAll(int index, Collection<? extends E> c) {
+            SimpleList.this.addAll(from + index, c);
+            to += c.size();
+            return true;
+        }
+
+        @Override
+        public boolean removeAll(Collection<?> c) {
+            int prev = size();
+            for (Object o : c) {
+                remove(o);
+            }
+            return prev != size();
+        }
+
+        @Override
+        public boolean retainAll(Collection<?> c) {
+            return retainImpl(this, c);
+        }
+
+        public void sort(Comparator<? super E> c) {
+            sortImpl(c, from, to);
+        }
+
+        @Override
+        public void clear() {
+            clearImpl(from, to);
+            to = from;
+        }
+
+        @Override
+        public E get(int index) {
+            return SimpleList.this.get(from + index);
+        }
+
+        @Override
+        public E set(int index, E element) {
+            return SimpleList.this.set(from + index, element);
+        }
+
+        @Override
+        public void add(int index, E element) {
+            SimpleList.this.add(index + from, element);
+            to++;
+        }
+
+        @Override
+        public E remove(int index) {
+            E ret = SimpleList.this.remove(index + from);
+            to--;
+            return ret;
+        }
+
+        @Override
+        public int indexOf(Object o) {
+            return indexOfImpl(o, from, to);
+        }
+
+        @Override
+        public int lastIndexOf(Object o) {
+            return lastIndexOfImpl(o, from, to);
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return listIterator(0);
+        }
+
+        @Override
+        public ListIterator<E> listIterator() {
+            return listIterator(0);
+        }
+
+        @Override
+        public ListIterator<E> listIterator(int index) {
+            return new LI(from + index, from, to) {
+                @Override
+                public void remove() {
+                    super.remove();
+                    to--;
+                }
+            };
+        }
+
+        @Override
+        public List<E> subList(int fromIndex, int toIndex) {
+            return new Sub(from + fromIndex, from + toIndex);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return equalsList(this, obj);
+        }
+
+        @Override
+        public int hashCode() {
+            return hashList(this);
+        }
+
+        @Override
+        public String toString() {
+            return toStringList(this);
+        }
+    }
+
+    private class LI implements ListIterator<E> {
+        private int prev = -1;
+        private int at;
+        private final int min;
+        private final int max;
+        private int add;
+
+        LI(int at, int min, int max) {
+            this.at = at;
+            this.min = min;
+            this.max = max;
+        }
+
+        LI(int min, int max) {
+            this(min, min, max);
+        }
+
+        @Override
+        public boolean hasNext() {
+            return at < max + add;
+        }
+
+        @Override
+        public E next() {
+            if (at == max + add) {
+                throw new NoSuchElementException();
+            }
+            prev = at;
+            return (E) arr[at++];
+        }
+
+        @Override
+        public boolean hasPrevious() {
+            return at > min;
+        }
+
+        @Override
+        public E previous() {
+            if (at == min) {
+                throw new NoSuchElementException();
+            }
+            prev = --at;
+            return (E) arr[prev];
+        }
+
+        @Override
+        public int nextIndex() {
+            return at - min;
+        }
+
+        @Override
+        public int previousIndex() {
+            return at - 1 - min;
+        }
+
+        @Override
+        public void remove() {
+            if (prev == -1) {
+                throw new IllegalStateException();
+            }
+            SimpleList.this.remove(prev);
+            at = prev;
+            prev = -1;
+            add--;
+        }
+
+        @Override
+        public void set(E e) {
+            SimpleList.this.set(min + prev, e);
+        }
+
+        @Override
+        public void add(E e) {
+            SimpleList.this.add(min + at, e);
+            add++;
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json/src/main/java/org/netbeans/html/json/spi/FunctionBinding.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/spi/FunctionBinding.java b/json/src/main/java/org/netbeans/html/json/spi/FunctionBinding.java
index 41bce74..bd7d486 100644
--- a/json/src/main/java/org/netbeans/html/json/spi/FunctionBinding.java
+++ b/json/src/main/java/org/netbeans/html/json/spi/FunctionBinding.java
@@ -23,6 +23,7 @@ import java.lang.ref.WeakReference;
 import net.java.html.BrwsrCtx;
 import net.java.html.json.Function;
 import net.java.html.json.Model;
+import static org.netbeans.html.json.spi.PropertyBinding.weakSupported;
 
 /** Describes a function provided by the {@link Model} and 
  * annotated by {@link Function} annotation.
@@ -113,7 +114,11 @@ public abstract class FunctionBinding {
 
         @Override
         public FunctionBinding weak() {
-            return new Weak(model, name, index, access);
+            if (weakSupported) {
+                return new Weak(model, name, index, access);
+            } else {
+                return this;
+            }
         }
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json/src/main/java/org/netbeans/html/json/spi/Observers.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/spi/Observers.java b/json/src/main/java/org/netbeans/html/json/spi/Observers.java
index 59c225e..0728f1a 100644
--- a/json/src/main/java/org/netbeans/html/json/spi/Observers.java
+++ b/json/src/main/java/org/netbeans/html/json/spi/Observers.java
@@ -18,21 +18,18 @@
  */
 package org.netbeans.html.json.spi;
 
-import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
+import org.netbeans.html.json.impl.SimpleList;
 
 /**
  *
  * @author Jaroslav Tulach
  */
 final class Observers {
-    private static final LinkedList<Watcher> GLOBAL = new LinkedList<Watcher>();
-    private final List<Watcher> watchers = new ArrayList<Watcher>();
-    private final List<Ref> observers = new ArrayList<Ref>();
+    private static final List<Watcher> GLOBAL = SimpleList.asList();
+    private final List<Watcher> watchers = SimpleList.asList();
+    private final List<Ref> observers = SimpleList.asList();
 
     Observers() {
         assert Thread.holdsLock(GLOBAL);
@@ -42,7 +39,7 @@ final class Observers {
         synchronized (GLOBAL) {
             verifyUnlocked(p);
             final Watcher nw = new Watcher(p, name);
-            GLOBAL.push(nw);
+            GLOBAL.add(nw);
             return Usages.register(name, nw, usages);
         }
     }
@@ -118,7 +115,7 @@ final class Observers {
             return ref.proto == null ? null : ref;
         }
     }
-    
+
     private Watcher find(String prop) {
         if (prop == null) {
             return null;
@@ -148,7 +145,7 @@ final class Observers {
     }
 
     static final void valueHasMutated(Proto p, String propName) {
-        List<Watcher> mutated = new LinkedList<Watcher>();
+        List<Watcher> mutated = SimpleList.asList();
         synchronized (GLOBAL) {
             Observers mine = p.observers(false);
             if (mine == null) {
@@ -219,7 +216,8 @@ final class Observers {
     }
 
     static final class Usages {
-        private final Map<String,Watcher> watchers = new HashMap<String, Watcher>();
+        private final List<String> names = SimpleList.asList();
+        private final List<Watcher> watchers = SimpleList.asList();
 
         private Usages() {
         }
@@ -229,9 +227,14 @@ final class Observers {
                 if (usages == null) {
                     usages = new Usages();
                 }
-                Observers.Watcher prev = usages.watchers.put(propName, w);
-                if (prev != null) {
+                int index = usages.names.indexOf(propName);
+                if (index == -1) {
+                    usages.names.add(propName);
+                    usages.watchers.add(w);
+                } else {
+                    Watcher prev = usages.watchers.get(index);
                     prev.destroy();
+                    usages.watchers.set(index, w);
                 }
             }
             return usages;

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json/src/main/java/org/netbeans/html/json/spi/PropertyBinding.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/spi/PropertyBinding.java b/json/src/main/java/org/netbeans/html/json/spi/PropertyBinding.java
index b151b49..ef83ffd 100644
--- a/json/src/main/java/org/netbeans/html/json/spi/PropertyBinding.java
+++ b/json/src/main/java/org/netbeans/html/json/spi/PropertyBinding.java
@@ -36,6 +36,8 @@ public abstract class PropertyBinding {
     PropertyBinding() {
     }
 
+    static final boolean weakSupported;
+
     static {
         new PropertyBindingAccessor() {
             @Override
@@ -74,6 +76,14 @@ public abstract class PropertyBinding {
                 return new Impl(model, bindings, name, index, access, propertyType);
             }
         };
+        boolean weakOK;
+        try {
+            Class<?> weakRefClass = Class.forName("java.lang.ref.WeakReference"); // NOI18N
+            weakOK = weakRefClass != null;
+        } catch (ClassNotFoundException ex) {
+            weakOK = false;
+        }
+        weakSupported = weakOK;
     }
 
     /** Name of the property this binding represents.
@@ -188,7 +198,11 @@ public abstract class PropertyBinding {
 
         @Override
         public PropertyBinding weak() {
-            return new Weak(model, bindings, name, index, access, propertyType);
+            if (weakSupported) {
+                return new Weak(model, bindings, name, index, access, propertyType);
+            } else {
+                return this;
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json/src/main/java/org/netbeans/html/json/spi/Proto.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/spi/Proto.java b/json/src/main/java/org/netbeans/html/json/spi/Proto.java
index 626a6cb..6f9065f 100644
--- a/json/src/main/java/org/netbeans/html/json/spi/Proto.java
+++ b/json/src/main/java/org/netbeans/html/json/spi/Proto.java
@@ -18,12 +18,12 @@
  */
 package org.netbeans.html.json.spi;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import net.java.html.BrwsrCtx;
 import net.java.html.json.ComputedProperty;
 import net.java.html.json.Model;
+import net.java.html.json.Models;
 import net.java.html.json.Property;
 import org.netbeans.html.json.impl.Bindings;
 import org.netbeans.html.json.impl.JSON;
@@ -878,7 +878,7 @@ public final class Proto {
          * @since 1.0
          */
         public final <T> void replaceValue(Collection<? super T> arr, Class<T> type, Object value) {
-            List<T> tmp = new ArrayList<T>();
+            List<T> tmp = Models.asList();
             if (value instanceof Object[]) {
                 for (Object e : (Object[]) value) {
                     tmp.add(extractValue(type, e));

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/json/src/test/java/org/netbeans/html/json/impl/SimpleListTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/org/netbeans/html/json/impl/SimpleListTest.java b/json/src/test/java/org/netbeans/html/json/impl/SimpleListTest.java
new file mode 100644
index 0000000..58eee5a
--- /dev/null
+++ b/json/src/test/java/org/netbeans/html/json/impl/SimpleListTest.java
@@ -0,0 +1,123 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.html.json.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class SimpleListTest {
+
+    public SimpleListTest() {
+    }
+
+    @DataProvider(name = "lists")
+    public static Object[][] bothLists() {
+        return new Object[][] {
+            new Object[] { new ArrayList<Object>() },
+            new Object[] { SimpleList.asList() },
+        };
+    }
+
+    @Test(dataProvider = "lists")
+    public void testListIterator(List<String> list) {
+        list.add("Hi");
+        list.add("Ahoj");
+        list.add("Ciao");
+
+        Collections.sort(list);
+
+        ListIterator<String> it = list.listIterator(3);
+        assertEquals(it.previous(), "Hi");
+        assertEquals(it.previous(), "Ciao");
+        it.remove();
+        assertEquals(it.next(), "Hi");
+        assertEquals(it.previous(), "Hi");
+        assertEquals(it.previous(), "Ahoj");
+        assertEquals(list.size(), 2);
+    }
+
+    @Test(dataProvider = "lists")
+    public void toStringHashTest(List<Number> list) {
+        list.add(3);
+        list.add(3.3f);
+        list.add(4L);
+        list.add(4.4);
+        assertEquals(list.toString(), "[3, 3.3, 4, 4.4]");
+        assertEquals(list.hashCode(), 1374332816);
+    }
+
+    @Test(dataProvider = "lists")
+    public void toStringHashSubListTest(List<Number> list) {
+        list.add(3);
+        list.add(3.3f);
+        list.add(4L);
+        list.add(4.4);
+
+        list = list.subList(0, 4);
+
+        assertEquals(list.toString(), "[3, 3.3, 4, 4.4]");
+        assertEquals(list.hashCode(), 1374332816);
+    }
+
+    @Test(dataProvider = "lists")
+    public void subListEqualsTest(List<Number> list) {
+        list.add(3);
+        list.add(3.3f);
+        list.add(4L);
+        list.add(4.4);
+
+        assertEquals(list, list.subList(0, 4));
+    }
+
+    @Test(dataProvider = "lists")
+    public void retainAll(List<Number> list) {
+        list.add(3);
+        list.add(3.3f);
+        list.add(4L);
+        list.add(4.4);
+
+        list.retainAll(Collections.singleton(4L));
+
+        assertEquals(list.size(), 1);
+        assertEquals(list.get(0), 4L);
+    }
+
+    @Test(dataProvider = "lists")
+    public void retainAllOnSubList(List<Number> list) {
+        list.add(3);
+        list.add(3.3f);
+        list.add(4L);
+        list.add(4.4);
+
+        List<Number> subList = list.subList(1, 4);
+
+        subList.retainAll(Collections.singleton(4L));
+
+        assertEquals(subList.size(), 1);
+        assertEquals(subList.get(0), 4L);
+
+        assertEquals(list.size(), 2);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java
----------------------------------------------------------------------
diff --git a/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java b/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java
index 4f304af..eb8afa4 100644
--- a/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java
+++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java
@@ -18,7 +18,6 @@
  */
 package org.netbeans.html.ko4j;
 
-import java.util.logging.Logger;
 import net.java.html.json.Model;
 import net.java.html.json.OnReceive;
 import org.netbeans.html.boot.spi.Fn;
@@ -54,7 +53,6 @@ import org.openide.util.lookup.ServiceProvider;
  */
 @ServiceProvider(service = Provider.class)
 public final class KO4J implements Provider {
-    static final Logger LOG = Logger.getLogger(KOSockets.class.getName());
     private KOTech ko4j;
     private KOTransfer trans;
     private KOSockets socks;

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java
----------------------------------------------------------------------
diff --git a/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java
index dd1ba6d..c94e5ae 100644
--- a/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java
+++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java
@@ -18,11 +18,12 @@
  */
 package org.netbeans.html.ko4j;
 
+import java.util.List;
+import net.java.html.json.Models;
 import org.netbeans.html.context.spi.Contexts;
 import org.netbeans.html.json.spi.FunctionBinding;
 import org.netbeans.html.json.spi.PropertyBinding;
 import org.netbeans.html.json.spi.Technology;
-import static org.netbeans.html.ko4j.KO4J.LOG;
 
 /** This is an implementation package - just
  * include its JAR on classpath and use official {@link Context} API
@@ -132,9 +133,12 @@ implements Technology.BatchCopy<Object>, Technology.ValueMutated<Object>, Techno
         Object ko = Knockout.applyBindings(id, data);
         if (ko instanceof Knockout) {
             ((Knockout)ko).hold();
+            applied.add((Knockout) ko);
         }
     }
 
+    private static final List<Knockout> applied = Models.asList();
+
     @Override
     public Object wrapArray(Object[] arr) {
         return arr;
@@ -142,7 +146,6 @@ implements Technology.BatchCopy<Object>, Technology.ValueMutated<Object>, Techno
     
     @Override
     public void runSafe(final Runnable r) {
-        LOG.warning("Technology.runSafe has been deprecated. Use BrwsrCtx.execute!");
         r.run();
     }    
 

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/ko4j/src/main/java/org/netbeans/html/ko4j/KOTransfer.java
----------------------------------------------------------------------
diff --git a/ko4j/src/main/java/org/netbeans/html/ko4j/KOTransfer.java b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTransfer.java
index 6da4858..e980f98 100644
--- a/ko4j/src/main/java/org/netbeans/html/ko4j/KOTransfer.java
+++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTransfer.java
@@ -22,8 +22,8 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.util.ArrayList;
 import java.util.List;
+import net.java.html.json.Models;
 import org.netbeans.html.context.spi.Contexts;
 import org.netbeans.html.json.spi.JSONCall;
 import org.netbeans.html.json.spi.Transfer;
@@ -65,7 +65,7 @@ implements Transfer {
                     call.notifyError(ex);
                 }
             }
-            List<String> headerPairs = new ArrayList<String>();
+            List<String> headerPairs = Models.asList();
             String h = call.getHeaders();
             if (h != null) {
                 int pos = 0;
@@ -94,7 +94,7 @@ implements Transfer {
     @Override
     public Object toJSON(InputStream is) throws IOException {
         StringBuilder sb = new StringBuilder();
-        InputStreamReader r = new InputStreamReader(is);
+        InputStreamReader r = new InputStreamReader(is, "UTF-8");
         for (;;) {
             int ch = r.read();
             if (ch == -1) {

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java
----------------------------------------------------------------------
diff --git a/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java b/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java
index f175ee0..df5b03a 100644
--- a/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java
+++ b/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java
@@ -18,11 +18,6 @@
  */
 package org.netbeans.html.ko4j;
 
-import java.lang.ref.ReferenceQueue;
-import java.lang.ref.WeakReference;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
 import net.java.html.js.JavaScriptBody;
 import net.java.html.js.JavaScriptResource;
 import net.java.html.json.Model;
@@ -39,9 +34,7 @@ import org.netbeans.html.json.spi.PropertyBinding;
  * @author Jaroslav Tulach
  */
 @JavaScriptResource("knockout-3.4.0.js")
-final class Knockout extends WeakReference<Object> {
-    private static final ReferenceQueue<Object> QUEUE = new ReferenceQueue();
-    private static final Set<Knockout> active = Collections.synchronizedSet(new HashSet<Knockout>());
+final class Knockout  {
 
     @JavaScriptBody(args = {"object", "property"}, body =
         "var ret;\n" +
@@ -60,7 +53,7 @@ final class Knockout extends WeakReference<Object> {
     private Object strong;
 
     public Knockout(Object model, Object js, PropertyBinding[] props, FunctionBinding[] funcs) {
-        super(model, QUEUE);
+        this.strong = model;
         this.js = js;
         this.props = new PropertyBinding[props.length];
         for (int i = 0; i < props.length; i++) {
@@ -70,16 +63,14 @@ final class Knockout extends WeakReference<Object> {
         for (int i = 0; i < funcs.length; i++) {
             this.funcs[i] = funcs[i].weak();
         }
-        active.add(this);
     }
 
     static void cleanUp() {
         for (;;) {
-            Knockout ko = (Knockout)QUEUE.poll();
+            Knockout ko = null;
             if (ko == null) {
                 return;
             }
-            active.remove(ko);
             clean(ko.js);
             ko.js = null;
             ko.props = null;
@@ -88,7 +79,10 @@ final class Knockout extends WeakReference<Object> {
     }
 
     final void hold() {
-        strong = get();
+    }
+
+    final Object get() {
+        return strong;
     }
 
     final Object getValue(int index) {

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/ko4j/src/test/java/org/netbeans/html/ko4j/KOFx.java
----------------------------------------------------------------------
diff --git a/ko4j/src/test/java/org/netbeans/html/ko4j/KOFx.java b/ko4j/src/test/java/org/netbeans/html/ko4j/KOFx.java
index ba47648..1e34b1c 100644
--- a/ko4j/src/test/java/org/netbeans/html/ko4j/KOFx.java
+++ b/ko4j/src/test/java/org/netbeans/html/ko4j/KOFx.java
@@ -22,8 +22,6 @@ import java.io.Closeable;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 import javafx.application.Platform;
 import org.netbeans.html.boot.spi.Fn;
 import org.testng.ITest;

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java
----------------------------------------------------------------------
diff --git a/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java b/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java
index 389086e..4306983 100644
--- a/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java
+++ b/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java
@@ -24,7 +24,6 @@ import java.io.InputStreamReader;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.net.URI;
-import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLConnection;
 import java.util.ArrayList;
@@ -174,7 +173,7 @@ public final class KnockoutFXTest extends KnockoutTCK {
     private static native String findBaseURL();
     
     @Override
-    public URI prepareURL(String content, String mimeType, String[] parameters) {
+    public String prepareWebResource(String content, String mimeType, String[] parameters) {
         try {
             final URL baseURL = new URL(findBaseURL());
             StringBuilder sb = new StringBuilder();
@@ -189,12 +188,9 @@ public final class KnockoutFXTest extends KnockoutTCK {
             URL query = new URL(baseURL, sb.toString());
             URLConnection c = query.openConnection();
             BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
-            URI connectTo = new URI(br.readLine());
-            return connectTo;
+            return br.readLine();
         } catch (IOException ex) {
             throw new IllegalStateException(ex);
-        } catch (URISyntaxException ex) {
-            throw new IllegalStateException(ex);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/ee703cfd/src/main/javadoc/overview.html
----------------------------------------------------------------------
diff --git a/src/main/javadoc/overview.html b/src/main/javadoc/overview.html
index 408e0cb..5a898b6 100644
--- a/src/main/javadoc/overview.html
+++ b/src/main/javadoc/overview.html
@@ -57,6 +57,11 @@
         multiple observers</a> on a single model object.
         Better <a target="_blank" href="https://netbeans.org/bugzilla/show_bug.cgi?id=270553">
         GC behavior</a> specified in TCK and used in Knockout for Java implementation.
+        Removing dependency on Java collection classes implementations.
+        Adding {@link net.java.html.json.Models#asList} factory method to
+        create simple list implementation.
+        Simplifying {@link org.netbeans.html.json.tck.KnockoutTCK} to avoid
+        usage of {@link java.net.URI}, etc.
 
         <h3>New features in version 1.4</h3>