changeset 150:5118d0e38ba4 core-javascript-latex

$ hg merge core-javascript # into core-javascript-latex
author jf3243
date Tue, 01 Nov 2011 08:58:38 +0000
parents 5666f217df39 (current diff) 6c98b9680b2a (diff)
children
files core-javascript/index.rst core-javascript/js/exercise-1.js core-javascript/js/exercise-2.js core-javascript/js/solution-1-a.js core-javascript/js/solution-1-b.js core-javascript/js/solution-1-c.js core-javascript/js/solution-1-d.js core-javascript/js/solution-2-a.js core-javascript/js/solution-2-b.js core-javascript/js/solution-2-c.js core-javascript/js/solution-2-d.js
diffstat 38 files changed, 762 insertions(+), 532 deletions(-) [+]
line wrap: on
line diff
--- a/core-javascript/arguments.rst	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/arguments.rst	Tue Nov 01 08:58:38 2011 +0000
@@ -1,6 +1,17 @@
 Arguments
 =========
 
+This can be omitted at a first reading.  The main point here is that
+in JavaScript
+
+#. There is no checking for number and type of arguments.
+
+#. The arguments actually supplied are stored in a special variable,
+   called *arguments*.
+
+#. The value of *arguments* is almost, but not exactly, an array.
+
+
 Test code
 ---------
 
@@ -8,13 +19,3 @@
    :language: javascript
    :start-after: start return_arguments
    :end-before: end return_arguments
-
-
-Discussion
-----------
-
-Explanation
------------
-
-Exercises
----------
--- a/core-javascript/bind-is-transient.rst	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/bind-is-transient.rst	Tue Nov 01 08:58:38 2011 +0000
@@ -16,8 +16,54 @@
 Discussion
 ----------
 
+We create an object that has a *return_this* method.  The outcome of
+calling *return_this* depends on how it is called.
+
+There's a logic in the test code that produces contradictory, or at
+least surprising, outcomes.
+
+From
+
+.. code-block: javascript
+
+   obj.return_this === return_this;
+   method_deferred === obj.return_this;
+   method_deferred === return_this;
+
+we would expect
+
+.. code-block: javascript
+
+   obj.return_this() === return_this();
+   method_deferred() === obj.return_this();
+   method_deferred() === return_this();
+
+But this means that in *obj.return_this()* the *obj* is not relevant.
+But JavaScript (or its designers) wanted objects to have methods, so
+they introduced a special rule.
+
+
 Explanation
 -----------
 
-Exercises
----------
+JavaScript does not distinguish classes and instances.  Python, and
+perhaps other dynamic languages, does.  This allows Python to supply a
+bound method, which retains a reference to the object, when a function
+belonging to the class is called on an instance.
+
+Here's a Python (version 3) command line dialogue that illustrates
+this.
+
+>>> def method(): pass          # The function.
+...
+>>> class A: method = method    # The class.
+>>> A.method                    # Function from class.
+<function method at 0x15be518>
+>>> A.method is method          # Same as the original function.
+True
+>>> a = A()                     # Instance.
+>>> a.method                    # Bound method, not original function.
+<bound method A.method of <__main__.A object at 0x16b9d10>>
+
+The odd behaviour shown in the JavaScript test code is a consequence
+of JavaScript not distinguishing between classes and instances.
--- a/core-javascript/core-javascript-work/counters.css	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/core-javascript-work/counters.css	Tue Nov 01 08:58:38 2011 +0000
@@ -1,17 +1,17 @@
-body {
-    background: #DDD;
-    font-family: sans-serif;
-}
-
-#example {
-    padding: 20px;
-}
-
-#example span {
-    padding: 10px;
-    margin: 10px;
-    border: 10px solid blue;
-    background: #DDF;
-    foreground: blue;
-    font-weight: bold;
-}
+body {
+    background: #DDD;
+    font-family: sans-serif;
+}
+
+#example {
+    padding: 20px;
+}
+
+#example span {
+    padding: 10px;
+    margin: 10px;
+    border: 10px solid blue;
+    background: #DDF;
+    foreground: blue;
+    font-weight: bold;
+}
--- a/core-javascript/core-javascript-work/counters.html	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/core-javascript-work/counters.html	Tue Nov 01 08:58:38 2011 +0000
@@ -1,18 +1,18 @@
-<html>
-<head>
-<script src="library.js"></script>
-<script src="counters.js"></script>
-<link rel="stylesheet" type="text/css" href="counters.css" />
-<title>JS for Python: example: counters</title>
-</head>
-<body>
-<h1>Counters</h1>
-
-<p>Click on a counter to increment its value.</p>
-
-<div id="example">
-<p>This will disappear if JavaScript is working properly.</p>
-</div>
-
-<p>Return to documentation of <a href="../counters-example.html">Counters example</a>.</p>
-</body>
+<html>
+<head>
+<script src="library.js"></script>
+<script src="counters.js"></script>
+<link rel="stylesheet" type="text/css" href="counters.css" />
+<title>JS for Python: example: counters</title>
+</head>
+<body>
+<h1>Counters</h1>
+
+<p>Click on a counter to increment its value.</p>
+
+<div id="example">
+<p>This will disappear if JavaScript is working properly.</p>
+</div>
+
+<p>Return to documentation of <a href="../counters-example.html">Counters example</a>.</p>
+</body>
--- a/core-javascript/core-javascript-work/counters.js	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/core-javascript-work/counters.js	Tue Nov 01 08:58:38 2011 +0000
@@ -1,79 +1,79 @@
-(function()
-{
-    // Define a Counter class.
-    var counter = {};           // Prototype object for Counter.
-
-    counter.__init__ = function(name){
-
-        this.name = name;
-        this.count = 0;
-    };
-
-    counter.onclick = function(event){
-
-        this.count ++;
-    };
-
-    counter.html = function(){
-
-        return this.name + ' ' + this.count;
-    };
-
-    Counter = SimpleClass(counter);
-
-
-    // Make explicit use of global variables.
-    var global = (function(){return this;})();
-
-
-    // Interaction.
-    var onclick_factory = function(models){
-
-        var onclick = function(event){
-
-	    event = event || global.event; // For IE event handling.
-	    var target = event.target || event.srcElement;
-            var id = target.id;
-            if (id) {
-                var id_num = +id.slice(1);
-                var model = models[id_num];
-                model.onclick();
-                var html = model.html();
-                if (html){
-                    global.document.getElementById(id).innerHTML = html;
-                }
-            }
-        };
-        return onclick;
-    };
-
-
-    // Set up the web page.
-    global.onload = function(){
-
-        var models = [
-            Counter('apple'),
-            Counter('banana'),
-            Counter('cherry'),
-            Counter('date')
-        ];
-
-        var element = document.getElementById('example');
-
-        element.innerHTML = (
-            '<span id="a0">apple 0</span>'
-            + '<span id="a1">banana 0</span>'
-            + '<span id="a2">cherry 0</span>'
-            + '<span id="a3">date 0</span>'
-        );
-
-        element.onclick = onclick_factory(models);
-        element = undefined;    // Avoid IE memory leak.
-    };
-
-})();
-
-
-
-
-
+(function()
+{
+    // Define a Counter class.
+    var counter = {};           // Prototype object for Counter.
+
+    counter.__init__ = function(name){
+
+        this.name = name;
+        this.count = 0;
+    };
+
+    counter.onclick = function(event){
+
+        this.count ++;
+    };
+
+    counter.html = function(){
+
+        return this.name + ' ' + this.count;
+    };
+
+    Counter = SimpleClass(counter);
+
+
+    // Make explicit use of global variables.
+    var global = (function(){return this;})();
+
+
+    // Interaction.
+    var onclick_factory = function(models){
+
+        var onclick = function(event){
+
+	    event = event || global.event; // For IE event handling.
+	    var target = event.target || event.srcElement;
+            var id = target.id;
+            if (id) {
+                var id_num = +id.slice(1);
+                var model = models[id_num];
+                model.onclick();
+                var html = model.html();
+                if (html){
+                    global.document.getElementById(id).innerHTML = html;
+                }
+            }
+        };
+        return onclick;
+    };
+
+
+    // Set up the web page.
+    global.onload = function(){
+
+        var models = [
+            Counter('apple'),
+            Counter('banana'),
+            Counter('cherry'),
+            Counter('date')
+        ];
+
+        var element = document.getElementById('example');
+
+        element.innerHTML = (
+            '<span id="a0">apple 0</span>'
+            + '<span id="a1">banana 0</span>'
+            + '<span id="a2">cherry 0</span>'
+            + '<span id="a3">date 0</span>'
+        );
+
+        element.onclick = onclick_factory(models);
+        element = undefined;    // Avoid IE memory leak.
+    };
+
+})();
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core-javascript/core-javascript-work/demo_testtools.js	Tue Nov 01 08:58:38 2011 +0000
@@ -0,0 +1,14 @@
+TEST('all-pass', function()
+{
+    assert( 2 + 2 === 4 );
+    assert( 'the ' + 'cat' === 'the cat');
+});
+
+
+TEST('2-4-fail', function()
+{
+    assert( true );
+    assert( false );
+    assert( 1 );
+    assert( 0 );
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core-javascript/core-javascript-work/exercise-1.js	Tue Nov 01 08:58:38 2011 +0000
@@ -0,0 +1,14 @@
+var AAA = (function (BBB) 
+{
+    BBB.fff = function(ccc) 
+    {
+        return {
+            ggg: function(ddd) 
+            {
+                return BBB.hhh(ddd, ccc.iii());
+            }
+        };
+    };
+    return BBB;
+
+}(AAA || {}));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core-javascript/core-javascript-work/exercise-2.js	Tue Nov 01 08:58:38 2011 +0000
@@ -0,0 +1,11 @@
+var copy_attributes = function(tgt, src){
+    
+    tgt.aaa = src.get_aaa();
+    tgt.bbb = src.get_bbb();
+    tgt.ccc = src.get_ccc();
+    tgt.ddd = src.get_ddd();
+    tgt.eee = src.get_eee();
+    tgt.fff = src.get_fff();
+    tgt.ggg = src.get_ggg();
+    tgt.hhh = src.get_hhh();
+};
--- a/core-javascript/core-javascript-work/library.js	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/core-javascript-work/library.js	Tue Nov 01 08:58:38 2011 +0000
@@ -1,25 +1,25 @@
-// start create
-var create = function(parent){
-
-    var tmp = function(){};
-    tmp.prototype = parent;
-    var child = new tmp();
-
-    return child;
-};
-// end create
-
-
-// start SimpleClass
-var SimpleClass = function(prototype){
-
-    var cls = function(){
-        
-        var instance = create(prototype);
-        instance.__init__.apply(instance, arguments);
-        return instance;
-    };
-
-    return cls;
-};
-// end SimpleClass
+// start create
+var create = function(parent){
+
+    var tmp = function(){};
+    tmp.prototype = parent;
+    var child = new tmp();
+
+    return child;
+};
+// end create
+
+
+// start SimpleClass
+var SimpleClass = function(prototype){
+
+    var cls = function(){
+        
+        var instance = create(prototype);
+        instance.__init__.apply(instance, arguments);
+        return instance;
+    };
+
+    return cls;
+};
+// end SimpleClass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core-javascript/core-javascript-work/solution-1-a.js	Tue Nov 01 08:58:38 2011 +0000
@@ -0,0 +1,15 @@
+var AAA = function () 
+{
+    var BBB = AAA || {};
+    BBB.fff = function(ccc) 
+    {
+        return {
+            ggg: function(ddd) 
+            {
+                return BBB.hhh(ddd, ccc.iii());
+            }
+        };
+    };
+    return BBB;
+
+}();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core-javascript/core-javascript-work/solution-1-b.js	Tue Nov 01 08:58:38 2011 +0000
@@ -0,0 +1,5 @@
+var AAA = function () 
+{
+    var BBB = AAA || {};
+    return BBB;
+}();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core-javascript/core-javascript-work/solution-1-c.js	Tue Nov 01 08:58:38 2011 +0000
@@ -0,0 +1,1 @@
+var AAA = AAA || {};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core-javascript/core-javascript-work/solution-1-d.js	Tue Nov 01 08:58:38 2011 +0000
@@ -0,0 +1,11 @@
+var AAA = AAA || {};
+
+AAA.fff = function(ccc) 
+{
+    return {
+        ggg: function(ddd) 
+        {
+            return AAA.hhh(ddd, ccc.iii());
+        }
+    };
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core-javascript/core-javascript-work/solution-2-a.js	Tue Nov 01 08:58:38 2011 +0000
@@ -0,0 +1,10 @@
+var copy_attributes = function(tgt, src){
+    
+    var keys = ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff', 'ggg', 'hhh'];
+    var i;
+    var key;
+
+    for(i=0; i< keys.length; i++){
+        tgt[key] = src['get_' + key]();        
+    }
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core-javascript/core-javascript-work/solution-2-b.js	Tue Nov 01 08:58:38 2011 +0000
@@ -0,0 +1,11 @@
+var copy_attributes_factory = function(keys){
+
+    return function(src, tgt){
+        var i;
+        var key;
+
+        for(i=0; i< keys.length; i++){
+            tgt[key] = src['get_' + key]();        
+        };
+    };
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core-javascript/core-javascript-work/solution-2-c.js	Tue Nov 01 08:58:38 2011 +0000
@@ -0,0 +1,15 @@
+var Fields = function(keys){
+    this.keys = keys;
+};
+
+Fields.prototype = {
+    copy_attributes : function(src, tgt){
+
+        var keys = this.keys;
+        var i;
+
+        for(i=0; i< keys.length; i++){
+            tgt[key] = src['get_' + key]();        
+        };
+    }
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core-javascript/core-javascript-work/solution-2-d.js	Tue Nov 01 08:58:38 2011 +0000
@@ -0,0 +1,23 @@
+// Rhino $ js -f library.js -f solution-2-d.js -
+
+var fields = {};
+
+fields.__init__ = function(keys){
+    this.keys = keys;
+};
+
+fields.copy_attributes = function(src, tgt){
+
+    var keys = this.keys;
+    var key;
+    var i;
+
+    for(i=0; i< keys.length; i++){
+        key = keys[i];
+        tgt[key] = src['get_' + key]();
+    };
+};
+
+var Fields = SimpleClass(fields);
+
+
--- a/core-javascript/core-javascript-work/test_library.js	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/core-javascript-work/test_library.js	Tue Nov 01 08:58:38 2011 +0000
@@ -1,40 +1,40 @@
-var telltail = 'global';
-
-var TEST = function(title, code){
-    print( 'Testing: ' + title );
-    code();
-};
-
-var assert = function(arg){
-    if(!arg){
-        ddt();
-    }
-};
-
-
-// start SimpleClass
-TEST('SimpleClass', function()
-{
-    var fruit = {};
-
-    fruit.__init__ = function(name, colour){
-
-        this.name = name;
-        this.colour = colour;
-    };
-
-    fruit.greet = function(){
-
-        return "Hello, I'm a " + this.color + " " + this.name + ".";
-    };
-
-    var Fruit = SimpleClass(fruit);
-
-    var bn = Fruit('banana', 'yellow');
-    var rc = Fruit('cherry', 'red');
-    var gs = Fruit('Granny Smith', 'green');
-
-    assert( bn.greet() === "Hello, I'm a undefined banana." );
-
-});
-// end SimpleClass
+var telltail = 'global';
+
+var TEST = function(title, code){
+    print( 'Testing: ' + title );
+    code();
+};
+
+var assert = function(arg){
+    if(!arg){
+        ddt();
+    }
+};
+
+
+// start SimpleClass
+TEST('SimpleClass', function()
+{
+    var fruit = {};
+
+    fruit.__init__ = function(name, colour){
+
+        this.name = name;
+        this.colour = colour;
+    };
+
+    fruit.greet = function(){
+
+        return "Hello, I'm a " + this.color + " " + this.name + ".";
+    };
+
+    var Fruit = SimpleClass(fruit);
+
+    var bn = Fruit('banana', 'yellow');
+    var rc = Fruit('cherry', 'red');
+    var gs = Fruit('Granny Smith', 'green');
+
+    assert( bn.greet() === "Hello, I'm a undefined banana." );
+
+});
+// end SimpleClass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core-javascript/core-javascript-work/testtools.js	Tue Nov 01 08:58:38 2011 +0000
@@ -0,0 +1,30 @@
+var telltail = 'global';
+var _assertion_count = 0;
+
+// Define a global function 'log'.
+var log;
+if (this.hasOwnProperty('jsArguments')){
+    
+    log = function(s){
+        print(s + '\n');
+    };
+} else {
+    log = print;    
+}
+
+// 
+var TEST = function(title, code){
+
+    log( 'Testing: ' + title );
+    _assertion_count = 0;
+    code();
+};
+
+var assert = function(arg){
+    _assertion_count += 1;
+    if (!arg){
+        var msg = '! assert ' + _assertion_count + ' has failed';
+        log(msg);
+    }
+};
+
--- a/core-javascript/core-javascript-work/tutorial.js	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/core-javascript-work/tutorial.js	Tue Nov 01 08:58:38 2011 +0000
@@ -1,201 +1,203 @@
-var telltail = 'global';
-
-var TEST = function(title, code){
-    print( 'Testing: ' + title );
-    code();  
-};
-
-var assert = function(arg){
-    if(!arg){
-        ddt();
-    }  
-};
-
-'0' == 0 || ddt;
-0 == '' || ddt;
-'0' != '' || ddt;
-NaN != NaN || ddt;
-
-
-// start closures
-TEST('closures', function()
-{
-    // A factory for creating get-set pairs.
-    var get_set_factory = function(){
-
-        var value;
-        var get = function(){
-            return value;
-        };
-        var set = function(new_value){
-            value = new_value;            
-        };
-
-        return {
-            get: get,
-            set: set
-        };        
-    };
-
-    // Create and unpack two get-set pairs.
-    var tmp;
-    tmp= get_set_factory();
-    var get_a = tmp.get;
-    var set_a = tmp.set;
-
-    tmp= get_set_factory();
-    var get_b = tmp.get;
-    var set_b = tmp.set;
-
-    // Test that both pairs work.
-    set_a(12);
-    assert( get_a() === 12 );
-
-    set_b(13);
-    assert( get_b() === 13 );
-
-    // Test that each pair has its own value.
-    assert( get_a() === 12 );
-
-});
-// end closures
-
-
-// start return_this
-TEST('return_this', function()
-{
-    var return_this = function(){
-        return this;
-    };
-
-    var default_this = return_this();
-    assert( default_this.telltail === 'global' );
-    
-    var obj = {};
-    obj.return_this = return_this;
-    assert( obj.return_this === return_this );
-    
-    assert( obj.return_this() === obj );
-    assert( obj['return_this']() === obj );
-    
-    assert( return_this.call(obj) === obj );
-    assert( return_this.apply(obj) === obj );
-
-    assert( return_this.call(undefined).telltail === 'global' );
-    assert( return_this.apply(undefined).telltail === 'global' );
-
-});
-// end return_this
-
-
-// start transient-bind
-TEST('transient-bind', function()
-{
-    // Set up the test object.
-    var return_this = function(){
-        return this;
-    };
-    var obj = {
-        return_this : return_this
-    };
-
-    // Deferring method call changes the outcome.
-    var method_deferred = obj.return_this;
-    assert( method_deferred ===  obj.return_this );
-    assert( method_deferred() !==  obj.return_this() );
-
-    // The two outcomes, precisely stated.
-    assert( obj.return_this() === obj );
-    assert( method_deferred().telltail === 'global' );
-
-});
-// end transient-bind
-
-
-// start millers-device
-TEST('millers-device', function()
-{
-    var array = [];
-    var obj = {};
-    var fn = function(){};
-
-    assert( typeof array === 'object' );
-    assert( '' + obj === '[object Object]' );
-    
-    assert( obj.toString() === '[object Object]' );
-
-    var object_toString = obj.toString;
-
-    assert( object_toString.call(array) === '[object Array]' );
-    assert( object_toString.call(fn) === '[object Function]' );
-
-});
-// end millers-device
-
-
-// start return_arguments
-TEST('return_arguments', function()
-{
-    var return_arguments = function(){
-        return arguments;
-    };
-    
-    var my_arguments = return_arguments(0, 1);
-    
-    assert( my_arguments.length === 2 );
-    
-    assert( my_arguments[0]  === 0 );
-    assert( my_arguments[1]  === 1 );
-    
-    assert( '' + my_arguments === '[object Object]' );
-    assert( '' + [0, 1] === '0,1' );
-    
-    var array_slice = [].slice;
-    var my_arguments_fixed = array_slice.call( my_arguments );
-
-    assert( '' + my_arguments_fixed === '0,1');
-
-    var obj = {};
-    assert( obj.toString.call( my_arguments_fixed ) === '[object Array]' );
-
-});
-// end return_arguments
-
-
-// start new-operator
-TEST('new-operator', function()
-{
-    var this_in_Fn;
-
-    var Fn = function(){
-        this_in_Fn = this;
-    };
-
-    this_in_Fn = null;
-    var non_instance = Fn();
-    assert( non_instance === undefined );
-    assert( this_in_Fn.telltail === 'global');
-
-    this_in_Fn = null;
-    var instance = new Fn();
-    assert( instance === this_in_Fn );
-    assert( instance.telltail === undefined );
-
-    Fn.prototype.telltail = 'instance-of-Fn';
-    assert( instance.telltail === 'instance-of-Fn' );
-
-    Fn.prototype = {
-        telltail : 'prototype-is-changed'
-    };
-    var second_instance = new Fn();
-    assert( second_instance.telltail === 'prototype-is-changed' );
-
-    Fn.prototype = second_instance;
-    second_instance.i = 42;
-
-    var third_instance = new Fn();
-    assert( third_instance.telltail === 'prototype-is-changed' );
-    assert( third_instance.i === 42 );
-
-});
-// end new-operator
+// [Rhino] $ js -f testtools.js -f tutorial.js
+// [JSDB] $ jsdb -load testtools.js -load tutorial.js
+
+// start warm-up
+TEST('warm-up', function()
+{
+    assert( '0' == 0 );
+    assert ( 0 == '' );
+    assert( '0' != '' );
+
+    var a = NaN;
+    assert( a != a );
+
+});
+// end warm-up
+
+
+// start closures
+TEST('closures', function()
+{
+    // A factory for creating get-set pairs.
+    var get_set_factory = function(){
+
+        var value;
+        var get = function(){
+            return value;
+        };
+        var set = function(new_value){
+            value = new_value;
+        };
+
+        return {
+            get: get,
+            set: set
+        };
+    };
+
+    // Create and unpack two get-set pairs.
+    var tmp;
+    tmp= get_set_factory();
+    var get_a = tmp.get;
+    var set_a = tmp.set;
+
+    tmp= get_set_factory();
+    var get_b = tmp.get;
+    var set_b = tmp.set;
+
+    // Test that both pairs work.
+    set_a(12);
+    assert( get_a() === 12 );
+
+    set_b(13);
+    assert( get_b() === 13 );
+
+    // Test that each pair has its own value.
+    assert( get_a() === 12 );
+
+});
+// end closures
+
+
+// start return_this
+TEST('return_this', function()
+{
+    var return_this = function(){
+        return this;
+    };
+
+    var default_this = return_this();
+    assert( default_this.telltail === 'global' );
+
+    var obj = {};
+    obj.return_this = return_this;
+    assert( obj.return_this === return_this );
+
+    assert( obj.return_this() === obj );
+    assert( obj['return_this']() === obj );
+
+    assert( return_this.call(obj) === obj );
+    assert( return_this.apply(obj) === obj );
+
+    assert( return_this.call(undefined).telltail === 'global' );
+    assert( return_this.apply(undefined).telltail === 'global' );
+
+});
+// end return_this
+
+
+// start transient-bind
+TEST('transient-bind', function()
+{
+    // Set up the test object.
+    var return_this = function(){
+        return this;
+    };
+    var obj = {
+        return_this : return_this
+    };
+    assert( obj.return_this === return_this );
+
+    // Deferring method call changes the outcome.
+    var method_deferred = obj.return_this;
+    assert( method_deferred ===  obj.return_this );
+    assert( method_deferred() !==  obj.return_this() );  // AAA
+
+    // The two outcomes, precisely stated.
+    assert( obj.return_this() === obj );
+    assert( method_deferred().telltail === 'global' );
+
+    // Another view on the matter.
+    assert( method_deferred === return_this );
+    assert( method_deferred() === return_this() );  // BBB
+
+});
+// end transient-bind
+
+
+// start millers-device
+TEST('millers-device', function()
+{
+    var array = [];
+    var obj = {};
+    var fn = function(){};
+
+    assert( typeof array === 'object' );
+    assert( '' + obj === '[object Object]' );
+
+    assert( obj.toString() === '[object Object]' );
+
+    var object_toString = obj.toString;
+
+    assert( object_toString.call(array) === '[object Array]' );
+    assert( object_toString.call(fn) === '[object Function]' );
+
+});
+// end millers-device
+
+
+// start return_arguments
+TEST('return_arguments', function()
+{
+    var return_arguments = function(){
+        return arguments;
+    };
+
+    var my_arguments = return_arguments(0, 1);
+
+    assert( my_arguments.length === 2 );
+
+    assert( my_arguments[0]  === 0 );
+    assert( my_arguments[1]  === 1 );
+
+    assert( '' + my_arguments === '[object Object]' );
+    assert( '' + [0, 1] === '0,1' );
+
+    var array_slice = [].slice;
+    var my_arguments_fixed = array_slice.call( my_arguments );
+
+    assert( '' + my_arguments_fixed === '0,1');
+
+    var obj = {};
+    assert( obj.toString.call( my_arguments_fixed ) === '[object Array]' );
+
+});
+// end return_arguments
+
+
+// start new-operator
+TEST('new-operator', function()
+{
+    // A 'traditional class'.  It records 'this' as a side effect.
+    var this_in_Fn;
+    var Fn = function(){
+        this_in_Fn = this;
+    };
+
+    // Call the 'class' without the 'new'.
+    this_in_Fn = null;          // Clear any previous value.
+    var non_instance = Fn();
+    assert( non_instance === undefined );
+    assert( this_in_Fn.telltail === 'global');
+
+    // Call the 'class' with the 'new'.
+    this_in_Fn = null;          // Clear any previous value.
+    var instance = new Fn();
+    assert( instance === this_in_Fn );
+    assert( instance.telltail === undefined );
+
+    // Demonstrate that instance is a descendant of Fn.prototype.
+    Fn.prototype.telltail = 'instance-of-Fn';
+    assert( instance.telltail === 'instance-of-Fn' );
+
+    // We can give Fn a new prototype.
+    instance.new_telltail = 'child-of-instance';
+    Fn.prototype = instance;
+
+    // And now an instance of Fn has two telltails.
+    var second_instance = new Fn();
+    assert( second_instance.telltail === 'instance-of-Fn' );
+    assert( second_instance.new_telltail === 'child-of-instance' );
+
+});
+// end new-operator
--- a/core-javascript/exercise-1.rst	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/exercise-1.rst	Tue Nov 01 08:58:38 2011 +0000
@@ -13,7 +13,7 @@
 
 #.  Suggest a better way of going about things.
 
-.. literalinclude:: /js/exercise-1.js
+.. literalinclude:: /core-javascript-work/exercise-1.js
    :language: javascript
 
 
--- a/core-javascript/exercise-2.rst	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/exercise-2.rst	Tue Nov 01 08:58:38 2011 +0000
@@ -5,7 +5,7 @@
 everything to hide the origin of the code.  But it's not something
 I've made up.
 
-.. literalinclude:: /js/exercise-2.js
+.. literalinclude:: /core-javascript-work/exercise-2.js
    :language: javascript
 
 The exercise is
--- a/core-javascript/index.rst	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/index.rst	Tue Nov 01 08:58:38 2011 +0000
@@ -6,6 +6,7 @@
 
    getting-started
    counters-example
+   testtools
 
    immutables
    equality
--- a/core-javascript/js/exercise-1.js	Mon Oct 31 14:22:00 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-var AAA = (function (BBB) 
-{
-    BBB.fff = function(ccc) 
-    {
-        return {
-            ggg: function(ddd) 
-            {
-                return BBB.hhh(ddd, ccc.iii());
-            }
-        };
-    };
-    return BBB;
-
-}(AAA || {}));
--- a/core-javascript/js/exercise-2.js	Mon Oct 31 14:22:00 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-var copy_attributes = function(tgt, src){
-    
-    tgt.aaa = src.get_aaa();
-    tgt.bbb = src.get_bbb();
-    tgt.ccc = src.get_ccc();
-    tgt.ddd = src.get_ddd();
-    tgt.eee = src.get_eee();
-    tgt.fff = src.get_fff();
-    tgt.ggg = src.get_ggg();
-    tgt.hhh = src.get_hhh();
-};
--- a/core-javascript/js/solution-1-a.js	Mon Oct 31 14:22:00 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-var AAA = function () 
-{
-    var BBB = AAA || {};
-    BBB.fff = function(ccc) 
-    {
-        return {
-            ggg: function(ddd) 
-            {
-                return BBB.hhh(ddd, ccc.iii());
-            }
-        };
-    };
-    return BBB;
-
-}();
--- a/core-javascript/js/solution-1-b.js	Mon Oct 31 14:22:00 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-var AAA = function () 
-{
-    var BBB = AAA || {};
-    return BBB;
-}();
--- a/core-javascript/js/solution-1-c.js	Mon Oct 31 14:22:00 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-var AAA = AAA || {};
--- a/core-javascript/js/solution-1-d.js	Mon Oct 31 14:22:00 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-var AAA = AAA || {};
-
-AAA.fff = function(ccc) 
-{
-    return {
-        ggg: function(ddd) 
-        {
-            return AAA.hhh(ddd, ccc.iii());
-        }
-    };
-};
--- a/core-javascript/js/solution-2-a.js	Mon Oct 31 14:22:00 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-var copy_attributes = function(tgt, src){
-    
-    var keys = ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff', 'ggg', 'hhh'];
-    var i;
-    var key;
-
-    for(i=0; i< keys.length; i++){
-        tgt[key] = src['get_' + key]();        
-    }
-};
--- a/core-javascript/js/solution-2-b.js	Mon Oct 31 14:22:00 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-var copy_attributes_factory = function(keys){
-
-    return function(src, tgt){
-        var i;
-        var key;
-
-        for(i=0; i< keys.length; i++){
-            tgt[key] = src['get_' + key]();        
-        };
-    };
-};
--- a/core-javascript/js/solution-2-c.js	Mon Oct 31 14:22:00 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-var Fields = function(keys){
-    this.keys = keys;
-};
-
-Fields.prototype = {
-    copy_attributes : function(src, tgt){
-
-        var keys = this.keys;
-        var i;
-
-        for(i=0; i< keys.length; i++){
-            tgt[key] = src['get_' + key]();        
-        };
-    }
-};
--- a/core-javascript/js/solution-2-d.js	Mon Oct 31 14:22:00 2011 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-var fields = {};
-
-fields.__init__ = function(keys){
-    this.keys = keys;
-};
-
-fields.copy_attributes = function(src, tgt){
-    
-    var keys = this.keys;
-    var i;
-    
-    for(i=0; i< keys.length; i++){
-        tgt[key] = src['get_' + key]();        
-    };
-};
-
-var Fields = Class(fields);
-
-
--- a/core-javascript/millers-device.rst	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/millers-device.rst	Tue Nov 01 08:58:38 2011 +0000
@@ -1,18 +1,22 @@
 Mark Miller's device
 ====================
 
+This can be omitted at a first reading. Mark Miller is one of the
+leading JavaScript experts at Google.  He's been credited an ingenious
+application of call that gives a simple and reliable test for whether
+or not an object is an array.
+
+This may not sound very much, but it is something that had been
+puzzling the other experts for some years.  For example, Crockford in
+his *Good Parts* (published 2008, page 61) gives a much more complex
+and less reliable solution to this problem.
+
+The moral of this story is that even the experts in JavaScript can
+have difficulty finding the best way to solve a simple problem.
+
 Test code
 ---------
 .. literalinclude:: /core-javascript-work/tutorial.js
    :language: javascript
    :start-after: start millers-device
    :end-before: end millers-device
-
-Discussion
-----------
-
-Explanation
------------
-
-Exercises
----------
--- a/core-javascript/solution-1.rst	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/solution-1.rst	Tue Nov 01 08:58:38 2011 +0000
@@ -3,7 +3,7 @@
 
 Here's the code we're studying.
 
-.. literalinclude:: /js/exercise-1.js
+.. literalinclude:: /core-javascript-work/exercise-1.js
    :language: javascript
 
 
@@ -22,7 +22,7 @@
 body.  We can always do this, without changing the meaning, provided the
 function is called only once.
 
-.. literalinclude:: /js/solution-1-a.js
+.. literalinclude:: /core-javascript-work/solution-1-a.js
    :language: javascript
 
 There, that's better.  We no longer have to read to the end of the
@@ -38,7 +38,7 @@
 BBB.  In other words, it mutates the object pointed to by BBB, but the
 variable BBB still points to the same object as it did before.
 
-.. literalinclude:: /js/solution-1-b.js
+.. literalinclude:: /core-javascript-work/solution-1-b.js
    :language: javascript
 
 
@@ -59,7 +59,7 @@
 
 Therefore, our truncated version of the original exercise is equivalent to
 
-.. literalinclude:: /js/solution-1-c.js
+.. literalinclude:: /core-javascript-work/solution-1-c.js
    :language: javascript
 
 This idiom is very common in JavaScript, and is (as here) a
@@ -94,7 +94,7 @@
 The following is almost equivalent to our original JavaScript code.
 Note that BBB.hhh has been changed to AAA.hhh.
 
-.. literalinclude:: /js/solution-1-d.js
+.. literalinclude:: /core-javascript-work/solution-1-d.js
    :language: javascript
 
 
--- a/core-javascript/solution-2.rst	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/solution-2.rst	Tue Nov 01 08:58:38 2011 +0000
@@ -4,7 +4,7 @@
 Here's the code we are studying.  The first task is make a loop that
 does the assignments.
 
-.. literalinclude:: /js/exercise-2.js
+.. literalinclude:: /core-javascript-work/exercise-2.js
    :language: javascript
 
 
@@ -18,7 +18,7 @@
 Here's the solution.  There's a bit of overhead in setting up the
 loop, but the body of the loop is straightforward.
 
-.. literalinclude:: /js/solution-2-a.js
+.. literalinclude:: /core-javascript-work/solution-2-a.js
    :language: javascript
 
 
@@ -31,7 +31,7 @@
 This is a common refactoring pattern, and so is worth learning well.
 First we give the code, and then the explanation.
 
-.. literalinclude:: /js/solution-2-b.js
+.. literalinclude:: /core-javascript-work/solution-2-b.js
    :language: javascript
 
 
@@ -56,7 +56,7 @@
 the class supplying the *new* operator to create the new instance (and
 chaos results if the user forgets).
 
-.. literalinclude:: /js/solution-2-c.js
+.. literalinclude:: /core-javascript-work/solution-2-c.js
    :language: javascript
 
 A minor point is the trailing sequence of right curly braces.  Two are
@@ -64,21 +64,28 @@
 happens if we put a semicolon there?
 
 
-A Class class
--------------
+A SimpleClass solution
+----------------------
 
 Here's another solution to the third task, which does not require the
 user to supply a *new* operator when creating instances.  Instead it
 uses a factory function, which we call *Class* , that creates an
 instance constructor function from a prototype object.
 
-.. literalinclude:: /js/solution-2-d.js
+.. literalinclude:: /core-javascript-work/solution-2-d.js
    :language: javascript
 
 
-A bound method class
+Exercise: write test
 --------------------
 
+Here's an exercise.  Write a JavaScript file that tests this solution.
+
+
+Exercise: bound method class
+----------------------------
+
+
 Recall that this-based instance methods are somewhat fragile.  In
 other words, code like this will fail (and make unwanted changes to
 the global object):
@@ -101,3 +108,5 @@
    var myclass = {}    // The prototype object.
    // Add methods to myclass.
    var MyClass = BoundMethodClass(myclass);
+
+The exercise is to create (and test) a BoundMethodClass factory.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core-javascript/testtools.rst	Tue Nov 01 08:58:38 2011 +0000
@@ -0,0 +1,76 @@
+Test tools
+==========
+
+To make it easier to test code, and to ensure that example code is
+correct, there is a small testtools.js file in the work folder.
+
+
+How to write tests
+------------------
+
+To prepare a test create a file like this.  It's also in the work
+folder.  (For real examples the file will give *assert* a more
+interesting argument, whose truth or falsity is perhaps not obvious.)
+
+.. literalinclude:: /core-javascript-work/demo_testtools.js
+   :language: javascript
+
+
+How to run tests
+----------------
+
+Here's how to run the tests at the command line, finishing with a
+command prompt that allows you inspect the state and also run the test
+again.
+
+
+Rhino
+^^^^^
+
+For Rhino use *load* to run the test again.
+
+.. code-block:: sh
+
+   core-javascript-work$ js -f testtools.js -f demo_testtools.js -f -
+   Testing: all-pass
+   Testing: 2-4-fail
+   ! assert 2 has failed
+   ! assert 4 has failed
+   Rhino 1.7 release 2 2010 01 20
+   js> load('demo_testtools.js')  // You type this.
+   Testing: all-pass
+   Testing: 2-4-fail
+   ! assert 2 has failed
+   ! assert 4 has failed
+   js>
+
+
+JSDB
+^^^^
+
+For JSDB use *run* to run the test again.
+
+.. code-block:: sh
+
+   C:core-javascript-work> jsdb -load testtools.js -load demo_testtools.js
+   Testing: all-pass
+   Testing: 2-4-fail
+   ! assert 2 has failed
+   ! assert 4 has failed
+   js> load('demo_testtools.js')  // You type this.
+   Testing: all-pass
+   Testing: 2-4-fail
+   ! assert 2 has failed
+   ! assert 4 has failed
+   js>
+
+
+testools.js
+-----------
+
+(Optional on a first reading.)  Here's the file testools.js.  It's
+short and simple (and has a not-nice dependency on global variables).
+It also has a branch based on whether it's being run on JSDB or Rhino.
+
+.. literalinclude:: /core-javascript-work/testtools.js
+   :language: javascript
--- a/core-javascript/what-is-new.rst	Mon Oct 31 14:22:00 2011 +0000
+++ b/core-javascript/what-is-new.rst	Tue Nov 01 08:58:38 2011 +0000
@@ -1,6 +1,16 @@
 What is new?
 ============
 
+This can be omitted at a first reading, and omitted altogether if you
+never have to deal with code that uses the *new* operator.  If you do,
+then you **must** read about the missing *new* problem.
+
+JavaScript has an object tree.  This is a fundamental language
+feature.  The *new* operator is a way of adding objects to the tree.
+The *create* function, which is built-in to the latest version of
+JavaScript, can be defined in terms of *new*, and vice versa.
+
+
 Test code
 ---------
 
@@ -9,11 +19,44 @@
    :start-after: start new-operator
    :end-before: end new-operator
 
+
 Discussion
 ----------
 
-Explanation
------------
+By changing the prototype object of *Fn* we start building a tree of
+objects.
+
+There is a built-in relation between an object and its parent.  There
+is no relation between the object and its constructor, here called
+*Fn*, except that at the time of construction the parent of the object
+is Fn.prototype.
+
+The exact rules for the behaviour of *new* are complicated and not
+given here.
+
+
+No missing *new* warning
+------------------------
 
-Exercises
----------
+We saw that when *Fn* is called without the *new* then during its
+execution the value of *this* is the global object.  If the
+constructor *Fn* mutates *this* (and almost every constructor does),
+then it is the global object that is mutated.
+
+This is very bad:
+
+#. You may clobber someone elses data.
+
+#. Someone else may clobber your data.
+
+#. If you create two instances, you will clobber your own data.
+
+#. Testing for this error involves extra work.
+
+#. Bugs that arise from this error can appear random and can be hard
+   to find.
+
+.. note::
+
+   Crockford writes **A much better alternative is to not use new at
+   all."**