From e511e0705eb3ed848403fc1dee333a0dec02892a Mon Sep 17 00:00:00 2001 From: Bob Cassels Date: Wed, 17 Jun 2015 03:06:30 -0400 Subject: [PATCH 01/31] Rename degree trig functions; fix accuracy; add radian trig functions; add tests. --- jquery-turtle.js | 108 +++++++++++++++++++++++++++++++----- test/globals.html | 7 +++ test/numeric_functions.html | 47 ++++++++++++++++ 3 files changed, 147 insertions(+), 15 deletions(-) create mode 100644 test/numeric_functions.html diff --git a/jquery-turtle.js b/jquery-turtle.js index 7633e73..0c58411 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -8047,41 +8047,119 @@ var dollar_turtle_methods = { ["abs(x) The absolute value of x. " + "see abs -5"], Math.abs), acos: wrapraw('acos', - ["acos(degreees) Trigonometric arccosine, in degrees. " + + ["acos(radians) Trigonometric arccosine, in radians. " + "see acos 0.5"], - function acos(x) { return roundEpsilon(Math.acos(x) * 180 / Math.PI); } + function acos(x) { return Math.acos(x); } ), asin: wrapraw('asin', - ["asin(degreees) Trigonometric arcsine, in degrees. " + + ["asin(radians) Trigonometric arcsine, in radians. " + "see asin 0.5"], - function asin(x) { return roundEpsilon(Math.asin(x) * 180 / Math.PI); } + function asin(x) { return Math.asin(x); } ), atan: wrapraw('atan', - ["atan(degreees) Trigonometric arctangent, in degrees. " + + ["atan(radians) Trigonometric arctangent, in radians. " + "see atan 0.5"], - function atan(x) { return roundEpsilon(Math.atan(x) * 180 / Math.PI); } + function atan(x) { return Math.atan(x); } ), atan2: wrapraw('atan2', - ["atan2(degreees) Trigonometric two-argument arctangent, " + - "in degrees. see atan -1, 0"], + ["atan2(radians) Trigonometric two-argument arctangent, " + + "in radians. see atan -1, 0"], function atan2(x, y) { - return roundEpsilon(Math.atan2(x, y) * 180 / Math.PI); + return Math.atan2(x, y); }), cos: wrapraw('cos', - ["cos(degreees) Trigonometric cosine, in degrees. " + + ["cos(radians) Trigonometric cosine, in radians. " + "see cos 45"], - function cos(x) { return roundEpsilon(Math.cos((x % 360) * Math.PI / 180)); } + function cos(x) { return Math.cos((x % 360) * Math.PI / 180); } ), sin: wrapraw('sin', - ["sin(degreees) Trigonometric sine, in degrees. " + + ["sin(radians) Trigonometric sine, in radians. " + "see sin 45"], - function sin(x) { return roundEpsilon(Math.sin((x % 360) * Math.PI / 180)); } + function sin(x) { return Math.sin((x % 360) * Math.PI / 180); } ), tan: wrapraw('tan', - ["tan(degreees) Trigonometric tangent, in degrees. " + + ["tan(radians) Trigonometric tangent, in radians. " + "see tan 45"], - function tan(x) { return roundEpsilon(Math.tan((x % 360) * Math.PI / 180)); } + function tan(x) { return Math.tan((x % 360) * Math.PI / 180); } ), + acosd: wrapraw('acosd', + ["acosd(degrees) Trigonometric arccosine, in degrees. " + + "see acosd 0.5"], + function acosd(x) { return Math.acos(x); } + ), + asind: wrapraw('asind', + ["asind(degrees) Trigonometric arcsine, in degrees. " + + "see asind 0.5"], + function asind(x) { return Math.asin(x); } + ), + atand: wrapraw('atand', + ["atand(degrees) Trigonometric arctangent, in degrees. " + + "see atand 0.5"], + function atand(x) { return Math.atan(x); } + ), + atan2d: wrapraw('atan2d', + ["atan2d(degrees) Trigonometric two-argument arctangent, " + + "in degrees. see atand -1, 0"], + function atan2d(x, y) { + return Math.atan2(x, y); + }), + cosd: wrapraw('cosd', + ["cosd(degrees) Trigonometric cosine, in degrees. " + + "see cosd 45"], + function cosd(x) { + x = x % 360; + if (x % 30 === 0) { + switch ((x < 0) ? x + 360 : x) { + case 0: return 1; + case 60: return .5; + case 90: return 0; + case 120: return -.5; + case 180: return -1; + case 240: return -.5; + case 270: return 0; + case 300: return .5; + } + } + return Math.cos(x / 180 * Math.PI); + }), + sind: wrapraw('sind', + ["sind(degrees) Trigonometric sine, in degrees. " + + "see sind 45"], + function sind(x) { + x = x % 360; + if (x % 30 === 0) { + switch ((x < 0) ? x + 360 : x) { + case 0: return 0; + case 30: return .5; + case 90: return 1; + case 150: return .5; + case 180: return 0; + case 210: return -.5; + case 270: return -1; + case 330: return -.5 + } + } + return Math.sin(x / 180 * Math.PI); + }), + tand: wrapraw('tand', + ["tand(degrees) Trigonometric tangent, in degrees. " + + "see tand 45"], + function tand(x) { + x = x % 360; + if (x % 45 === 0) { + switch ((x < 0) ? x + 360 : x) { + case 0: return 0; + case 45: return 1; + case 90: return Infinity; + case 135: return -1; + case 180: return 0; + case 225: return 1; + case 270: return Infinity; + case 315: return -1 + } + } + return Math.tan(x / 180 * Math.PI); + }), ceil: wrapraw('ceil', ["ceil(x) Round up. " + "see ceil 1.9"], Math.ceil), diff --git a/test/globals.html b/test/globals.html index 0376880..6f5b8c6 100644 --- a/test/globals.html +++ b/test/globals.html @@ -86,6 +86,13 @@ "cos", "sin", "tan", + "acosd", + "asind", + "atand", + "atan2d", + "cosd", + "sind", + "tand", "ceil", "floor", "round", diff --git a/test/numeric_functions.html b/test/numeric_functions.html new file mode 100644 index 0000000..368e893 --- /dev/null +++ b/test/numeric_functions.html @@ -0,0 +1,47 @@ + + + + + +
+ From a278ee91f73ae0cb36671b640e7c2d7c99014931 Mon Sep 17 00:00:00 2001 From: Bob Cassels Date: Fri, 19 Jun 2015 23:11:46 -0400 Subject: [PATCH 02/31] Replace atan2 with 2-arg atan; implement inverse trig functions. --- jquery-turtle.js | 126 +++++++++++++++++++++--------------- test/globals.html | 2 - test/numeric_functions.html | 32 ++++++++- 3 files changed, 105 insertions(+), 55 deletions(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index 0c58411..d375efa 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -7628,6 +7628,8 @@ $.fn.extend(turtlefn); var turtleGIFUrl = "data:image/gif;base64,R0lGODlhKAAwAPIFAAAAAAFsOACSRTCuSICAgP///wAAAAAAACH5BAlkAAYAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAKAAwAAAD72i6zATEgBCAebHpzUnxhDAMAvhxKOoV3ziuZyo3RO26dTbvgXj/gsCO9ysOhENZz+gKJmcUkmA6PSKfSqrWieVtuU+KGNXbXofLEZgR/VHCgdua4isGz9mbmM6U7/94BmlyfUZ1fhqDhYuGgYqMkCOBgo+RfWsNlZZ3ewIpcZaIYaF6XaCkR6aokqqrk0qrqVinpK+fsbZkuK2ouRy0ob4bwJbCibthh6GYebGcY7/EsWqTbdNG1dd9jnXPyk2d38y0Z9Yub2yA6AvWPYk+zEnkv6xdCoPuw/X2gLqy9vJIGAN4b8pAgpQOIlzI8EkCACH5BAlkAAYALAAAAAAoADAAAAPuaLrMBMSAEIB5senNSfGEMAwC+HEo6hXfOK5nKjdE7bp1Nu+BeP+CwI73Kw6EQ1nP6AomZxSSYDo9Ip9KqtaJ5W25Xej3qqGYsdEfZbMcgZXtYpActzLMeLOP6c7f3nVNfEZ7TXSFg4lyZAYBio+LZYiQfHMbc3iTlG9ilGpdjp4ujESiI6RQpqegqkesqqhKrbEpoaa0KLaiuBy6nrxss6+3w7tomo+cDXmBnsoLza2nsb7SN2tl1nyozVOZTJhxysxnd9XYCrrAtT7KQaPruavBo2HQ8xrvffaN+GV5/JbE45fOG8Ek5Q4qXHgwAQA7" +function modulo(n, m) { return (+n % (m = +m) + m) % m; } + var eventfn = { click:1, dblclick:1, mouseup:1, mousedown:1, mousemove:1 }; function global_turtle_animating() { @@ -8047,77 +8049,97 @@ var dollar_turtle_methods = { ["abs(x) The absolute value of x. " + "see abs -5"], Math.abs), acos: wrapraw('acos', - ["acos(radians) Trigonometric arccosine, in radians. " + + ["acos(x) Trigonometric arccosine, in radians. " + "see acos 0.5"], function acos(x) { return Math.acos(x); } ), asin: wrapraw('asin', - ["asin(radians) Trigonometric arcsine, in radians. " + + ["asin(y) Trigonometric arcsine, in radians. " + "see asin 0.5"], - function asin(x) { return Math.asin(x); } + function asin(y) { return Math.asin(y); } ), atan: wrapraw('atan', - ["atan(radians) Trigonometric arctangent, in radians. " + + ["atan(y, x = 1) Trigonometric arctangent, in radians. " + "see atan 0.5"], - function atan(x) { return Math.atan(x); } + function atan(x, y) { return Math.atan2(x, (y == undefined) ? 1 : y); } ), - atan2: wrapraw('atan2', - ["atan2(radians) Trigonometric two-argument arctangent, " + - "in radians. see atan -1, 0"], - function atan2(x, y) { - return Math.atan2(x, y); - }), cos: wrapraw('cos', ["cos(radians) Trigonometric cosine, in radians. " + - "see cos 45"], - function cos(x) { return Math.cos((x % 360) * Math.PI / 180); } + "see cos 0"], + function cos(x) { return Math.cos(x); } ), sin: wrapraw('sin', ["sin(radians) Trigonometric sine, in radians. " + - "see sin 45"], - function sin(x) { return Math.sin((x % 360) * Math.PI / 180); } + "see sin 0"], + function sin(x) { return Math.sin(x); } ), tan: wrapraw('tan', ["tan(radians) Trigonometric tangent, in radians. " + - "see tan 45"], - function tan(x) { return Math.tan((x % 360) * Math.PI / 180); } + "see tan 0"], + function tan(x) { return Math.tan(x); } ), + + // For degree versions of trig functions, make sure we return exact + // results when possible. The set of values we have to consider is + // fortunately very limited. See "Rational Values of Trigonometric + // Functions." http://www.jstor.org/stable/2304540 + acosd: wrapraw('acosd', - ["acosd(degrees) Trigonometric arccosine, in degrees. " + + ["acosd(x) Trigonometric arccosine, in degrees. " + "see acosd 0.5"], - function acosd(x) { return Math.acos(x); } - ), + function acosd(x) { + switch (x) { + case 1: return 0; + case .5: return 60; + case 0: return 90; + case -.5: return 120; + case -1: return 180; + } + return Math.acos(x) * 180 / Math.PI; + }), asind: wrapraw('asind', - ["asind(degrees) Trigonometric arcsine, in degrees. " + + ["asind(x) Trigonometric arcsine, in degrees. " + "see asind 0.5"], - function asind(x) { return Math.asin(x); } - ), + function asind(x) { + switch (x) { + case 1: return 90; + case .5: return 30; + case 0: return 0; + case -.5: return -30; + case -1: return -90; + } + return Math.asin(x) * 180 / Math.PI; + }), atand: wrapraw('atand', - ["atand(degrees) Trigonometric arctangent, in degrees. " + - "see atand 0.5"], - function atand(x) { return Math.atan(x); } - ), - atan2d: wrapraw('atan2d', - ["atan2d(degrees) Trigonometric two-argument arctangent, " + - "in degrees. see atand -1, 0"], - function atan2d(x, y) { - return Math.atan2(x, y); + ["atand(y, x = 1) Trigonometric arctangent, " + + "in degrees. see atand -1, 0/mark>"], + function atand(y, x) { + if (x == undefined) { x = 1; } + if (y == 0) { + return (x == 0) ? NaN : ((x > 0) ? 0 : 180); + } else if (x == 0) { + return (y > 0) ? Infinity : -Infinity; + } else if (abs(y) == abs(x)) { + return (y > 0) ? ((x > 0) ? 45 : 135) : + ((x > 0) ? -45 : -135); + } + return Math.atan2(y, x) * 180 / Math.PI; }), cosd: wrapraw('cosd', ["cosd(degrees) Trigonometric cosine, in degrees. " + "see cosd 45"], function cosd(x) { - x = x % 360; + x = modulo(x, 360); if (x % 30 === 0) { switch ((x < 0) ? x + 360 : x) { - case 0: return 1; - case 60: return .5; - case 90: return 0; + case 0: return 1; + case 60: return .5; + case 90: return 0; case 120: return -.5; - case 180: return -1; + case 180: return -1; case 240: return -.5; - case 270: return 0; - case 300: return .5; + case 270: return 0; + case 300: return .5; } } return Math.cos(x / 180 * Math.PI); @@ -8126,17 +8148,17 @@ var dollar_turtle_methods = { ["sind(degrees) Trigonometric sine, in degrees. " + "see sind 45"], function sind(x) { - x = x % 360; + x = modulo(x, 360); if (x % 30 === 0) { switch ((x < 0) ? x + 360 : x) { - case 0: return 0; - case 30: return .5; - case 90: return 1; - case 150: return .5; - case 180: return 0; + case 0: return 0; + case 30: return .5; + case 90: return 1; + case 150: return .5; + case 180: return 0; case 210: return -.5; - case 270: return -1; - case 330: return -.5 + case 270: return -1; + case 330: return -.5; } } return Math.sin(x / 180 * Math.PI); @@ -8145,16 +8167,16 @@ var dollar_turtle_methods = { ["tand(degrees) Trigonometric tangent, in degrees. " + "see tand 45"], function tand(x) { - x = x % 360; + x = modulo(x, 360); if (x % 45 === 0) { switch ((x < 0) ? x + 360 : x) { - case 0: return 0; - case 45: return 1; - case 90: return Infinity; + case 0: return 0; + case 45: return 1; + case 90: return Infinity; case 135: return -1; case 180: return 0; case 225: return 1; - case 270: return Infinity; + case 270: return -Infinity; case 315: return -1 } } diff --git a/test/globals.html b/test/globals.html index 6f5b8c6..7ab6874 100644 --- a/test/globals.html +++ b/test/globals.html @@ -82,14 +82,12 @@ "acos", "asin", "atan", - "atan2", "cos", "sin", "tan", "acosd", "asind", "atand", - "atan2d", "cosd", "sind", "tand", diff --git a/test/numeric_functions.html b/test/numeric_functions.html index 368e893..49ee2df 100644 --- a/test/numeric_functions.html +++ b/test/numeric_functions.html @@ -11,6 +11,9 @@ ok(sin(0) === 0); ok(cos(0) === 1); ok(tan(0) === 0); + ok(asin(0) === 0); + ok(acos(1) === 0); + ok(atan(0) === 0); ok(sind(0) === 0); ok(sind(30) === .5); @@ -37,9 +40,36 @@ ok(tand(135) === -1); ok(tand(180) === 0); ok(tand(225) === 1); - ok(tand(270) === Infinity); + ok(tand(270) === -Infinity); ok(tand(315) === -1); ok(tand(360) === 0); + + ok(asind(0) === 0); + ok(asind(.5) === 30); + ok(asind(1) === 90); + ok(asind(-.5) === -30); + ok(asind(-1) === -90); + + ok(acosd(1) === 0); + ok(acosd(.5) === 60); + ok(acosd(0) === 90); + ok(acosd(-.5) === 120); + ok(acosd(-1) === 180); + + ok(atand(0) === 0); + ok(atand(1) === 45); + ok(atand(Infinity) === 90); + ok(atand(-1) === -45); + ok(atand(0, 1) === 0); + ok(atand(1, 1) === 45); + ok(atand(Infinity, 1) === 90); + ok(atand(-1, 1) === -45); + ok(atand(0, -1) === 180); + ok(atand(1, -1) === 135); + ok(atand(-Infinity) === -90); + ok(atand(-Infinity, 1) === -90); + ok(atand(-1, -1) === -135); + done(function() { start(); }); From 8c2fe217e3905127f27971c04cee699280dde69d Mon Sep 17 00:00:00 2001 From: Bob Cassels Date: Fri, 19 Jun 2015 23:18:10 -0400 Subject: [PATCH 03/31] Fix indentation, arg names for atan. --- jquery-turtle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index d375efa..10b64fd 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -8061,7 +8061,7 @@ var dollar_turtle_methods = { atan: wrapraw('atan', ["atan(y, x = 1) Trigonometric arctangent, in radians. " + "see atan 0.5"], - function atan(x, y) { return Math.atan2(x, (y == undefined) ? 1 : y); } + function atan(y, x) { return Math.atan2(y, (x == undefined) ? 1 : x); } ), cos: wrapraw('cos', ["cos(radians) Trigonometric cosine, in radians. " + From cf0efe37da90c2e93de1b1a7132811e86ed25568 Mon Sep 17 00:00:00 2001 From: Bob Cassels Date: Fri, 19 Jun 2015 23:59:01 -0400 Subject: [PATCH 04/31] Use simple form for sin, cos, etc. radians versions. --- jquery-turtle.js | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index 10b64fd..8ec182f 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -8050,14 +8050,10 @@ var dollar_turtle_methods = { "see abs -5"], Math.abs), acos: wrapraw('acos', ["acos(x) Trigonometric arccosine, in radians. " + - "see acos 0.5"], - function acos(x) { return Math.acos(x); } - ), + "see acos 0.5"], Math.acos), asin: wrapraw('asin', ["asin(y) Trigonometric arcsine, in radians. " + - "see asin 0.5"], - function asin(y) { return Math.asin(y); } - ), + "see asin 0.5"], Math.asin), atan: wrapraw('atan', ["atan(y, x = 1) Trigonometric arctangent, in radians. " + "see atan 0.5"], @@ -8065,19 +8061,13 @@ var dollar_turtle_methods = { ), cos: wrapraw('cos', ["cos(radians) Trigonometric cosine, in radians. " + - "see cos 0"], - function cos(x) { return Math.cos(x); } - ), + "see cos 0"], Math.cos), sin: wrapraw('sin', ["sin(radians) Trigonometric sine, in radians. " + - "see sin 0"], - function sin(x) { return Math.sin(x); } - ), + "see sin 0"], Math.sin), tan: wrapraw('tan', ["tan(radians) Trigonometric tangent, in radians. " + - "see tan 0"], - function tan(x) { return Math.tan(x); } - ), + "see tan 0"], Math.tan), // For degree versions of trig functions, make sure we return exact // results when possible. The set of values we have to consider is From b3c3f68462b4ea77202e45674dd94f51d944e350 Mon Sep 17 00:00:00 2001 From: Bob Cassels Date: Sat, 20 Jun 2015 00:11:45 -0400 Subject: [PATCH 05/31] Make convertToRadians a tiny bit more accurate. Move modulo. --- jquery-turtle.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index 8ec182f..62fe284 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -1487,6 +1487,8 @@ function writeTurtleTransform(ts) { return result.join(' '); } +function modulo(n, m) { return (+n % (m = +m) + m) % m; } + function radiansToDegrees(r) { var d = r * 180 / Math.PI; if (d > 180) { d -= 360; } @@ -1494,7 +1496,7 @@ function radiansToDegrees(r) { } function convertToRadians(d) { - return d * Math.PI / 180; + return d / 180 * Math.PI; } function normalizeRotation(x) { @@ -7628,8 +7630,6 @@ $.fn.extend(turtlefn); var turtleGIFUrl = "data:image/gif;base64,R0lGODlhKAAwAPIFAAAAAAFsOACSRTCuSICAgP///wAAAAAAACH5BAlkAAYAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAKAAwAAAD72i6zATEgBCAebHpzUnxhDAMAvhxKOoV3ziuZyo3RO26dTbvgXj/gsCO9ysOhENZz+gKJmcUkmA6PSKfSqrWieVtuU+KGNXbXofLEZgR/VHCgdua4isGz9mbmM6U7/94BmlyfUZ1fhqDhYuGgYqMkCOBgo+RfWsNlZZ3ewIpcZaIYaF6XaCkR6aokqqrk0qrqVinpK+fsbZkuK2ouRy0ob4bwJbCibthh6GYebGcY7/EsWqTbdNG1dd9jnXPyk2d38y0Z9Yub2yA6AvWPYk+zEnkv6xdCoPuw/X2gLqy9vJIGAN4b8pAgpQOIlzI8EkCACH5BAlkAAYALAAAAAAoADAAAAPuaLrMBMSAEIB5senNSfGEMAwC+HEo6hXfOK5nKjdE7bp1Nu+BeP+CwI73Kw6EQ1nP6AomZxSSYDo9Ip9KqtaJ5W25Xej3qqGYsdEfZbMcgZXtYpActzLMeLOP6c7f3nVNfEZ7TXSFg4lyZAYBio+LZYiQfHMbc3iTlG9ilGpdjp4ujESiI6RQpqegqkesqqhKrbEpoaa0KLaiuBy6nrxss6+3w7tomo+cDXmBnsoLza2nsb7SN2tl1nyozVOZTJhxysxnd9XYCrrAtT7KQaPruavBo2HQ8xrvffaN+GV5/JbE45fOG8Ek5Q4qXHgwAQA7" -function modulo(n, m) { return (+n % (m = +m) + m) % m; } - var eventfn = { click:1, dblclick:1, mouseup:1, mousedown:1, mousemove:1 }; function global_turtle_animating() { From 6756b7d0c378a524e90b82e87fea2560818c6ca1 Mon Sep 17 00:00:00 2001 From: David Bau Date: Sat, 1 Aug 2015 04:12:16 -0400 Subject: [PATCH 06/31] Support sending DOM elements to label. --- jquery-turtle.js | 8 +++++++- test/label.html | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index 3e2d6d1..f8b9318 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -3695,7 +3695,7 @@ function forwardBodyMouseEventsIfNeeded() { var warn = $.turtle.nowarn; $.turtle.nowarn = true; var sel = $(globalDrawing.surface) - .find('.turtle').within('touch', e).eq(0); + .find('.turtle,.turtlelabel').within('touch', e).eq(0); $.turtle.nowarn = warn; if (sel.length === 1) { // Erase portions of the event that are wrong for the turtle. @@ -7050,6 +7050,10 @@ var turtlefn = { // Place the label on the screen using the figured styles. var out = prepareOutput(html, 'label').result.css(applyStyles) .addClass('turtlelabel').appendTo(getTurtleField()); + // If the output has a turtleinput, then forward mouse events. + if (out.hasClass('turtleinput') || out.find('.turtleinput').length) { + mouseSetupHook.apply(out.get(0)); + } if (styles && 'id' in styles) { out.attr('id', styles.id); } @@ -9256,6 +9260,8 @@ function prepareOutput(html, tag) { if (html === undefined || html === null) { // Make empty line when no arguments. return {result: $(prefix + '
' + suffix)}; + } else if (html.jquery || (html instanceof Element && (html = $(html)))) { + return {result: html}; } else { var wrapped = false, result = null; html = '' + html; diff --git a/test/label.html b/test/label.html index 08983f4..927b318 100644 --- a/test/label.html +++ b/test/label.html @@ -62,6 +62,10 @@ equal(rounded($('label:contains(bottomleft)').direction()), 0); equal(direction(), 90); equal(rounded($('label:contains(upside down)').direction()), 180); + var b; + label(b = button('hello')); + ok(touches(b)); + equal(b.direction(), 90); start(); }); }); From 6ee424c34c45fdfdc60159348f0cbee8fa23291c Mon Sep 17 00:00:00 2001 From: David Bau Date: Fri, 7 Aug 2015 13:55:23 -0400 Subject: [PATCH 07/31] Rename log to debug. --- jquery-turtle.js | 7 ++++++- test/globals.html | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index 03b214e..e1e4cdd 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -8405,7 +8405,7 @@ $.turtle = function turtle(id, options) { global.onerror = see; } // Set up an alias. - global.log = see; + global.debug = see; } // Copy $.turtle.* functions into global namespace. if (!('functions' in options) || options.functions) { @@ -10701,6 +10701,11 @@ function initconsolelog() { _log.apply(this, arguments); see.apply(this, arguments); } + var _debug = global.console._debug = global.console.debug; + global.console.debug = function debug() { + _debug.apply(this, arguments); + see.apply(this, arguments); + } } } catch(e) { } } diff --git a/test/globals.html b/test/globals.html index ccbd1bd..d45d30b 100644 --- a/test/globals.html +++ b/test/globals.html @@ -31,7 +31,7 @@ "lastmousedown", "lastmousemove", "see", - "log", + "debug", "printpage", "interrupt", "cs", From 91fe1a24c2afddbb4e6c5a3809727ad0ed780b06 Mon Sep 17 00:00:00 2001 From: David Bau Date: Fri, 7 Aug 2015 21:28:59 -0400 Subject: [PATCH 08/31] Include log as a deprecated version of debug. --- jquery-turtle.js | 2 ++ test/globals.html | 1 + 2 files changed, 3 insertions(+) diff --git a/jquery-turtle.js b/jquery-turtle.js index e1e4cdd..bbc58fd 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -8406,6 +8406,8 @@ $.turtle = function turtle(id, options) { } // Set up an alias. global.debug = see; + // 'debug' should be used now instead of log + deprecate(global, 'log', 'debug'); } // Copy $.turtle.* functions into global namespace. if (!('functions' in options) || options.functions) { diff --git a/test/globals.html b/test/globals.html index d45d30b..5be33a5 100644 --- a/test/globals.html +++ b/test/globals.html @@ -32,6 +32,7 @@ "lastmousemove", "see", "debug", + "log", "printpage", "interrupt", "cs", From 559d8a6932aa535133d8ac53223ac492d222395f Mon Sep 17 00:00:00 2001 From: David Bau Date: Sat, 8 Aug 2015 06:30:43 -0400 Subject: [PATCH 09/31] Remove default padding from label. --- jquery-turtle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index 5cd1c1a..c38d6fd 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -7091,7 +7091,7 @@ var turtlefn = { var intick = insidetick; return this.plan(function(j, elem) { cc.appear(j); - var applyStyles = {padding: 8}, + var applyStyles = {}, currentStyles = this.prop('style'); // For defaults, copy inline styles of the turtle itself except for // properties in the following list (these are the properties used to From edaf4b74d21731e91cea550eb500abdd4d462f7a Mon Sep 17 00:00:00 2001 From: David Bau Date: Sun, 13 Sep 2015 06:54:40 -0400 Subject: [PATCH 10/31] Fix for crash on unparented element with speed infinity. --- jquery-turtle.js | 2 +- test/wear.html | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index c38d6fd..bc26c13 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -5761,7 +5761,7 @@ function canElementMoveInstantly(elem) { // moving at speed Infinity. var atime; return (elem && $.queue(elem).length == 0 && - !elem.parentElement.style.transform && + (!elem.parentElement || !elem.parentElement.style.transform) && ((atime = animTime(elem)) === 0 || $.fx.speeds[atime] === 0)); } diff --git a/test/wear.html b/test/wear.html index 9b91ca6..eed8ddc 100644 --- a/test/wear.html +++ b/test/wear.html @@ -64,6 +64,8 @@ wear(blue); pause(0.1, function() { ok(b.touches(blue)); + // Verify we don't crash when using wear on a disconnected canvas. + $('').css({ position: 'absolute' }).wear('pencil'); setTimeout(start, 0); }); }); From 38ddc83f865815d553738e9455e69863cd8b5774 Mon Sep 17 00:00:00 2001 From: David Bau Date: Thu, 24 Sep 2015 11:51:26 -0400 Subject: [PATCH 11/31] Make jQuery show/hide queue by default on ".turtle" objects. --- jquery-turtle.js | 56 ++++++++++++++++++++++++++++++++++++++--------- test/globals.html | 2 ++ test/hide.html | 29 ++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 test/hide.html diff --git a/jquery-turtle.js b/jquery-turtle.js index bc26c13..0b6fc22 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -7571,6 +7571,33 @@ var turtlefn = { }) }; +////////////////////////////////////////////////////////////////////////// +// QUEUING SUPPORT +////////////////////////////////////////////////////////////////////////// + +function queueShowHideToggle() { + $.each(['toggle', 'show', 'hide'], function(i, name) { + + + var builtInFn = $.fn[name]; + // Change show/hide/toggle to queue their behavior by default. + // Since animating show/hide will call the zero-argument + // form synchronously at the end of animation, we avoid + // infinite recursion by examining jQuery's internal fxshow + // state and avoiding the recursion if the animation is calling + // show/hide. + $.fn[name] = function(speed, easing, callback) { + var a = arguments; + // TODO: file a bug in jQuery to allow solving this without _data. + if (!a.length && this.hasClass('turtle') && + (this.length > 1 || !$._data(this[0], 'fxshow'))) { + a = [0]; + } + builtInFn.apply(this, a); + } + }); +} + // If the queue for an image is empty, starts by queuing a wait-for-load. function queueWaitIfLoadingImg(img, qname) { if (!qname) qname = 'fx'; @@ -7585,6 +7612,10 @@ function queueWaitIfLoadingImg(img, qname) { } } +////////////////////////////////////////////////////////////////////////// +// HUNG LOOP DETECTION +////////////////////////////////////////////////////////////////////////// + var warning_shown = {}, loopCounter = 0, hungTimer = null, @@ -8452,15 +8483,15 @@ $.turtle = function turtle(id, options) { parseFloat(options.hangtime) : 20000; // Set up global events. - if (!('events' in options) || options.events) { + if (options.events !== false) { turtleevents(options.eventprefix); } - if (!('pressed' in options) || options.pressed) { + if (options.pressed !== false) { addKeyEventHooks(); pressedKey.enable(true); } // Set up global log function. - if (!('see' in options) || options.see) { + if (options.see !== false) { exportsee(); exportedsee = true; if (global.addEventListener) { @@ -8473,8 +8504,12 @@ $.turtle = function turtle(id, options) { // 'debug' should be used now instead of log deprecate(global, 'log', 'debug'); } + if (options.queuehide !== false) { + queueShowHideToggle(); + } + // Copy $.turtle.* functions into global namespace. - if (!('functions' in options) || options.functions) { + if (options.functions !== false) { global.printpage = global.print; $.extend(global, dollar_turtle_methods); } @@ -8501,11 +8536,11 @@ $.turtle = function turtle(id, options) { } if (selector && !selector.length) { selector = null; } // Globalize selected jQuery methods of a singleton turtle. - if (selector && selector.length === 1 && - (!('global' in options) || options.global)) { + if (selector && selector.length === 1 && (options.global !== false)) { var extraturtlefn = { css:1, fadeIn:1, fadeOut:1, fadeTo:1, fadeToggle:1, - animate:1, toggle:1, finish:1, promise:1, direct:1 }; + animate:1, toggle:1, finish:1, promise:1, direct:1, + show:1, hide:1 }; var globalfn = $.extend({}, turtlefn, extraturtlefn); global_turtle_methods.push.apply(global_turtle_methods, globalizeMethods(selector, globalfn)); @@ -8514,14 +8549,14 @@ $.turtle = function turtle(id, options) { selector.css({zIndex: 1}); } // Set up global objects by id. - if (!('ids' in options) || options.ids) { + if (options.ids !== false) { turtleids(options.idprefix); if (selector && id) { global[id] = selector; } } // Set up test console. - if (!('panel' in options) || options.panel) { + if (options.panel !== false) { var seeopt = { title: 'test panel (type help for help)', abbreviate: [undefined, helpok], @@ -10296,7 +10331,8 @@ function isprimitive(vt) { } function isdom(obj) { - return (obj.nodeType && obj.nodeName && typeof(obj.cloneNode) == 'function'); + return (obj && obj.nodeType && obj.nodeName && + typeof(obj.cloneNode) == 'function'); } function midtruncate(s, maxlen) { diff --git a/test/globals.html b/test/globals.html index 7033d33..5c760fc 100644 --- a/test/globals.html +++ b/test/globals.html @@ -331,6 +331,8 @@ "fadeTo", "fadeToggle", "animate", + "show", + "hide", "toggle", "finish", "promise" diff --git a/test/hide.html b/test/hide.html new file mode 100644 index 0000000..7af0f92 --- /dev/null +++ b/test/hide.html @@ -0,0 +1,29 @@ + + + + + +
+ From d4793973c3972f3e384d5a2262fff4d825fc7be3 Mon Sep 17 00:00:00 2001 From: David Bau Date: Thu, 24 Sep 2015 12:08:09 -0400 Subject: [PATCH 12/31] Improve the debug event protocol: bind only if ide says it's ok. --- jquery-turtle.js | 14 +++++--------- test/debugevents.html | 1 + 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index 0b6fc22..892563a 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -9834,18 +9834,14 @@ function autoArgs(arguments, start, map) { ////////////////////////////////////////////////////////////////////////// var debug = { init: function initdebug() { + if (this.ide) return; // Don't re-initialize debug. try { - if (parent && parent.ide) { - if (this.ide !== parent.ide) { - this.ide = parent.ide; - this.ide.bindframe(global); - } + if (parent && parent.ide && parent.ide.bindframe && + parent.ide.bindframe(global, parent)) { + this.ide = parent.ide; this.attached = true; } - } catch(e) { - this.ide = null; - this.attached = false; - } + } catch(e) { } if (this.attached) { if (global.addEventListener) { global.addEventListener('error', function(event) { diff --git a/test/debugevents.html b/test/debugevents.html index 64d3a57..b63142f 100644 --- a/test/debugevents.html +++ b/test/debugevents.html @@ -64,6 +64,7 @@ window.ide = { bindframe: function() { verify('bindframe'); + return true; }, reportEvent: function(eventname, args) { verify([eventname, args[0]]); From 72945b16c69a96d18b2cb6c11484747d50574429 Mon Sep 17 00:00:00 2001 From: David Bau Date: Thu, 24 Sep 2015 15:33:24 -0400 Subject: [PATCH 13/31] Make interrupt robust when AudioContext is closed. --- jquery-turtle.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index 892563a..1c2508e 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -3899,11 +3899,16 @@ function resetAudio() { atop.out = null; atop.currentStart = null; } - var dcn = atop.ac.createDynamicsCompressor(); - dcn.ratio = 16; - dcn.attack = 0.0005; - dcn.connect(atop.ac.destination); - atop.out = dcn; + // If resetting due to interrupt after AudioContext closed, this can fail. + try { + var dcn = atop.ac.createDynamicsCompressor(); + dcn.ratio = 16; + dcn.attack = 0.0005; + dcn.connect(atop.ac.destination); + atop.out = dcn; + } catch (e) { + getAudioTop.audioTop = null; + } } } From 189612044a106365832a87cdfdcbcbc4b84bea00 Mon Sep 17 00:00:00 2001 From: David Bau Date: Mon, 12 Oct 2015 21:27:52 -0400 Subject: [PATCH 14/31] Implementation of readvoice: voice recognition on Chrome. --- jquery-turtle.js | 69 ++++++++++++++++++++++++++++++++++++++++------- test/globals.html | 1 + 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index 1c2508e..fa02719 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -7729,7 +7729,7 @@ $.fn.extend(turtlefn); // * Sets up a global "hatch" function to make a new turtle. ////////////////////////////////////////////////////////////////////////// -var turtleGIFUrl = "data:image/gif;base64,R0lGODlhKAAwAPIFAAAAAAFsOACSRTCuSICAgP///wAAAAAAACH5BAlkAAYAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAKAAwAAAD72i6zATEgBCAebHpzUnxhDAMAvhxKOoV3ziuZyo3RO26dTbvgXj/gsCO9ysOhENZz+gKJmcUkmA6PSKfSqrWieVtuU+KGNXbXofLEZgR/VHCgdua4isGz9mbmM6U7/94BmlyfUZ1fhqDhYuGgYqMkCOBgo+RfWsNlZZ3ewIpcZaIYaF6XaCkR6aokqqrk0qrqVinpK+fsbZkuK2ouRy0ob4bwJbCibthh6GYebGcY7/EsWqTbdNG1dd9jnXPyk2d38y0Z9Yub2yA6AvWPYk+zEnkv6xdCoPuw/X2gLqy9vJIGAN4b8pAgpQOIlzI8EkCACH5BAlkAAYALAAAAAAoADAAAAPuaLrMBMSAEIB5senNSfGEMAwC+HEo6hXfOK5nKjdE7bp1Nu+BeP+CwI73Kw6EQ1nP6AomZxSSYDo9Ip9KqtaJ5W25Xej3qqGYsdEfZbMcgZXtYpActzLMeLOP6c7f3nVNfEZ7TXSFg4lyZAYBio+LZYiQfHMbc3iTlG9ilGpdjp4ujESiI6RQpqegqkesqqhKrbEpoaa0KLaiuBy6nrxss6+3w7tomo+cDXmBnsoLza2nsb7SN2tl1nyozVOZTJhxysxnd9XYCrrAtT7KQaPruavBo2HQ8xrvffaN+GV5/JbE45fOG8Ek5Q4qXHgwAQA7" +var turtleGIFUrl = "data:image/gif;base64,R0lGODlhKAAwAPIFAAAAAAFsOACSRTCuSICAgP///wAAAAAAACH5BAlkAAYAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAKAAwAAAD72i6zATEgBCAebHpzUnxhDAMAvhxKOoV3ziuZyo3RO26dTbvgXj/gsCO9ysOhENZz+gKJmcUkmA6PSKfSqrWieVtuU+KGNXbXofLEZgR/VHCgdua4isGz9mbmM6U7/94BmlyfUZ1fhqDhYuGgYqMkCOBgo+RfWsNlZZ3ewIpcZaIYaF6XaCkR6aokqqrk0qrqVinpK+fsbZkuK2ouRy0ob4bwJbCibthh6GYebGcY7/EsWqTbdNG1dd9jnXPyk2d38y0Z9Yub2yA6AvWPYk+zEnkv6xdCoPuw/X2gLqy9vJIGAN4b8pAgpQOIlzI8EkCACH5BAlkAAYALAAAAAAoADAAAAPuaLrMBMSAEIB5senNSfGEMAwC+HEo6hXfOK5nKjdE7bp1Nu+BeP+CwI73Kw6EQ1nP6AomZxSSYDo9Ip9KqtaJ5W25Xej3qqGYsdEfZbMcgZXtYpActzLMeLOP6c7f3nVNfEZ7TXSFg4lyZAYBio+LZYiQfHMbc3iTlG9ilGpdjp4ujESiI6RQpqegqkesqqhKrbEpoaa0KLaiuBy6nrxss6+3w7tomo+cDXmBnsoLza2nsb7SN2tl1nyozVOZTJhxysxnd9XYCrrAtT7KQaPruavBo2HQ8xrvffaN+GV5/JbE45fOG8Ek5Q4qXHgwAQA7"; var eventfn = { click:1, dblclick:1, mouseup:1, mousedown:1, mousemove:1 }; @@ -8039,12 +8039,16 @@ var dollar_turtle_methods = { readnum: wrapglobalcommand('readnum', ["readnum(html, fn) Reads numeric input. Only numbers allowed: " + "readnum 'Amount?', (v) -> write 'Tip: ' + (0.15 * v)"], - doOutput, function readnum(a, b) { return prepareInput(a, b, 1); }), + doOutput, function readnum(a, b) { return prepareInput(a, b, 'number'); }), readstr: wrapglobalcommand('readstr', ["readstr(html, fn) Reads text input. Never " + "converts input to a number: " + "readstr 'Enter code', (v) -> write v.length + ' long'"], - doOutput, function readstr(a, b) { return prepareInput(a, b, -1); }), + doOutput, function readstr(a, b) { return prepareInput(a, b, 'text'); }), + readvoice: wrapglobalcommand('readvoice', + ["readvoice(html, fn) Reads voice input, if the browser supports it:" + + "readvoice 'Say something', (v) -> write v"], + doOutput, function readstr(a, b) { return prepareInput(a, b, 'voice'); }), menu: wrapglobalcommand('menu', ["menu(map) shows a menu of choices and calls a function " + "based on the user's choice: " + @@ -9635,18 +9639,24 @@ function prepareButton(name, callback) { // for creating an input box with a label, for one-shot input ////////////////////////////////////////////////////////////////////////// +var microphoneSvg = "data:image/svg+xml," + // Simplify $('body').append('' + label) and onchange hookup. -function prepareInput(name, callback, numeric) { +// Type can be 'auto', 'number', 'text', or 'voice' for slightly +// different interfaces. +function prepareInput(name, callback, type) { if ($.isFunction(name) && !callback) { callback = name; name = null; } + if (!type) { type = 'auto'; } name = $.isNumeric(name) || name ? name : '⇒'; var textbox = $('').css({margin:0, padding:0}), label = $('').append(textbox), debounce = null, - lastseen = textbox.val(); + lastseen = textbox.val(), + recognition = null; function dodebounce() { if (!debounce) { debounce = setTimeout(function() { debounce = null; }, 1000); @@ -9660,15 +9670,15 @@ function prepareInput(name, callback, numeric) { lastseen = val; textbox.remove(); label.append(val).css({display: 'table'}); - if (numeric > 0 || ( - numeric >= 0 && $.isNumeric(val) && ('' + parseFloat(val) == val))) { + if (type == 'number' || (type == 'auto' && + $.isNumeric(val) && ('' + parseFloat(val) == val))) { val = parseFloat(val); } label.prop('value', val); if (callback) { setTimeout(function() {callback.call(label, val); }, 0); } } function validate() { - if (numeric <= 0) return true; + if (type != 'numeric') return true; var val = textbox.val(), nval = val.replace(/[^0-9\.]/g, ''); if (val != nval || !$.isNumeric(nval)) { @@ -9682,19 +9692,58 @@ function prepareInput(name, callback, numeric) { if (!validate()) { return false; } newval(); } - if (numeric > 0 && (e.which >= 32 && e.which <= 127) && + if (type == 'voice' && recognition) { + recognition.abort(); + recognition = null; + } + if (type == 'numeric' && (e.which >= 32 && e.which <= 127) && (e.which < '0'.charCodeAt(0) || e.which > '9'.charCodeAt(0)) && (e.which != '.'.charCodeAt(0) || ~textbox.val().indexOf('.'))) { return false; } } + if (type == 'voice' && 'function' == typeof(global.webkitSpeechRecognition)) { + try { + recognition = new global.webkitSpeechRecognition(); + recognition.continuous = false; + recognition.interimResults = true; + textbox.css({backgroundColor: 'lightyellow', + color: 'gray', + backgroundImage: "url(" + microphoneSvg + ")", + backgroundRepeat: 'no-repeat', + backgroundPosition: 'center'}); + recognition.onspeechstart = function() { + textbox.css({background: 'lightgreen'}); + }; + recognition.onend = function() { + textbox.css({color: '', backgroundColor: '', backgroundImage: '', + backgroundRepeat: '', backgroundPosition: ''}); + textbox.val(lastseen); + newval(); + }; + recognition.onresult = function(event) { + var text = event.results[0][0].transcript; + var confidence = event.results[0][0].confidence; + var shade = 128 - 128 * confidence; + if (event.results[0].isFinal) { + shade = 0; + lastseen = text; + } + textbox.css({color: componentColor('rgb', shade, shade, shade)}); + textbox.val(text); + }; + recognition.start(); + } catch (e) { + console.log(e); + } + } textbox.on('keypress keydown', key); textbox.on('change', newval); return { result: label, setup: function() { dodebounce(); - if (numeric < 0) { + if (type == 'text' || type == 'voice') { // Widen a "readstr" textbox to make it fill the line. var availwidth = label.parent().width(), freewidth = availwidth + label.offset().left - textbox.offset().left, diff --git a/test/globals.html b/test/globals.html index 5c760fc..f208663 100644 --- a/test/globals.html +++ b/test/globals.html @@ -60,6 +60,7 @@ "typeline", "read", "readnum", + "readvoice", "readstr", "menu", "random", From b98735d30a54c251defcbfb047bb9b53aa609e52 Mon Sep 17 00:00:00 2001 From: David Bau Date: Tue, 13 Oct 2015 06:55:10 -0400 Subject: [PATCH 15/31] Also allow nonprefixed SpeechRecognition api. --- jquery-turtle.js | 73 +++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index fa02719..19ab9cb 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -9429,8 +9429,8 @@ function plainBoxPrint(clr, text) { maxWidth: '1.2em', overflow: 'hidden' }).appendTo(getTrailingPre()), finish = function() { - if (clr) { elem.css({background: clr}); } - if (text) { elem.text(text); } + if (clr != null) { elem.css({background: clr}); } + if (text != null) { elem.text(text); } }; if (!global_turtle) { finish(); @@ -9702,39 +9702,42 @@ function prepareInput(name, callback, type) { return false; } } - if (type == 'voice' && 'function' == typeof(global.webkitSpeechRecognition)) { - try { - recognition = new global.webkitSpeechRecognition(); - recognition.continuous = false; - recognition.interimResults = true; - textbox.css({backgroundColor: 'lightyellow', - color: 'gray', - backgroundImage: "url(" + microphoneSvg + ")", - backgroundRepeat: 'no-repeat', - backgroundPosition: 'center'}); - recognition.onspeechstart = function() { - textbox.css({background: 'lightgreen'}); - }; - recognition.onend = function() { - textbox.css({color: '', backgroundColor: '', backgroundImage: '', - backgroundRepeat: '', backgroundPosition: ''}); - textbox.val(lastseen); - newval(); - }; - recognition.onresult = function(event) { - var text = event.results[0][0].transcript; - var confidence = event.results[0][0].confidence; - var shade = 128 - 128 * confidence; - if (event.results[0].isFinal) { - shade = 0; - lastseen = text; - } - textbox.css({color: componentColor('rgb', shade, shade, shade)}); - textbox.val(text); - }; - recognition.start(); - } catch (e) { - console.log(e); + if (type == 'voice') { + var SR = global.SpeechRecognition || global.webkitSpeechRecognition; + if ('function' == typeof(SR)) { + try { + recognition = new SR(); + recognition.continuous = false; + recognition.interimResults = true; + textbox.css({backgroundColor: 'lightyellow', + color: 'gray', + backgroundImage: "url(" + microphoneSvg + ")", + backgroundRepeat: 'no-repeat', + backgroundPosition: 'center'}); + recognition.onspeechstart = function() { + textbox.css({background: 'lightgreen'}); + }; + recognition.onend = function() { + textbox.css({color: '', backgroundColor: '', backgroundImage: '', + backgroundRepeat: '', backgroundPosition: ''}); + textbox.val(lastseen); + newval(); + }; + recognition.onresult = function(event) { + var text = event.results[0][0].transcript; + var confidence = event.results[0][0].confidence; + var shade = 128 - 128 * confidence; + if (event.results[0].isFinal) { + shade = 0; + lastseen = text; + } + textbox.css({color: componentColor('rgb', shade, shade, shade)}); + textbox.val(text); + }; + recognition.start(); + } catch (e) { + console.log(e); + } } } textbox.on('keypress keydown', key); From 84edbca9e636cfbb825faa5c2ff763531ed343e8 Mon Sep 17 00:00:00 2001 From: Amit Deutsch Date: Mon, 26 Oct 2015 19:22:27 -0700 Subject: [PATCH 16/31] Fixed language of 'say' command to british-english, fixed bug in which 'readvoice' command was executing out of order. --- jquery-turtle.js | 77 ++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index 19ab9cb..9f4064d 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -6886,6 +6886,7 @@ var turtlefn = { var msg = new SpeechSynthesisUtterance(words); msg.addEventListener('end', complete); msg.addEventListener('error', complete); + msg.lang = 'en-GB'; speechSynthesis.speak(msg); pollTimer = setInterval(function() { // Chrome speech synthesis fails to deliver an 'end' event @@ -9702,44 +9703,6 @@ function prepareInput(name, callback, type) { return false; } } - if (type == 'voice') { - var SR = global.SpeechRecognition || global.webkitSpeechRecognition; - if ('function' == typeof(SR)) { - try { - recognition = new SR(); - recognition.continuous = false; - recognition.interimResults = true; - textbox.css({backgroundColor: 'lightyellow', - color: 'gray', - backgroundImage: "url(" + microphoneSvg + ")", - backgroundRepeat: 'no-repeat', - backgroundPosition: 'center'}); - recognition.onspeechstart = function() { - textbox.css({background: 'lightgreen'}); - }; - recognition.onend = function() { - textbox.css({color: '', backgroundColor: '', backgroundImage: '', - backgroundRepeat: '', backgroundPosition: ''}); - textbox.val(lastseen); - newval(); - }; - recognition.onresult = function(event) { - var text = event.results[0][0].transcript; - var confidence = event.results[0][0].confidence; - var shade = 128 - 128 * confidence; - if (event.results[0].isFinal) { - shade = 0; - lastseen = text; - } - textbox.css({color: componentColor('rgb', shade, shade, shade)}); - textbox.val(text); - }; - recognition.start(); - } catch (e) { - console.log(e); - } - } - } textbox.on('keypress keydown', key); textbox.on('change', newval); return { @@ -9755,6 +9718,44 @@ function prepareInput(name, callback, type) { marginwidth = textbox.outerWidth(true) - textbox.width(); textbox.width(desiredwidth - marginwidth); } + if (type == 'voice') { + var SR = global.SpeechRecognition || global.webkitSpeechRecognition; + if ('function' == typeof(SR)) { + try { + recognition = new SR(); + recognition.continuous = false; + recognition.interimResults = true; + textbox.css({backgroundColor: 'lightyellow', + color: 'gray', + backgroundImage: "url(" + microphoneSvg + ")", + backgroundRepeat: 'no-repeat', + backgroundPosition: 'center'}); + recognition.onspeechstart = function() { + textbox.css({background: 'lightgreen'}); + }; + recognition.onend = function() { + textbox.css({color: '', backgroundColor: '', backgroundImage: '', + backgroundRepeat: '', backgroundPosition: ''}); + textbox.val(lastseen); + newval(); + }; + recognition.onresult = function(event) { + var text = event.results[0][0].transcript; + var confidence = event.results[0][0].confidence; + var shade = 128 - 128 * confidence; + if (event.results[0].isFinal) { + shade = 0; + lastseen = text; + } + textbox.css({color: componentColor('rgb', shade, shade, shade)}); + textbox.val(text); + }; + recognition.start(); + } catch (e) { + console.log(e); + } + } + } // Focus, but don't cause autoscroll to occur due to focus. undoScrollAfter(function() { textbox.focus(); }); } From fd5689961c87e6d68f57db7e257b6f29ad01c1af Mon Sep 17 00:00:00 2001 From: Amit Deutsch Date: Tue, 27 Oct 2015 08:29:41 -0700 Subject: [PATCH 17/31] Added submit button to read and readnum, added type=number to readnum input box. --- jquery-turtle.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index 9f4064d..cc262a1 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -9653,8 +9653,9 @@ function prepareInput(name, callback, type) { if (!type) { type = 'auto'; } name = $.isNumeric(name) || name ? name : '⇒'; var textbox = $('').css({margin:0, padding:0}), + button = $('').css({marginLeft:4}), label = $('').append(textbox), + '').append(textbox).append(button), debounce = null, lastseen = textbox.val(), recognition = null; @@ -9670,6 +9671,7 @@ function prepareInput(name, callback, type) { dodebounce(); lastseen = val; textbox.remove(); + button.remove(); label.append(val).css({display: 'table'}); if (type == 'number' || (type == 'auto' && $.isNumeric(val) && ('' + parseFloat(val) == val))) { @@ -9718,7 +9720,11 @@ function prepareInput(name, callback, type) { marginwidth = textbox.outerWidth(true) - textbox.width(); textbox.width(desiredwidth - marginwidth); } + if (type == 'number') { + textbox.attr('type', 'number'); + } if (type == 'voice') { + button.css({display:none}); var SR = global.SpeechRecognition || global.webkitSpeechRecognition; if ('function' == typeof(SR)) { try { From cf4d9317f89b805dfa8d6a40e843330e4367b828 Mon Sep 17 00:00:00 2001 From: Amit Deutsch Date: Wed, 28 Oct 2015 11:12:01 -0700 Subject: [PATCH 18/31] Added newval handler to button instead of text box blur. --- jquery-turtle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index cc262a1..ac528b6 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -9706,7 +9706,7 @@ function prepareInput(name, callback, type) { } } textbox.on('keypress keydown', key); - textbox.on('change', newval); + button.on('click', newval); return { result: label, setup: function() { From cf03900eb29f746ee61f4d5a232f5eff9f30b2de Mon Sep 17 00:00:00 2001 From: Amit Deutsch Date: Wed, 28 Oct 2015 21:34:18 -0700 Subject: [PATCH 19/31] Replaced the readvoice command with the listen command. --- jquery-turtle.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index 9f4064d..c44f712 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -8046,9 +8046,9 @@ var dollar_turtle_methods = { "converts input to a number: " + "readstr 'Enter code', (v) -> write v.length + ' long'"], doOutput, function readstr(a, b) { return prepareInput(a, b, 'text'); }), - readvoice: wrapglobalcommand('readvoice', - ["readvoice(html, fn) Reads voice input, if the browser supports it:" + - "readvoice 'Say something', (v) -> write v"], + listen: wrapglobalcommand('listen', + ["listen(html, fn) Reads voice input, if the browser supports it:" + + "listen 'Say something', (v) -> write v"], doOutput, function readstr(a, b) { return prepareInput(a, b, 'voice'); }), menu: wrapglobalcommand('menu', ["menu(map) shows a menu of choices and calls a function " + From 3a71978450e101f033b7c74e21e3ae2164583461 Mon Sep 17 00:00:00 2001 From: Amit Deutsch Date: Wed, 28 Oct 2015 22:40:46 -0700 Subject: [PATCH 20/31] Fixed broken test. --- test/globals.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/globals.html b/test/globals.html index f208663..a19cb14 100644 --- a/test/globals.html +++ b/test/globals.html @@ -60,7 +60,7 @@ "typeline", "read", "readnum", - "readvoice", + "listen", "readstr", "menu", "random", From de2c752ebc0908693e84a4fa6d83ca039bdd233f Mon Sep 17 00:00:00 2001 From: David Bau Date: Thu, 29 Oct 2015 02:47:21 -0400 Subject: [PATCH 21/31] Fix test. --- test/inputoutput.html | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/inputoutput.html b/test/inputoutput.html index a29c622..b3b33b4 100644 --- a/test/inputoutput.html +++ b/test/inputoutput.html @@ -20,14 +20,22 @@ equal(td.eq(2).text(), "3"); var clicked = 0; setTimeout(function() { - $('input').val('Amy').change(); + $('input').val('Amy'); + $('button').click(); }, 1); - var b; + var b, r2; var r = read('name?', function(t) { equal(t, 'Amy'); setTimeout(function() { + $('input').val('34'); + var e = jQuery.Event("keydown"); + e.which = 13; // Enter. + $('input').trigger(e); $('button').click(); }, 1); + r2 = readnum('count?', function(c) { + equal(c, 34); + }); b = button('click me!', function() { equal(equal($('button').last().text(), 'click me!')); equal(clicked++, 0); From 06dad3b5ea0a13b87768711dc32e36da44bdbc6b Mon Sep 17 00:00:00 2001 From: David Bau Date: Thu, 19 Nov 2015 06:50:19 -0500 Subject: [PATCH 22/31] Do not require /img/ for wear, and also add sync for newly written objects. --- jquery-turtle.js | 11 +++++++++-- test/wear.html | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index de99da4..506354e 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -2689,7 +2689,7 @@ function imgUrl(url) { if (/\//.test(url)) { return url; } url = '/img/' + url; if (isPencilHost(global.location.hostname)) { return url; } - return '//pencil.io' + url; + return '//pencilcode.net' + url; } // Retrieves the pencil code login cookie, if there is one. function loginCookie() { @@ -5944,6 +5944,9 @@ function wrapglobalcommand(name, helptext, fn, fnfilter) { this.plan(cc.resolver(j)); }); cc.exit(); + if (early && early.result && early.result.constructor === jQuery) { + sync(animate, early.result); + } } else { cc = setupContinuation(null, name, arguments, argcount); fn.apply(early, arguments); @@ -9026,7 +9029,7 @@ function nameToImg(name, defaultshape) { // Deal with unquoted "tan" and "dot". name = name.helpname || name.name; } - if (name.constructor === $) { + if (name.constructor === jQuery) { // Unwrap jquery objects. if (!name.length) { return null; } name = name.get(0); @@ -9057,6 +9060,10 @@ function nameToImg(name, defaultshape) { if (shape) { return shape(color); } + // Default to '/img/' URLs if it doesn't match a well-known name. + if (!/\//.test(name)) { + name = imgUrl(name); + } // Parse URLs. if (/\//.test(name)) { var hostname = absoluteUrlObject(name).hostname; diff --git a/test/wear.html b/test/wear.html index eed8ddc..12a9d3f 100644 --- a/test/wear.html +++ b/test/wear.html @@ -24,6 +24,20 @@ }); }); +asyncTest("Wears an creative commons image.", function() { + var r = new Turtle(red); + r.speed(100); + tick(60, function() { + ok(r.width() != 20 || r.getxy()[1] == 0); + }); + r.wear('t-watermelon'); // no /img/ needed. + r.done(function() { + ok(r.width() != 20); + tick(null); + setTimeout(start, 0); + }); +}); + asyncTest("Wears and hittests different shapes.", function() { speed(Infinity); dot(red, 30); From f4ba15971301c6b11cbb0c71e61be99c14436912 Mon Sep 17 00:00:00 2001 From: David Bau Date: Thu, 19 Nov 2015 07:36:23 -0500 Subject: [PATCH 23/31] Allow 'say' when there is no global turtle. --- jquery-turtle.js | 73 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index 506354e..bcf03f1 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -6427,6 +6427,39 @@ function drawArrowLine(c, w, x0, y0, x1, y1) { drawArrowHead(c, m); } +////////////////////////////////////////////////////////////////////////// +// VOICE SYNTHESIS +// Method for uttering words. +////////////////////////////////////////////////////////////////////////// +function utterSpeech(words, cb) { + var pollTimer = null; + function complete() { + if (pollTimer) { clearInterval(pollTimer); } + if (cb) { cb(); } + } + if (!global.speechSynthesis) { + console.log('No speech synthesis: ' + words); + complete(); + return; + } + try { + var msg = new global.SpeechSynthesisUtterance(words); + msg.addEventListener('end', complete); + msg.addEventListener('error', complete); + msg.lang = navigator.language || 'en-GB'; + global.speechSynthesis.speak(msg); + pollTimer = setInterval(function() { + // Chrome speech synthesis fails to deliver an 'end' event + // sometimes, so we also poll every 250ms. + if (global.speechSynthesis.pending || global.speechSynthesis.speaking) return; + complete(); + }, 250); + } catch (e) { + if (global.console) { global.console.log(e); } + complete(); + } +} + ////////////////////////////////////////////////////////////////////////// // TURTLE FUNCTIONS // Turtle methods to be registered as jquery instance methods. @@ -6876,35 +6909,13 @@ var turtlefn = { this.plan(function(j, elem) { cc.appear(j); this.queue(function(next) { - var finished = false, - pollTimer = null, - complete = function() { - if (finished) return; - clearInterval(pollTimer); - finished = true; + utterSpeech(words, function() { cc.resolve(j); next(); - }; - try { - var msg = new SpeechSynthesisUtterance(words); - msg.addEventListener('end', complete); - msg.addEventListener('error', complete); - msg.lang = 'en-GB'; - speechSynthesis.speak(msg); - pollTimer = setInterval(function() { - // Chrome speech synthesis fails to deliver an 'end' event - // sometimes, so we also poll every 250ms. - if (speechSynthesis.pending || speechSynthesis.speaking) return; - complete(); - }, 250); - } catch (e) { - if (global.console) { global.console.log(e); } - complete(); - } + }); }); }); return this; - }), play: wrapcommand('play', 1, ["play(notes) Play notes. Notes are specified in " + @@ -7863,6 +7874,20 @@ var dollar_turtle_methods = { function globalspeed(mps) { globaldefaultspeed(mps); }), + say: wrapraw('say', + ["say(words) Say something. Use English words." + + "say \"Let's go!\""], + function say(words) { + if (global_turtle) { + var sel = $(global_turtle); + sel.say.call(sel, words); + } else { + var cc = setupContinuation(null, 'say', arguments, 0); + cc.appear(null); + utterSpeech(words, function() { cc.resolve(null); }); + cc.exit(); + } + }), play: wrapraw('play', ["play(notes) Play notes. Notes are specified in " + "" + From 2a0dcce08464b3b6e729411b1c11d696e1cbb91c Mon Sep 17 00:00:00 2001 From: David Bau Date: Thu, 19 Nov 2015 09:01:52 -0500 Subject: [PATCH 24/31] Add test for speech synthesis. --- test/say.html | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 test/say.html diff --git a/test/say.html b/test/say.html new file mode 100644 index 0000000..a8aed1c --- /dev/null +++ b/test/say.html @@ -0,0 +1,25 @@ + + + + + +
+ + + + From 5565321dc105e6949e7483b46f3134d188fd7ca8 Mon Sep 17 00:00:00 2001 From: David Bau Date: Thu, 19 Nov 2015 09:07:55 -0500 Subject: [PATCH 25/31] Fix global_turtle sync when writing new objects. --- jquery-turtle.js | 6 +++--- test/sync.html | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index bcf03f1..8465c7e 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -5944,15 +5944,15 @@ function wrapglobalcommand(name, helptext, fn, fnfilter) { this.plan(cc.resolver(j)); }); cc.exit(); - if (early && early.result && early.result.constructor === jQuery) { - sync(animate, early.result); - } } else { cc = setupContinuation(null, name, arguments, argcount); fn.apply(early, arguments); cc.exit(); } if (early) { + if (early.result && early.result.constructor === jQuery && global_turtle) { + sync(global_turtle, early.result); + } return early.result; } }; diff --git a/test/sync.html b/test/sync.html index 87e4d1a..4808c51 100644 --- a/test/sync.html +++ b/test/sync.html @@ -46,4 +46,22 @@ start(); }); }); + +asyncTest("Moves a written object and verifies that sync works.", function() { + speed(10); + var w = write('hello'); + w.bk(100); + sync(w, turtle); + w.plan(function() { + // When w is done moving, w2 should not have moved yet. + var xy2 = w2.getxy(); + var xy = w.getxy(); + ok(xy2[1] > xy[1]); + }); + var w2 = write('hello2'); + w2.bk(100); + done(function() { + start(); + }); +}); From 89e724b6054d3aac6eb2b142144a3b54f133f23a Mon Sep 17 00:00:00 2001 From: David Bau Date: Mon, 30 Nov 2015 07:39:54 -0500 Subject: [PATCH 26/31] Add $.turtle.colors. --- jquery-turtle.js | 1 + test/random.html | 1 + 2 files changed, 2 insertions(+) diff --git a/jquery-turtle.js b/jquery-turtle.js index 8465c7e..da2d879 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -8626,6 +8626,7 @@ $.turtle = function turtle(id, options) { }; $.extend($.turtle, dollar_turtle_methods); +$.turtle.colors = colors; function seehelphook(text, result) { // Also, check the command to look for (non-CoffeeScript) help requests. diff --git a/test/random.html b/test/random.html index 0d03405..4e6e289 100644 --- a/test/random.html +++ b/test/random.html @@ -20,6 +20,7 @@ equal(random([1,2,3]), 3); equal(random(), 0.9520654011140274); equal(random(null), 0.006122341186296597); + equal($.turtle.colors.indexOf('red'), 120); start(); }); From 157acf35a1166b9fc2df8adf840a62175c2230a3 Mon Sep 17 00:00:00 2001 From: Markus Bordihn Date: Sat, 9 Jan 2016 16:12:56 +0100 Subject: [PATCH 27/31] Fix and clean up the code to avoid compiler errors and warnings. --- jquery-turtle.js | 75 +++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/jquery-turtle.js b/jquery-turtle.js index da2d879..033294b 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -772,7 +772,7 @@ function readTransformMatrix(elem) { // Reads out the css transformOrigin property, if present. function readTransformOrigin(elem, wh) { var hidden = ($.css(elem, 'display') === 'none'), - swapout, old, name, gcs, origin; + swapout, old, name; if (hidden) { // IE GetComputedStyle doesn't give pixel values for transformOrigin // unless the element is unhidden. @@ -783,13 +783,13 @@ function readTransformOrigin(elem, wh) { elem.style[name] = swapout[name]; } } - var gcs = (global.getComputedStyle ? global.getComputedStyle(elem) : null), - origin = (gcs && gcs[transformOrigin] || $.css(elem, 'transformOrigin')); + var gcs = (global.getComputedStyle ? global.getComputedStyle(elem) : null); if (hidden) { for (name in swapout) { elem.style[name] = old[name]; } } + var origin = (gcs && gcs[transformOrigin] || $.css(elem, 'transformOrigin')); if (origin && origin.indexOf('%') < 0) { return $.map(origin.split(' '), parseFloat); } @@ -960,7 +960,7 @@ function getTurtleOrigin(elem, inverseParent, extra) { { position: "absolute", visibility: "hidden", display: "block" } : {}, substTransform = swapout[transform] = (inverseParent ? 'matrix(' + $.map(inverseParent, cssNum).join(', ') + ', 0, 0)' : 'none'), - old = {}, name, gbcr, transformOrigin, result; + old = {}, name, gbcr, transformOrigin; for (name in swapout) { old[name] = elem.style[name]; elem.style[name] = swapout[name]; @@ -1250,7 +1250,7 @@ function scrollWindowToDocumentPosition(pos, limit) { if (tx < ww2) { tx = ww2; } if (ty > dh - wh2) { ty = dh - wh2; } if (ty < wh2) { ty = wh2; } - targ = { pageX: tx, pageY: ty }; + var targ = { pageX: tx, pageY: ty }; if ($.isNumeric(limit)) { targ = limitMovement(w.origin(), targ, limit); } @@ -2178,8 +2178,7 @@ function touchesPixel(elem, color) { h = (bb.bottom - bb.top), osc = getOffscreenCanvas(w, h), octx = osc.getContext('2d'), - rgba = rgbaForColor(color), - j = 1, k, data; + j = 1, k; if (!c || c.length < 3 || !w || !h) { return false; } octx.drawImage(canvas, bb.left, bb.top, w, h, 0, 0, w, h); @@ -2726,7 +2725,8 @@ var stablyLoadedImages = {}; // @param css is a dictionary of css props to set when the image is loaded. // @param cb is an optional callback, called after the loading is done. function setImageWithStableOrigin(elem, url, css, cb) { - var record, urlobj = absoluteUrlObject(url), url = urlobj.href; + var record, urlobj = absoluteUrlObject(url); + url = urlobj.href; // The data-loading attr will always reflect the last URL requested. elem.setAttribute('data-loading', url); if (url in stablyLoadedImages) { @@ -3032,7 +3032,7 @@ var Pencil = (function(_super) { } // The pencil is a sprite that just defaults to zero size. var context = canvas ? canvas.parentElement : null; - var settings = { width: 0, height: 0, color: transparent }; + var settings = { width: 0, height: 0, color: 'transparent' }; Pencil.__super__.constructor.call(this, settings, context); // Set the pencil to hidden, infinite speed, // and drawing on the specifed canvas. @@ -3072,7 +3072,7 @@ var Webcam = (function(_super) { function Webcam(opts, context) { var attrs = "", hassrc = false, hasautoplay = false, hasdims = false; if ($.isPlainObject(opts)) { - for (key in opts) { + for (var key in opts) { attrs += ' ' + key + '="' + escapeHtml(opts[key]) + '"'; } hassrc = ('src' in opts); @@ -3317,12 +3317,12 @@ var Piano = (function(_super) { // Converts a midi number to a white key position (black keys round left). function wcp(n) { - return floor((n + 7) / 12 * 7); + return Math.floor((n + 7) / 12 * 7); }; // Converts from a white key position to a midi number. function mcp(n) { - return ceil(n / 7 * 12) - 7; + return Math.ceil(n / 7 * 12) - 7; }; // True if midi #n is a black key. @@ -4517,7 +4517,7 @@ var Instrument = (function() { if (key in given) { timbre[key] = given[key]; } else { - timbre[key] = defaulTimbre[key]; + timbre[key] = defaultTimbre[key]; } } } @@ -5206,7 +5206,6 @@ function parseABCFile(str) { function syncopateStem(stem, t) { var j, note, stemtime = stem.time, newtime = stemtime + t; stem.time = newtime; - syncopateStem for (j = 0; j < stem.notes.length; ++j) { note = stem.notes[j]; // Only adjust a note's duration if it matched the stem's duration. @@ -7116,8 +7115,8 @@ var turtlefn = { // For defaults, copy inline styles of the turtle itself except for // properties in the following list (these are the properties used to // make the turtle look like a turtle). - for (var j = 0; j < currentStyles.length; ++j) { - var styleProperty = currentStyles[j]; + for (var j2 = 0; j2 < currentStyles.length; ++j2) { + var styleProperty = currentStyles[j2]; if (/^(?:width|height|opacity|background-image|background-size)$/.test( styleProperty) || /transform/.test(styleProperty)) { continue; @@ -7535,7 +7534,6 @@ var turtlefn = { callback.apply(this, arguments); } }); - sync = null; }), plan: wrapraw('plan', ["plan(fn) Runs fn in the animation queue. For planning logic: " + @@ -7958,7 +7956,6 @@ var dollar_turtle_methods = { callback.apply(this, arguments); } }); - sync = null; }), load: wrapraw('load', ["load(url, cb) Loads data from the url and passes it to cb. " + @@ -7994,7 +7991,8 @@ var dollar_turtle_methods = { "save 'intro', 'pen gold, 20\\nfd 100\\n'"], function(url, data, cb) { if (!url) throw new Error('Missing url for save'); - var payload = { }, url = apiUrl(url, 'save'), key; + var payload = { }, key; + url = apiUrl(url, 'save'); if (/\.json(?:$|\?|\#)/.test(url)) { data = JSON.stringify(data, null, 2); } @@ -8254,7 +8252,7 @@ var dollar_turtle_methods = { return (x == 0) ? NaN : ((x > 0) ? 0 : 180); } else if (x == 0) { return (y > 0) ? Infinity : -Infinity; - } else if (abs(y) == abs(x)) { + } else if (Math.abs(y) == Math.abs(x)) { return (y > 0) ? ((x > 0) ? 45 : 135) : ((x > 0) ? -45 : -135); } @@ -8608,12 +8606,6 @@ $.turtle = function turtle(id, options) { seeopt.height = options.panelheight; } see.init(seeopt); - if (wrotebody) { - /* - see.html('Turtle script should be inside body ' + - '- wrote a <body>'); - */ - } // Return an eval loop hook string if 'see' is exported. if (exportedsee) { if (global.CoffeeScript) { @@ -9355,13 +9347,12 @@ function turtleevents(prefix) { if (prefix || prefix === '') { eventsaver = (function(e) { // Keep the old instance if possible. - var names = [prefix + e.type], j, old, name, prop; + var names = [prefix + e.type], j; if ((e.originalEvent || e) instanceof MouseEvent) { names.push(prefix + 'mouse'); } for (j = 0; j < names.length; ++j) { - var name = names[j]; - old = global[name], prop; + var name = names[j], old = global[name], prop; if (old && old.__proto__ === e.__proto__) { for (prop in old) { if (old.hasOwnProperty(prop)) delete old[prop]; } for (prop in e) { if (e.hasOwnProperty(prop)) old[prop] = e[prop]; } @@ -9757,7 +9748,7 @@ function prepareInput(name, callback, type) { textbox.attr('type', 'number'); } if (type == 'voice') { - button.css({display:none}); + button.css({display: 'none'}); var SR = global.SpeechRecognition || global.webkitSpeechRecognition; if ('function' == typeof(SR)) { try { @@ -9892,40 +9883,41 @@ function componentColor(t, args) { return t + '(' + Array.prototype.join.call(args, ',') + ')'; } -function autoArgs(arguments, start, map) { +function autoArgs(args, start, map) { var j = 0; var taken = []; var result = {}; for (var key in map) { var pattern = map[key]; - for (j = start; j < arguments.length; ++j) { + for (j = start; j < args.length; ++j) { if (~taken.indexOf(j)) continue; if (pattern == '*') { break; - } else if (pattern instanceof RegExp && pattern.test(arguments[j])) { + } else if (pattern instanceof RegExp && pattern.test(args[j])) { break; - } else if (pattern instanceof Function && pattern(arguments[j])) { + } else if (pattern instanceof Function && pattern(args[j])) { break; - } else if (pattern == typeof arguments[j]) { + } else if (pattern == typeof args[j]) { break; } } - if (j < arguments.length) { + if (j < args.length) { taken.push(j); - result[key] = arguments[j]; + result[key] = args[j]; } } - if (taken.length + start < arguments.length) { + if (taken.length + start < args.length) { var extra = []; - for (j = start; j < arguments.length; ++j) { + for (j = start; j < args.length; ++j) { if (~taken.indexOf(j)) continue; - extra.push(arguments[j]); + extra.push(args[j]); } result.extra = extra; } return result; } + ////////////////////////////////////////////////////////////////////////// // DEBUGGING SUPPORT ////////////////////////////////////////////////////////////////////////// @@ -10036,7 +10028,7 @@ debug.init(); c = cnv.getContext('2d'), relative = false, p = lineend || e, - s, html, dx, dy, dd, dir, ang; + html, dx, dy, dd, dir, ang; if (linestart && 'function' == typeof(linestart.pagexy)) { var xy = linestart.getxy(), s = linestart.pagexy(); s.x = xy[0]; @@ -10763,7 +10755,6 @@ function aselement(s, def) { default: return s; } - return null; } function stickscroll() { var stick = false, a = aselement(autoscroll, null); From 04503f35404c3a709d13b3e8b3e2bb7a5f4a4c4c Mon Sep 17 00:00:00 2001 From: Markus Bordihn Date: Wed, 13 Jan 2016 21:11:19 +0100 Subject: [PATCH 28/31] Fixed smaller issues and removed jquery-turtle.min.js from .gitignore. --- .gitignore | 1 - LICENSE.txt | 2 +- README.md | 2 +- jquery-turtle.js | 24 ++++++++++-------------- jquery-turtle.min.js | 5 +++++ 5 files changed, 17 insertions(+), 17 deletions(-) create mode 100644 jquery-turtle.min.js diff --git a/.gitignore b/.gitignore index c40cd56..a349cbb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ .svn node_modules -jquery-turtle.min.js diff --git a/LICENSE.txt b/LICENSE.txt index fca7187..f997494 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -2,7 +2,7 @@ jQuery-turtle version 2.0 LICENSE (MIT): -Copyright (c) 2013 Pencil Code Foundation, Google, and other contributors. +Copyright (c) 2013 Pencil Code Foundation, Google Inc., and other contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 91bace6..8af96ab 100644 --- a/README.md +++ b/README.md @@ -331,7 +331,7 @@ element. License (MIT) ------------- -Copyright (c) 2014 Pencil Code, Google, and other contributors +Copyright (c) 2014 Pencil Code, Google Inc., and other contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/jquery-turtle.js b/jquery-turtle.js index 033294b..b09f1ad 100644 --- a/jquery-turtle.js +++ b/jquery-turtle.js @@ -4709,16 +4709,13 @@ var Instrument = (function() { return result; } - var whiteNoiseBuf = null; function getWhiteNoiseBuf() { - if (whiteNoiseBuf == null) { - var ac = getAudioTop().ac, - bufferSize = 2 * ac.sampleRate, - whiteNoiseBuf = ac.createBuffer(1, bufferSize, ac.sampleRate), - output = whiteNoiseBuf.getChannelData(0); - for (var i = 0; i < bufferSize; i++) { - output[i] = Math.random() * 2 - 1; - } + var ac = getAudioTop().ac, + bufferSize = 2 * ac.sampleRate, + whiteNoiseBuf = ac.createBuffer(1, bufferSize, ac.sampleRate), + output = whiteNoiseBuf.getChannelData(0); + for (var i = 0; i < bufferSize; i++) { + output[i] = Math.random() * 2 - 1; } return whiteNoiseBuf; } @@ -7323,7 +7320,7 @@ var turtlefn = { if (typeof val != 'object' || !$.isNumeric(val.width) || !$.isNumeric(val.height) || !($.isArray(val.data) || val.data instanceof Uint8ClampedArray || - val.data instanceof Unit8Array)) { + val.data instanceof Uint8Array)) { return; } var imdat = ctx.createImageData( @@ -7917,7 +7914,7 @@ var dollar_turtle_methods = { sel.tone.apply(sel, arguments); } else { var instrument = getGlobalInstrument(); - instrument.play.apply(instrument, args); + instrument.play.apply(instrument); } }), silence: wrapraw('silence', @@ -8489,14 +8486,12 @@ var colors = [ $.turtle = function turtle(id, options) { var exportedsee = false; - if (!arguments.length) { - id = 'turtle'; - } if (arguments.length == 1 && typeof(id) == 'object' && id && !id.hasOwnProperty('length')) { options = id; id = 'turtle'; } + id = id || 'turtle'; options = options || {}; if ('turtle' in options) { id = options.turtle; @@ -8615,6 +8610,7 @@ $.turtle = function turtle(id, options) { } } } + return $('#' + id); }; $.extend($.turtle, dollar_turtle_methods); diff --git a/jquery-turtle.min.js b/jquery-turtle.min.js new file mode 100644 index 0000000..2718667 --- /dev/null +++ b/jquery-turtle.min.js @@ -0,0 +1,5 @@ +(function(a){function b(b,c){if(Ne>5)Oe.push({elem:b,qname:c});else{for(Ne+=1,a.dequeue(b,c);Oe.length>0;){var d=Oe.shift();a.dequeue(d.elem,d.qname),Vc()}Ne-=1}}function c(a,b){function c(){this.constructor=a}for(var d in b)Je.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a}function d(b){var c,d,e=b.charAt(0).toUpperCase()+b.slice(1),f=["Moz","Webkit","O","ms"],g=document.createElement("div");if(b in g.style)d=b;else for(var h=0;h<0?'"'+a+'"':"'"+a+"'":a}var c=[];for(var d in a)a.hasOwnProperty(d)&&c.push(d+":"+b(a[d])+";");return c.join(" ")}function h(a){return a}function i(a,b){var c=[a[0]*b[0]+a[2]*b[1],a[1]*b[0]+a[3]*b[1]];return 6==a.length&&(c[0]+=a[4],c[1]+=a[5]),c}function j(a,b){var c=[a[0]*b[0]+a[2]*b[1],a[1]*b[0]+a[3]*b[1],a[0]*b[2]+a[2]*b[3],a[1]*b[2]+a[3]*b[3]],d=6==a.length;return 6==b.length?(c.push(a[0]*b[4]+a[2]*b[5]+(d?a[4]:0)),c.push(a[1]*b[4]+a[3]*b[5]+(d?a[5]:0))):d&&(c.push(a[4]),c.push(a[5])),c}function k(a){return Math.abs(a)>1e-12}function l(a){return!(k(a[1])||k(a[2])||k(1-a[0])||k(1-a[3]))}function m(a){if(l(a))return[1,0,0,1];var b=u(a);return k(b[2])?j(o(-b[3]),j(p(1/b[1],1/b[2]),o(-b[0]))):null}function n(a){var b=m(a);if(4==a.length)return b;var c=i(b,[-a[4],-a[5]]);return b.push(c[0]),b.push(c[1]),b}function o(a){var b=Math.cos(a),c=Math.sin(a);return[b,c,-c,b]}function p(a,b){return 1==arguments.length&&(a=b),[a,0,0,b]}function q(a,b){return[a[0]+b[0],a[1]+b[1]]}function r(a,b){return[a[0]-b[0],a[1]-b[1]]}function s(a,b){return[a[0]*b,a[1]*b]}function t(a,b,c){return q(i(a,r(b,c)),c)}function u(a){var b,c,d=a[0]*a[0]+a[1]*a[1],e=a[0]*a[2]+a[1]*a[3],f=a[2]*a[2]+a[3]*a[3],g=-.5*Math.atan2(2*e,d-f),h=Math.cos(g),i=Math.sin(g),j=a[0]*h-a[2]*i,k=a[1]*h-a[3]*i,l=Math.atan2(k,j),m=Math.cos(l),n=Math.sin(l),o=(a[1]*i+a[3]*h)*m-(a[0]*i+a[2]*h)*n,p=(a[0]*h-a[2]*i)*m+(a[1]*h-a[3]*i)*n;return g<-Math.PI/4?(g+=Math.PI/2,c=p,b=o,l-=Math.PI/2):(b=p,c=o),l>Math.PI&&(l-=2*Math.PI),[l,b,c,g]}function v(a,b){var c=(b-a)/2,d=Math.cos(c),e=Math.sin(c),f=d,g=-e,h=1+f*d+g*e,i=f*e-g*d,j=i&&4/3*(Math.sqrt(2*h)-h)/i,k=f-j*g,l=g+j*f,m=k,n=-l,o=c+a,p=Math.cos(o),q=Math.sin(o);return[[k*p-l*q,k*q+l*p],[m*p-n*q,m*q+n*p],[Math.cos(b),Math.sin(b)]]}function w(a){var b=ra(a,!1);if(b)return[b.tx,b.ty];var c=x(a);return c?[c[4],c[5]]:[0,0]}function x(b){var c=Ie.getComputedStyle?Ie.getComputedStyle(b)[Pe]:a.css(b,"transform");if(!c||"none"===c)return null;var d=/^matrix\(([\-+.\de]+),\s*([\-+.\de]+),\s*([\-+.\de]+),\s*([\-+.\de]+),\s*([\-+.\de]+)(?:px)?,\s*([\-+.\de]+)(?:px)?\)$/.exec(c);return d?[parseFloat(d[1]),parseFloat(d[2]),parseFloat(d[3]),parseFloat(d[4]),parseFloat(d[5]),parseFloat(d[6])]:A(c)}function y(b,c){var d,e,f,g="none"===a.css(b,"display");if(g){d={position:"absolute",visibility:"hidden",display:"block"},e={};for(f in d)e[f]=b.style[f],b.style[f]=d[f]}var h=Ie.getComputedStyle?Ie.getComputedStyle(b):null;if(g)for(f in d)b.style[f]=e[f];var i=h&&h[Qe]||a.css(b,"transformOrigin");if(i&&i.indexOf("%")<0)return a.map(i.split(" "),parseFloat);if(c)return[c[0]/2,c[1]/2];var j=a(b);return[j.width()/2,j.height()/2]}function z(a){for(var b,c=[1,0,0,1];null!==a;)b=x(a),b&&!l(b)&&(c=j(b,c)),a=a.parentElement;return c.slice(0,4)}function A(b){var c=[1,0,0,1],d=[],e=[],f=/(?:^\s*|)(\w*)\s*\(([^)]*)\)\s*/g,g=b.replace(f,function(b){return d.push(b[1].toLowerCase()),e.push(a.map(b[2].split(","),function(a){var b=a.trim().toLowerCase();return{num:parseFloat(b),unit:b.replace(/^[+-.\de]*/,"")}})),""});if(g)return null;for(var h=d.length-1;h>=0;--h){var i,k,l,m=null,n=d[h],o=e[h];if("matrix"==n)o.length>=6&&(m=[o[0].num,o[1].num,o[2].num,o[3].num,o[4].num,o[5].num]);else if("rotate"==n)1==o.length&&(i=wa(o[0]),k=Math.cos(i),l=Math.sin(i),m=[k,-l,k,l]);else if("translate"==n||"translatex"==n||"translatey"==n){var p=0,q=0;if(o.length>=1){if(o[0].unit&&"px"!=o[0].unit)return null;if("translate"==n||"translatex"==n?p=o[0].num:"translatey"==n&&(q=o[0].num),"translate"==n&&o.length>=2){if(o[1].unit&&"px"!=o[1].unit)return null;q=o[1].num}m=[0,0,0,0,p,q]}}else if("scale"==n||"scalex"==n||"scaley"==n){var r=1,s=1;o.length>=1&&("scale"==n||"scalex"==n?r=o[0].num:"scaley"==n&&(s=o[0].num),"scale"==n&&o.length>=2&&(s=o[1].num),m=[r,0,0,s,0,0])}else{if("skew"!=n&&"skewx"!=n&&"skewy"!=n)return null;var t=0,u=0;o.length>=1&&("skew"==n||"skewx"==n?t=Math.tan(wa(o[0])):"skewy"==n&&(u=Math.tan(wa(o[0]))),"skew"==n&&o.length>=2&&(u=Math.tan(wa(o[0]))),m=[1,u,t,1,0,0])}c=j(c,m)}return c}function B(a,b,c){if(0>=c)return a;var d=b.pageX-a.pageX,e=b.pageY-a.pageY,f=d*d+e*e;if(c*c>=f)return b;var g=c/Math.sqrt(f);return{pageX:a.pageX+g*d,pageY:a.pageY+g*e}}function C(a,b,c){if(0>=c)b=a;else if(180>c){var d=xa(b-a);d>c?b=a+c:-c>d&&(b=a-c)}return xa(b)}function D(a,b,c,d){return{pageX:Math.floor(a+c/2),pageY:Math.floor(b+d/2)}}function E(a,b,c,d){var e=a+c,f=b+d;return[{pageX:a,pageY:b},{pageX:a,pageY:f},{pageX:e,pageY:f},{pageX:e,pageY:b}]}function F(a){if(!/e[\-+]/.exec(a))return a;var b=a.replace(/(?:\d+(?:\.\d*)?|\.\d+)e[\-+]\d+/g,function(a){return sa(parseFloat(a))});return b}function G(b,c,d){var e=a.data(b,"turtleData");if(e&&e.quickhomeorigin&&e.down&&e.style&&!d&&b.classList&&b.classList.contains("turtle"))return e.quickhomeorigin;var f,g,h,i="none"===a.css(b,"display"),j=i?{position:"absolute",visibility:"hidden",display:"block"}:{},k=(j[Pe]=c?"matrix("+a.map(c,sa).join(", ")+", 0, 0)":"none",{});for(f in j)k[f]=b.style[f],b.style[f]=j[f];g=N(b),h=y(b,[g.width,g.height]);for(f in j)b.style[f]=F(k[f]);d&&(d.gbcr=g,d.localorigin=h);var l=q([g.left,g.top],h);return e&&e.down&&e.style&&(e.quickhomeorigin=l),l}function H(){return Ie.innerHeight||a(Ie).height()}function I(){return Ie.innerWidth||a(Ie).width()}function J(){return document.body?a(document).height():document.height}function K(){return document.body?a(document).width():document.width}function L(a){return a.offsetHeight<=0&&a.offsetWidth<=0}function M(a,b,c,d){return{left:a,top:b,right:a+c,bottom:b+d,width:c,height:d}}function N(b){return mb(b)?M(b.pageX,b.pageY,0,0):a.isWindow(b)?M(a(Ie).scrollLeft(),a(Ie).scrollTop(),I(),H()):9===b.nodeType?M(0,0,K(),J()):"getBoundingClientRect"in b?T.apply(b):M(0,0,0,0)}function O(a,b,c){var d=Math.max(0,Math.max(c.top-a.pageY,a.pageY-c.bottom)),e=Math.max(0,Math.max(c.left-a.pageX,a.pageX-c.right));return e*e+d*d>b}function P(a,b,c){var d=Math.max(c.bottom-a.pageY,a.pageY-c.top),e=Math.max(c.right-a.pageX,a.pageX-c.left);return b>e*e+d*d}function Q(a,b){return b.right=a.top&&b.bottom<=a.bottom&&b.left>=a.left&&b.right<=a.right}function S(a,b){return 4===a.length&&a[0].pageX===b.left&&a[0].pageY===b.top&&a[1].pageX===b.left&&a[1].pageY===b.bottom&&a[2].pageX===b.right&&a[2].pageY===b.bottom&&a[3].pageX===b.right&&a[3].pageY===b.top}function T(){var a=this.getBoundingClientRect();return{top:a.top+Ie.pageYOffset,bottom:a.bottom+Ie.pageYOffset,left:a.left+Ie.pageXOffset,right:a.right+Ie.pageXOffset,width:a.width,height:a.height}}function U(b,c,d,e,f){var g,h,j,k,l=z(b.parentElement),n=m(l),o=G(b,n);if(n){if(a.isNumeric(d)&&(j=w(b),g=q(i(l,j),o),h={pageX:g[0],pageY:g[1]},c=B(h,c,d)),k=i(n,r([c.pageX,c.pageY],o)),e||f){var p=Gc(b);k[0]+=e*p,k[1]-=f*p}return sa(k[0])+" "+sa(k[1])}}function V(a){var b=a.offsetParent;return b?b:document}function W(b,c){c||(c=a(V(b)).pagexy());var d=z(b.parentElement),e=m(d),f=G(b,e),g=ra(b,!0),h=e&&i(e,r([c.pageX,c.pageY],f)),j=1/Gc(b);if(e)return[(g.tx-h[0])*j,(h[1]-g.ty)*j]}function X(b,c){var d,e,f=z(b.parentElement),g=(ra(b,!0),a(V(b)).pagexy()),h=Gc(b),j=[];for(e=0;ei-f&&(d=i-f),f>d&&(d=f),e>j-g&&(e=j-g),g>e&&(e=g);var l={pageX:d,pageY:e};a.isNumeric(c)&&(l=B(k.origin(),l,c)),k.scrollLeft(l.pageX-f),k.scrollTop(l.pageY-g)}function ca(a,b,c){var d=b.pageX-a.pageX,e=b.pageY-a.pageY,f=c.pageX-a.pageX,g=c.pageY-a.pageY;return f*e-d*g}function da(a,b,c){var d=c.pageX-a.pageX,e=c.pageY-a.pageY;return d*b.pageY-b.pageX*e}function ea(a,b){if(b.length<=0)return!1;if(1==b.length)return b[0].pageX==a.pageX&&b[0].pageY==a.pageY;var c=ca(a,b[b.length-1],b[0]);if(0===c)return!0;var d=c>0;if(2==b.length)return!1;for(var e=1;e0!=d)return!1}return!0}function fa(a,b){return{pageX:a.pageX-b.pageX,pageY:a.pageY-b.pageY}}function ga(a,b,c,d){var e,f,g=fa(c,b);for(e=0;e0?1:0>a?-1:0}function ia(a){if(a.length<=2)return 0;var b=ca(a[a.length-1],a[0],a[1]);if(0!==b)return ha(b);for(var c=1;c1&&1!=ha(ca(a[a.length-2],a[a.length-1],b));)a.pop();return a.length&&d(a[a.length-1],b)||a.push(b),a}function c(a,b,c){for(var d=0;db.pageX?1:a.pageYb.pageY?1:0}a.sort(e);var f=c(a,[],b),g=c(a.reverse(),[],b);return f.concat(g.slice(1,-1))}function ma(b){if(!b)return null;if(a.isArray(b))return b;for(var c=a.map(b.trim().split(/\s+/),parseFloat),d=[],e=0;e+1180&&(b-=360),b}function wa(a){return a/180*Math.PI}function xa(a){return Math.abs(a)>180&&(a%=360,a>180?a-=360:-180>=a&&(a+=360)),a}function ya(a){return Math.abs(a)>=720&&(a=a%360+(a>0?360:-360)),a}function za(){return Re.field||Ba(),Re.field}function Aa(){return Re.surface||Ba(),Re.surface}function Ba(){var b=document.createElement("samp"),c=document.createElement("samp"),d=Math.floor(I()/2),e=Math.floor(H()/2);a(b).css({position:"absolute",display:"inline-block",top:0,left:0,width:"100%",height:"100%",font:"inherit",zIndex:-1,transformOrigin:d+"px "+e+"px",pointerEvents:"none",overflow:"hidden"}).addClass("turtlefield"),a(c).attr("id","origin").css({position:"absolute",display:"inline-block",top:e,left:d,width:"100%",height:"0",font:"inherit",transformOrigin:"0px 0px",pointerEvents:"all",turtleSpeed:1/0}).appendTo(b),Re.surface=b,Re.field=c,Ca(),Sb()}function Ca(){document.body?(null==a("html").attr("style")&&a("html").css("min-height","100%"),a(Re.surface).prependTo("body"),Rb()):a(document).ready(Ca)}function Da(a){return a.drawOnCanvas||(a.drawOnCanvas=Fa()),a.drawOnCanvas}function Ea(b){var c=a.data(b,"turtleData");return c?c.drawOnCanvas?c.drawOnCanvas:Re.canvas:null}function Fa(){if(Re.canvas)return Re.canvas;var b=Aa();return Re.canvas=document.createElement("canvas"),a(Re.canvas).css({"z-index":-1}),b.insertBefore(Re.canvas,b.firstChild),Ja(),Ha(Ja),a(Ie).resize(Ja),Re.canvas}function Ga(a,b){return Re.offscreen&&Re.offscreen.width===a&&Re.offscreen.height===b?(Re.offscreen.getContext("2d").clearRect(0,0,a,b),Re.offscreen):(Re.offscreen||(Re.offscreen=document.createElement("canvas")),Re.offscreen.width=a,Re.offscreen.height=b,Re.offscreen)}function Ha(b){var c=a("body"),d=c.width(),e=c.height(),f=function(){(c.width()!=d||c.height()!=e)&&(b(),d=c.width(),e=c.height())};Re.timer&&clearInterval(Re.timer),Re.timer=setInterval(f,250)}function Ia(){var b=a("body");return[Math.max(b.outerWidth(!0),Ie.innerWidth||a(Ie).width()),Math.max(b.outerHeight(!0),Ie.innerHeight||a(Ie).height())]}function Ja(){if(Re.canvas){var b,c=Ia(),d=c[0],e=c[1],f=Re.canvas.width,g=Re.canvas.height,h=Math.max(Math.min(2e3,Math.max(200,f)),100*Math.ceil(d/100))*Re.subpixel,i=Math.max(Math.min(2e3,Math.max(200,f)),100*Math.ceil(e/100))*Re.subpixel;a(Re.surface).css({width:d+"px",height:e+"px"}),(f!=h||g!=i)&&(b=document.createElement("canvas"),b.width=Math.min(f,h),b.height=Math.min(g,i),b.getContext("2d").drawImage(Re.canvas,0,0),Re.canvas.width=h,Re.canvas.height=i,Re.canvas.getContext("2d").drawImage(b,0,0),a(Re.canvas).css({width:h/Re.subpixel,height:i/Re.subpixel}))}}function Ka(a,b){if(!a)return null;if(a&&"function"==typeof a&&(a.helpname||a.name)&&(a=a.helpname||a.name),a=String(a),a.trim&&(a=a.trim()),!a||"none"===a)return null;if("path"===a||"fill"===a)return{savePath:!0};var c=!1;/^erase\b/.test(a)&&(a=a.replace(/^erase\b/,"white; globalCompositeOperation:destination-out"),c=!0);var d=f(a,b);return c&&(d.eraseMode=!0),d}function La(a){return a?g(a):"none"}function Ma(a){return"down"==a||a===!0?!0:"up"==a||a===!1?!1:He}function Na(a){return a?"down":"up"}function Oa(b){var c=a.data(b,"turtleData");return c||(c=a.data(b,"turtleData",{style:null,corners:[[]],path:[[]],down:!1,speed:"turtle",easing:"swing",turningRadius:0,drawOnCanvas:null,quickpagexy:null,quickhomeorigin:null,oldscale:1,instrument:null,stream:null})),c}function Pa(b){var c=a.data(b,"turtleData");return c?c.turningRadius:0}function Qa(){return{get:function(a,b,c){return sa(Pa(a))+"px"},set:function(a,b){var c=parseFloat(b);if(!isNaN(c)&&(Oa(a).turningRadius=c,a.style.turtleTurningRadius=""+sa(c)+"px",0===c)){var d=ra(a,!1);d&&(d.rot>180||d.rot<=-180)&&(d.rot=xa(d.rot),a.style[Pe]=ta(d))}}}}function Ra(){return{get:function(a,b,c){return La(Oa(a).style)},set:function(a,b){var c=Ka(b,"strokeStyle"),d=Oa(a);d.style&&(d.style=null,bb(a,d,!0)),d.style=c,a.style.turtlePenStyle=La(c),bb(a,d,!0)}}}function Sa(){return{get:function(a,b,c){return Na(Oa(a).down)},set:function(a,b){var c=Ma(b);if(c!==He){var d=Oa(a);c!=d.down&&(d.down=c,d.quickpagexy=null,d.quickhomeorigin=null,a.style.turtlePenDown=Na(c),bb(a,d,!0))}}}}function Ta(a,b){return 0===Math.round(a.pageX-b.pageX)&&0===Math.round(a.pageY-b.pageY)}function Ua(a,b){return 0===Math.round(1e3*(a.pageX-b.pageX))&&0===Math.round(1e3*(a.pageY-b.pageY))}function Va(a,b){return Ta(a,b)&&0===Math.round(a.pageX-b.pageX1)&&0===Math.round(a.pageY-b.pageY1)&&0===Math.round(b.pageX2-b.pageX)&&0===Math.round(b.pageY2-b.pageY)}function Wa(a){var b=1e3*a,c=Math.round(b);return Math.abs(c-b)1){h=b[j],f=h.length>2&&Ta(h[0],h[h.length-1])&&!Ta(h[0],h[Math.floor(h.length/2)]),g=f&&!("pageX2"in h[h.length-1]);var k=h[0].pageX,l=h[0].pageY;i.moveTo(k,l);for(var m=1;m1&&(d.length=1),d[0].length&&(d[0].length=0),void(c&&(e?f.length&&f[0].length&&(1==f[0].length?f[0].length=0:f.unshift([])):(f.length>1&&(f.length=1),f[0].length&&(f[0].length=0))));if(c||!e.savePath){var g=Y(a);if(c&&(g.corner=!0,ab(f[0],g)),!e.savePath){ab(d[0],g);var h=Kc(a);$a(Da(b),b.path,e,h,2)}}}}function cb(b,c){var d=Oa(b);d.style&&(c=a.extend({},d.style,c));var e=Kc(b);$a(Da(d),d.corners,c,e,1)}function db(b){if((!b||/\bcanvas\b/.test(b))&&Re.canvas){var c=Re.canvas.getContext("2d");c.save(),c.setTransform(1,0,0,1,0,0),c.clearRect(0,0,Re.canvas.width,Re.canvas.height),c.restore()}if((!b||/\bturtles\b/.test(b))&&Re.surface){var d=a(Re.surface).find(".turtle").not(".turtlefield");pf&&(d=d.not(pf)),d.remove()}if((!b||/\blabels\b/.test(b))&&Re.surface){var d=a(Re.surface).find(".turtlelabel").not(".turtlefield");d.remove()}(!b||/\btext\b/.test(b))&&a("body").contents().not(".turtlefield").remove()}function eb(a,b){if(!a||a.length<1)return null;for(var c=1,d={left:Math.floor(a[0].pageX),top:Math.floor(a[0].pageY),right:Math.ceil(a[0].pageX),bottom:Math.ceil(a[0].pageY)};c=c[3]/2)return!0}else{var o=!c;for(m=0;m0==o)return!0}return!1}function hb(a,b,c){if(b.img)("CANVAS"==a[0].tagName||a[0].tagName==b.img.tagName)&&Kb(b.img,a[0],b.css);else if("IMG"==a[0].tagName||"CANVAS"==a[0].tagName)Hb(a[0],b.url,b.css,c),c=null;else{var d={backgroundImage:"url("+b.url+")",backgroundRepeat:"no-repeat",backgroundPosition:"center"};b.css.width&&b.css.height&&(d.backgroundSize=b.css.width+"px "+b.css.height+"px"),a.css(d)}c&&c()}function ib(b,c,d){var e,f=ra(b,!0),g=f&&wa(f.rot),h=Gc(b),i=f&&c*h,j=f&&(d||0)*h,k=-Math.cos(g)*i,l=Math.sin(g)*i,m=a.data(b,"turtleData");f&&(d&&(k+=Math.sin(g)*j,l+=Math.cos(g)*j),m&&(e=m.quickpagexy)&&(m.quickpagexy={pageX:e.pageX+l,pageY:e.pageY+k}),f.tx+=l,f.ty+=k,b.style[Pe]=ta(f),bb(b,m,!0))}function jb(b,c,d){var e,f=ra(b,!0),g=a.data(b,"turtleData");f&&(g&&(e=g.quickpagexy)&&(g.quickpagexy={pageX:e.pageX+c,pageY:e.pageY-d}),f.tx+=c,f.ty-=d,b.style[Pe]=ta(f),bb(b,g,!0))}function kb(a,b){var c=ra(a,!0);c&&(c.rot+=b,a.style[Pe]=ta(c))}function lb(a,b,c){var d=ra(a,!0);if(d){var e=Gc(a),f=wa(d.rot),g=b*e,h=(c||0)*e,i=-Math.cos(f)*g,j=Math.sin(f)*g;return h&&(i+=Math.sin(f)*h,j+=Math.cos(f)*h),sa(d.tx+j)+" "+sa(d.ty+i)}}function mb(b){return b&&a.isNumeric(b.pageX)&&a.isNumeric(b.pageY)}function nb(){return{get:function(a,b,c){return Oa(a).speed},set:function(b,c){(a.isNumeric(c)&&!(0>=c)||c in a.fx.speeds||""+c=="Infinity")&&(Oa(b).speed=""+c)}}}function ob(){return{get:function(a,b,c){return Oa(a).easing},set:function(b,c){c in a.easing&&(Oa(b).easing=c)}}}function pb(b,c){var d=a.data(b,"turtleData");return c=c||Df,d?a.isNumeric(d.speed)||"Infinity"==d.speed?1e3/d.speed:"turtle"==d.speed&&c?0:d.speed:c?0:"turtle"}function qb(b){var c=a.data(b,"turtleData");return c?c.easing:null}function rb(){return{get:function(a,b,c){var d=ra(a,b),e=y(a);if(d){var f=wa(d.rot),g=Math.cos(f),h=Math.sin(f),i=Gc(a);return sa(((d.tx+e[0])*h-(d.ty+e[1])*g)/i)+"px"}},set:function(b,c){var d,e=ra(b,!0)||{tx:0,ty:0,rot:0,sx:1,sy:1,twi:0},f=y(b),g=Gc(b),h=parseFloat(c)*g,i=wa(e.rot),j=Math.cos(i),k=Math.sin(i),l=(e.tx+f[0])*j+(e.ty+f[1])*k,m=l*j+h*k-f[0],n=l*k-h*j-f[1],o=a.data(b,"turtleData");o&&(d=o.quickpagexy)&&(o.quickpagexy={pageX:d.pageX+(m-e.tx),pageY:d.pageY+(n-e.ty)}),e.tx=m,e.ty=n,b.style[Pe]=ta(e),bb(b,o)}}}function sb(b,c,d,e){return{get:function(a,c,e){var f=ra(a,c);return f?f[b]+d:void 0},set:function(d,f){var g,h=ra(d,!0)||{tx:0,ty:0,rot:0,sx:1,sy:1,twi:0},i={displace:e},j=a.data(d,"turtleData"),k=h.tx,l=h.ty;h[b]=c(f,d,h,i),d.style[Pe]=ta(h),i.displace?(j&&(g=j.quickpagexy)&&(j.quickpagexy={pageX:g.pageX+(h.tx-k),pageY:g.pageY+(h.ty-l)}),bb(d,j)):Z(d)}}}function tb(a,b,c){var d=ya(b-a),e=d>0?c:-c,f=wa(a),g=[Math.cos(f)*e,Math.sin(f)*e],h=wa(b);return{delta:d,sradius:e,dc:g,dx:g[0]-Math.cos(h)*e,dy:g[1]-Math.sin(h)*e}}function ub(a,b,c,d,e,f){var g,h,j,k,l,m,n,o,p,r,t,u=tb(c,d,e),w=u.sradius,x=u.dc;for(n=1,o=u.delta,p=Math.abs(u.delta),p>45&&(n=Math.ceil(p/45),o=u.delta/n),r=[];--n>=0;)g=0===n?d:c+o,h=wa(c+180),j=wa(g+180),r.push.apply(r,v(h,j)),c=g;for(t=[],k=0;k2||(j.length>=1&&(i[c]=parseFloat(j[0])),j.length>=2?i[d]=parseFloat(j[1]):e?i[d]=0:i[d]=i[c],b.style[Pe]=ta(i),e?(k&&(h=k.quickpagexy)&&(k.quickpagexy={pageX:h.pageX+(i.tx-l),pageY:h.pageY+(i.ty-m)}),bb(b,k)):Z(b))}}}function Ab(a){return Se.href=a,Se}function Bb(a){return Ab(a).href}function Cb(a){return/(?:^|\.)pencil(?:code)?\./i.test(a)}function Db(a){var b=Ab(null==a?"":a).hostname,c=/^(\w+)\.pencil(?:code)?\./i.exec(b);return c?c[1]:null}function Eb(a,b){var c=Ab(null==a?"":a),d=c.href;return Cb(c.hostname)?/^\/(?:edit|home|code|load|save)(?:\/|$)/.test(c.pathname)&&(d=c.protocol+"//"+c.host+"/"+b+"/"+c.pathname.replace(/\/[^\/]*(?:\/|$)/,"")+c.search+c.hash):Cb(Ie.location.hostname)&&(d="/proxy/"+d),d}function Fb(a){return/\//.test(a)?a:(a="/img/"+a,Cb(Ie.location.hostname)?a:"//pencilcode.net"+a)}function Gb(){if(!document.cookie)return null;for(var a=document.cookie.split(/;\s*/),b=0;b0&&b.height>0)try{e=c.getContext("2d"),e.clearRect(0,0,b.width,b.height),e.drawImage(b,0,0)}catch(i){}}else c.src=b.src;d&&g.css(d);var j=y(c);if(b&&!d.turtleHull)try{var k=De(b);Ge(k,parseFloat(g.css("width"))/b.width,parseFloat(g.css("height"))/b.height,-j[0],-j[1]),g.css("turtleHull",k)}catch(i){}Lb(c,f,j)}function Lb(b,c,d){var e=a(b);if(e.hasClass("turtle")&&(d[0]!=c[0]||d[1]!=c[1]))if("absolute"==e.css("position")&&/px$/.test(e.css("left"))&&/px$/.test(e.css("top")))e.css("left",parseFloat(e.css("left"))+c[0]-d[0]),e.css("top",parseFloat(e.css("top"))+c[1]-d[1]);else{var f=ra(b,!0);f.tx+=c[0]-d[0],f.ty+=c[1]-d[1],b.style[Pe]=ta(f)}}function Mb(b,c,d,e,f){var g,h,i,j,k;return e===He&&f===He?(g=a(d),g.length?(h=g[0],i=N(h),S(_(h),i)?b.filter(function(){var b=N(this);return c===(R(i,b)||!Q(i,b)&&a(this).inside(h))}):b.filter(function(){return c===a(this).inside(h)})):[]):(j=a.isNumeric(e)&&a.isNumeric(f)?[e,f]:e,a.isArray(j)&&(j=X(b[0]||document.body,[j])[0]),"touch"===d?mb(j)?b.filter(function(){return c===a(this).touches(j)}):(g=a(j),i=N(g[0]),S(_(g[0]),i)?b.filter(function(){var a=N(this);return c===(!Q(i,a)&&(R(i,a)||g.touches(this)))}):b.filter(function(){return c===g.touches(this)})):(k=d*d,b.filter(function(){var a=N(this);if(O(j,k,a))return!c;if(P(j,k,a))return c;var b=Y(this),d=j.pageX-b.pageX,e=j.pageY-b.pageY;return c===k>=d*d+e*e})))}function Nb(){if(!Ze){Ze=!0;try{Ie.parent.document.activeElement.blur()}catch(a){}Ie.focus()}}function Ob(b,c,d,e,f){for(var g=e.split(/\s+/),h=0;h<0?void 0:c.apply(this,arguments)};c.guid&&(d.guid=c.guid),a.handler=d}}function Wb(){Ob(a.event.fixHooks,"filter",a.event.keyHooks,"keydown keyup",Tb),Ob(a.event.fixHooks,"filter",a.event.keyHooks,"keypress",Ub),Ob(a.event.special,"add",{},"keydown keyup keypress",Vb)}function Xb(){return{get:function(a,b,c){return g(Zb(a).getTimbre())},set:function(a,b){Zb(a).setTimbre(f(b,"wave"))}}}function Yb(){return{get:function(a,b,c){return Zb(a).getVolume()},set:function(a,b){Zb(a).setVolume(parseFloat(b))}}}function Zb(b){var c=Oa(b);if(c.instrument)return c.instrument;c.instrument=new ef("piano");var d=a(b);return c.instrument.on("noteon",function(b){var c=a.Event("noteon");c.midi=b.midi,d.trigger(c)}),c.instrument.on("noteoff",function(b){var c=a.Event("noteoff");c.midi=b.midi,d.trigger(c)}),c.instrument}function $b(){return af||(af=new ef),af}function _b(){return!(!Ie.AudioContext&&!Ie.webkitAudioContext)}function ac(){if(ac.audioTop)return ac.audioTop;if(!_b())return null;var a=new(Ie.AudioContext||Ie.webkitAudioContext);return ac.audioTop={ac:a,wavetable:jc(a),out:null,currentStart:null},bc(),ac.audioTop}function bc(){if(ac.audioTop){var a=ac.audioTop;a.out&&(a.out.disconnect(),a.out=null,a.currentStart=null);try{var b=a.ac.createDynamicsCompressor();b.ratio=16,b.attack=5e-4,b.connect(a.ac.destination),a.out=b}catch(c){ac.audioTop=null}}}function cc(){var a=ac();return null!=a.currentStart?a.currentStart:(a.currentStart=Math.max(.25,a.ac.currentTime),setTimeout(function(){a.currentStart=null},0),a.currentStart)}function dc(a){return 440*Math.pow(2,(a-69)/12)}function ec(a){return Math.round(69+12*Math.log(a/440)/Math.LN2)}function fc(a){var b=/^(\^+|_+|=|)([A-Ga-g])([,']*)$/.exec(a);if(!b)return null;var c=b[3].replace(/,/g,"").length-b[3].replace(/'/g,"").length,d=bf[b[2]]+cf[b[1].charAt(0)]*b[1].length+12*c;return d+60}function gc(a){var b=(a-72)%12;(a>60||0!=b)&&(b+=12);for(var c=Math.round((a-b-60)/12),d=df[b];0!=c;)d+=c>0?"'":",",c+=c>0?-1:1;return d}function hc(a){return dc(fc(a))}function ic(a){function b(a,b){switch(a){case"V":A!==z&&c(b.split(" ")[0]);break;case"M":f(b,A);break;case"L":g(b,A);break;case"Q":h(b,A)}A.hasOwnProperty(a)?A[a]+="\n"+b:A[a]=b,"K"==a&&(B=k(b),A===z&&c(d()))}function c(a){a=a||"",(a||A===z)&&(z.voice||(z.voice={}),z.voice.hasOwnProperty(a)?(A=z.voice[a],C=A.accent):(A={id:a,accent:{slurred:0}},z.voice[a]=A,C=A.accent))}function d(){return z.V?z.V.split(/\s+/)[0]:""}function e(a){var e,f=a.match(gf),g=null,h=0,i=0,j=null;if(!f)return null;for(;h/.test(f[h]))i=f[h++].length;else if(/^\(\d+(?::\d+)*/.test(f[h]))j=o(f[h++]);else if(/^[!+].*[!+]$/.test(f[h]))p(f[h++],C);else if(/^.?".*"$/.test(f[h]))h++;else if(/^[()]$/.test(f[h]))"("==f[h++]?C.slurred+=1:(C.slurred-=1,C.slurred<=0&&(C.slurred=0,A.stems&&A.stems.length>=1&&m(A.stems[A.stems.length-1],!1)));else if(/\|/.test(f[h])){for(e in C)1==e.length&&delete C[e];h++}else g=q(f,h,B,C),null!==g?(j&&(n(g.stem,j.time),j.count-=1,j.count||(j=null)),i&&A.stems&&A.stems.length&&(e=i>0?(1-Math.pow(.5,i))*g.stem.time:(Math.pow(.5,-i)-1)*A.stems[A.stems.length-1].time,l(A.stems[A.stems.length-1],e),l(g.stem,-e)),i=0,C.slurred&&m(g.stem,!0),A===z&&c(d()),"stems"in A||(A.stems=[]),A.stems.push(g.stem),h=g.index):h++}function f(a,b){var c=/^C/.test(a)?1:t(a);c&&(b.unitnote||(.75>c?b.unitnote=1/16:b.unitnote=1/8))}function g(a,b){var c=t(a);c&&(b.unitnote=c)}function h(a,b){var c,d=a.split(/\s+|=/),e=null,f=null;for(c=0;c=0||/^[1-4]$/.test(d[c])?e=e||t(d[c]):f=f||Number(d[c]);e&&(b.unitbeat=e),f&&(b.tempo=f)}function i(a){var b,c,d,e,f,g={};for(c=0;c0)for(b=0;a>b&&7>b;++b)d[c.charAt(b)]="^";else for(b=0;b>a&&b>-7;--b)d[c.charAt(6+b)]="_";return d}function k(a){if(!a)return{};var b,c={"c#":7,"f#":6,b:5,e:4,a:3,d:2,g:1,c:0,f:-1,bb:-2,eb:-3,ab:-4,db:-5,gb:-6,cb:-7,"a#m":7,"d#m":6,"g#m":5,"c#m":4,"f#m":3,bm:2,em:1,am:0,dm:-1,gm:-2,cm:-3,fm:-4,bbm:-5,ebm:-6,abm:-7,"g#mix":7,"c#mix":6,"f#mix":5,bmix:4,emix:3,amix:2,dmix:1,gmix:0,cmix:-1,fmix:-2,bbmix:-3,ebmix:-4,abmix:-5,dbmix:-6,gbmix:-7,"d#dor":7,"g#dor":6,"c#dor":5,"f#dor":4,bdor:3,edor:2,ador:1,ddor:0,gdor:-1,cdor:-2,fdor:-3,bbdor:-4,ebdor:-5,abdor:-6,dbdor:-7,"e#phr":7,"a#phr":6,"d#phr":5,"g#phr":4,"c#phr":3,"f#phr":2,bphr:1,ephr:0,aphr:-1,dphr:-2,gphr:-3,cphr:-4,fphr:-5,bbphr:-6,ebphr:-7,"f#lyd":7,blyd:6,elyd:5,alyd:4,dlyd:3,glyd:2,clyd:1,flyd:0,bblyd:-1,eblyd:-2,ablyd:-3,dblyd:-4,gblyd:-5,cblyd:-6,fblyd:-7,"b#loc":7,"e#loc":6,"a#loc":5,"d#loc":4,"g#loc":3,"c#loc":2,"f#loc":1,bloc:0,eloc:-1,aloc:-2,dloc:-3,gloc:-4,cloc:-5,floc:-6,bbloc:-7},d=a.replace(/\s+/g,"").toLowerCase().substr(0,5),e=d.match(/maj|min|mix|dor|phr|lyd|loc|m/);b=e?"maj"==e?d.substr(0,e.index):"min"==e?d.substr(0,e.index+1):d.substr(0,e.index+e[0].length):/^[a-g][#b]?/.exec(d)||"";var f=j(c[b]),g=a.substr(b.length).match(/(_+|=|\^+)[a-g]/gi);if(g)for(var h=0;h<2))switch(a=a.substring(1,a.length-1)){case"pppp":case"ppp":b.dynamics=.2;break;case"pp":b.dynamics=.4;break;case"p":b.dynamics=.6;break;case"mp":b.dynamics=.8;break;case"mf":b.dynamics=1;break;case"f":b.dynamics=1.2;break;case"ff":b.dynamics=1.4;break;case"fff":case"ffff":b.dynamics=1.5}}function q(a,b,c,d){var e,f,g,h,i=[],j="",k=!1,l=null,m=1/0;if(bf&&(j=e,m=f),b0&&"="==a.charAt(0)?a.substr(1):a}function s(a,b,c){var d,e=/^(\^+|_+|=|)([A-Ga-g])(.*)$/.exec(a);return e?(d=e[2].toUpperCase(),e[1].length>0?(c[d]=e[1],r(a)):r(c.hasOwnProperty(d)?c[d]+e[2]+e[3]:b.hasOwnProperty(d)?b[d]+e[2]+e[3]:a)):a}function t(a){var b,c,d,e=/^(\d*)(?:\/(\d*))?$|^(\/+)$/.exec(a),f=0;if(e){if(e[3])return Math.pow(.5,e[3].length);if(c=e[2]?parseFloat(e[2]):/\//.test(a)?2:1,d=0,b=e[1]?parseFloat(e[1]):1,e[2])for(;d+1c;)d+=1,f=parseFloat(e[1].substring(0,d)),b=parseFloat(e[1].substring(d));return f+b/c}}var u,v,w,x,y=a.split("\n"),z={},A=z,B={},C={slurred:0};for(u=0;uc;++c)e[c]=b.real[c],f[c]=b.imag[c];try{return a.createPeriodicWave(e,f)}catch(g){}try{return a.createWaveTable(e,f)}catch(g){}return null}function d(a,b,c){var d,e,f={real:[],imag:[]},g=a.real.length;for(d=0;g>d;++d)e=Math.log(b[Math.min(d,b.length-1)]),f.real.push(a.real[d]*Math.exp(c*e)),f.imag.push(a.imag[d]*Math.exp(c*e));return f}var e,f,g,h,i,j,k={};for(e in b)if(f=b[e],j=c(f)){if(i={wave:j},f.mult)for(h=b[e].freq,i.freq={},g=0;gc;++c)b[c]&&(b[c].constructor===a?e.push.apply(e,b[c].toArray()):a.isArray(b[c])?e.push.apply(e,b[c]):e.push(b[c]));return{elts:a.unique(e),completion:d}}function lc(){function b(){var a,b=g;for(g=null,f&&f(),a=0;a1)for(c=0;c")}function oc(b){var c,d,e=a.extend({},sf,hf,tf);if(b&&!a.isArray(b.helptext)&&b in e&&(b=e[b]),b&&a.isArray(b.helptext)&&b.helptext.length){for(d=0;d/g,'<$1 style="border:1px solid black;text-decoration:none;word-break:keep-all;white-space:nowrap">').replace(/<(mark)>/g,'<$1 style="border:1px solid blue;color:blue;text-decoration:none;word-break:keep-all;white-space:nowrap;cursor:pointer;" onclick="see.enter($(this).text())">'))}return vf}if("number"==typeof b)return nc("Equal to the number "+b+"."),vf;if("boolean"==typeof b)return nc("Equal to the boolean value "+b+"."),vf;if(null===b)return nc("The special null value represents the absence of a value."),vf;if(b===He)return nc("This is an unassigned value."),vf;if(b===Ie)return nc("The global window object represents the browser window."),vf;if(b===document)return nc("The HTML document running the program."),vf;if(b===jQuery)return nc('The jQuery function. Read about it at
jquery.com.'),vf;if(b&&b!=oc)return nc("No help available for "+b),vf;c=[];for(var g in e)!e[g].helptext||!e[g].helptext.length||g in Ie&&"function"!=typeof Ie[g]||c.push(g);return c.sort(function(a,b){return a.length!=b.length?a.length-b.length:b>a?-1:a>b?1:0}),nc("help available for: "+c.map(function(a){return''+a+""}).join(" ")),vf}function pc(a){return 1==a.length&&qc(a[0])&&a[0]}function qc(b){var c;return b&&0==a.queue(b).length&&(!b.parentElement||!b.parentElement.style.transform)&&(0===(c=pb(b))||0===a.fx.speeds[c])}function rc(b,c){var d;if(null==c){if(qc(b))return;d=pb(b)}else d=1e3*c;var e=a(b);d>0&&e.delay(d)}function sc(a,b){if(b=b||0,a.length<=b)return null;var c=a[a.length-1];return"function"!=typeof c||c.helpname?null:c}function tc(b,c,d,e){function f(d,e){if(null!=d){var f=b&&b[d];e&&f&&bb(f,a.data(f,"turtleData"),!0),Hf.reportEvent("resolve",[c,m,j,d,f])}0==--k&&h&&(l?(Me+=1,setTimeout(function(){Me-=1,h()},0)):h())}function g(a){null!=a&&Hf.reportEvent("appear",[c,m,j,a,b&&b[a],i])}var h=sc(d,e),i=h?Array.prototype.slice.call(d,0,d.length-1):d,j=b?b.length||0:0,k=j+1,l=!0,m=Hf.nextId();return Hf.reportEvent("enter",[c,m,j,i]),{name:c,args:i,appear:g,resolve:f,resolver:function(a,b){return function(){f(a,b)}},exit:function(){Hf.reportEvent("exit",[c,m,j,i]),f(null),l=!1}}}function uc(b,c,d,e){var f=function(){if(Vc(b),Le)throw new Error(b+" interrupted");var d,f=tc(this,b,arguments,c),g=[f].concat(a.makeArray(f.args));try{d=e.apply(this,g)}finally{f.exit()}return d};return zc(b,d,f)}function vc(a,b,c){var d=function(){if(Vc(a),Le)throw new Error(a+" interrupted");return Wc(a,this),c.apply(this,arguments)};return zc(a,b,d)}function wc(b,c,d,e){var f=function(){if(Vc(b),Le)throw new Error(b+" interrupted");var c=null,f=0,g=pf;if(e&&(c=e.apply(null,arguments),f=arguments.length,g=Yc()),g){var h=a(pf).eq(0),i=arguments,j=tc(h,b,arguments,f);h.plan(function(a,b){j.appear(a),d.apply(c,i),this.plan(j.resolver(a))}),j.exit()}else j=tc(null,b,arguments,f),d.apply(c,arguments),j.exit();return c?(c.result&&c.result.constructor===jQuery&&pf&&lc(pf,c.result),c.result):void 0};return zc(b,c,f)}function xc(b,c){return zc(b,c,function(c,d){var e=/^key/.test(b),f=/^mouse|click$/.test(b),g=f?"input,button":e?"textarea,input:not([type]),input[type=text],input[type=password]":null;e&&Nb(),null==d&&"function"==typeof c&&(d=c,c=null),a(Ie).on(b+".turtleevent",null,c,g?function(b){return Le||a(b.target).closest(g).length?void 0:d.apply(this,arguments)}:d)})}function yc(){var b=a._data(Ie,"events");if(!b)return!1;for(var c in b)for(var d=b[c],e=0;eb?-c:c,l=null;i.style&&i.down&&(l=function(){var a=Y(h),c=ra(h,!0),d=z(h.parentElement);return function(){ub(i.corners[0],a,c.rot,c.rot+(e?-b:b),k*(i.oldscale?c.sy:1),d)}}()),i.turningRadius=k,this.animate({turtleRotation:g+sa(b)+"deg"},pb(h,f),qb(h)),this.plan(function(){l&&l(),i.turningRadius=j,a.resolve(d,!0)})}),this)}function Bc(a,b){null==b&&(b=100),"bk"===a.name&&(b=-b);var c,d=Df;return(c=pc(this))?(a.appear(0),ib(c,b,0),a.resolve(0,!0),this):(this.plan(function(c,e){a.appear(c),this.animate({turtleForward:"+="+sa(b||0)+"px"},pb(e,d),qb(e),a.resolver(c,!0))}),this)}function Cc(b,c,d){a.isArray(c)&&(d=c[1],c=c[0]),d||(d=0),c||(c=0);var e=Df;return this.plan(function(a,f){b&&b.appear(a),this.animate({turtlePosition:lb(f,d,c)},pb(f,e),qb(f),b&&b.resolver(a,!0))}),this}function Dc(b,c,d){a.isArray(c)&&(d=c[1],c=c[0]),d||(d=0),c||(c=0);var e,f=Df;return(e=pc(this))?(b&&b.appear(0),jb(e,c,d),b&&b.resolve(0),this):(this.plan(function(a,e){b&&b.appear(a);var g=w(e);this.animate({turtlePosition:sa(g[0]+c)+" "+sa(g[1]-d)},pb(e,f),qb(e),b&&b.resolver(a,!0))}),this)}function Ec(b,c,d){var e=c,f=0,g=0,h=null,i=Df;return a.isNumeric(e)&&a.isNumeric(d)?(f=parseFloat(e),g=parseFloat(d),e=null,h=null):a.isArray(e)?(f=e[0],g=e[1],e=null,h=d):a.isNumeric(d)&&(h=d),this.plan(function(c,d){var j=e;if(null===j&&(j=a(V(d)).pagexy()),j&&!mb(j))try{j=a(j).pagexy()}catch(k){return}return j&&mb(j)?a.isWindow(d)?(b&&b.appear(c),ba(j,h),void(b&&b.resolve(c))):void(9!==d.nodeType&&(b&&b.appear(c),this.animate({turtlePosition:U(d,j,h,f,g)},pb(d,i),qb(d),b&&b.resolver(c,!0)))):void 0}),this}function Fc(a){return function(b,c,d){return this.plan(function(e,f){b.appear(e);var g=this.css("turtlePenDown");this.css({turtlePenDown:"up"}),a.call(this,null,c,d),this.plan(function(){this.css({turtlePenDown:g}),b.resolve(e,!0)})}),this}}function Gc(b){var c=a.data(b,"turtleData");return c&&null!=c.oldscale?c.oldscale:1}function Hc(a,b,c){Jc.call(this,!0,a,b,c)}function Ic(a,b,c){Jc.call(this,!1,a,b,c)}function Jc(b,c,d,e){e===He&&(e=d),d&&e||(d=e=1);var f=Df;return this.plan(function(g,h){if(b&&(Oa(h).oldscale*=e),c.appear(g),a.isWindow(h)||9===h.nodeType)return void c.resolve(g);var i=a.map(a.css(h,"turtleScale").split(" "),parseFloat);1===i.length&&i.push(i[0]),i[0]*=d,i[1]*=e,this.animate({turtleScale:a.map(i,sa).join(" ")},pb(h,f),qb(h),c.resolver(g))}),this}function Kc(a,b){var c=z(a.parentElement),d=l(c),e=d?1:u(c)[1];return e*Gc(a)}function Lc(b){var c=Df;return function(d,e,f){if(a.isNumeric(e)){var g=e;e=f,f=g}return null==f&&(f=8.8),this.plan(function(g,h){var i=Oa(h),j=i.style;e||(e=j&&(j.fillStyle||j.strokeStyle)||"black"),d.appear(g);var k=this.pagexy(),l=ra(h,!0),m=Ka(e,"fillStyle"),n=Da(i),o=Kc(h),p=f*o,q=Math.max(0,p-2),r=p+(m.eraseMode?2:0),s=/rgba|hsla/.test(m.fillStyle);null==m.lineWidth&&j&&j.lineWidth&&(m.lineWidth=j.lineWidth),pc(this)?(b(n,k,r,l.rot,m,!0),d.resolve(g)):this.queue(function(e){a({radius:0}).animate({radius:q},{duration:pb(h,c),step:function(){s||b(n,k,this.radius,l.rot,m,!1)},complete:function(){b(n,k,r,l.rot,m,!0),d.resolve(g),e()}})})}),this}}function Mc(a,b,c,d,e){var f=a.getContext("2d");f.save(),Xa(f,e),c===1/0?(f.setTransform(1,0,0,1,0,0),f.fillRect(0,0,a.width,a.height)):(Za(f,a),f.beginPath(),f.arc(b.pageX,b.pageY,c/2,0,2*Math.PI,!1),f.closePath(),f.fill(),e.strokeStyle&&f.stroke()),f.restore()}function Nc(a,b,c,d,e){var f=a.getContext("2d");if(f.save(),Xa(f,e),c===1/0)f.setTransform(1,0,0,1,0,0),f.fillRect(0,0,a.width,a.height);else{var g=Math.sin((d+45)/180*Math.PI),h=Math.cos((d+45)/180*Math.PI),i=c*h/Math.SQRT2,j=c*g/Math.SQRT2;Za(f,a),f.beginPath(),f.moveTo(b.pageX-i,b.pageY-j),f.lineTo(b.pageX-j,b.pageY+i),f.lineTo(b.pageX+i,b.pageY+j),f.lineTo(b.pageX+j,b.pageY-i),f.closePath(),f.fill(),e.strokeStyle&&f.stroke()}f.restore()}function Oc(a,b,c,d,e,f){var g=a.getContext("2d");if(g.save(),Xa(g,e),!e.strokeStyle&&e.fillStyle&&(g.strokeStyle=e.fillStyle),c!==1/0){var h=Math.sin(d/180*Math.PI),i=-Math.cos(d/180*Math.PI),j=e.lineWidth||1.62,k=b.pageX+c*h,l=b.pageY+c*i,m=Pc(j,k,l,h,i),n=c-m.hs,o=n*h,p=n*i;Za(g,a),n>0&&(g.beginPath(),g.moveTo(b.pageX,b.pageY),g.lineTo(b.pageX+o,b.pageY+p),g.stroke()),f&&Qc(g,m)}g.restore()}function Pc(a,b,c,d,e){var f=Math.max(1.25*a,a+2),g=2*f,h=g-f/2;return{hs:h,x1:b,y1:c,xm:b-d*h,ym:c-e*h,x2:b-e*f-d*g,y2:c+d*f-e*g,x3:b+e*f-d*g,y3:c-d*f-e*g}}function Qc(a,b){a.beginPath(),a.moveTo(b.x2,b.y2),a.lineTo(b.x1,b.y1),a.lineTo(b.x3,b.y3),a.quadraticCurveTo(b.xm,b.ym,b.x2,b.y2),a.closePath(),a.fill()}function Rc(a,b,c,d,e,f){var g=e-c,h=f-d,i=Math.sqrt(g*g+h*h),j=g/i,k=h/i,l=Pc(b,e,f,j,k);i>l.hs&&(a.beginPath(),a.moveTo(c,d),a.lineTo(l.xm,l.ym),a.lineWidth=b,a.stroke()),Qc(a,l)}function Sc(a,b){function c(){d&&clearInterval(d),b&&b()}var d=null;if(!Ie.speechSynthesis)return console.log("No speech synthesis: "+a),void c();try{var e=new Ie.SpeechSynthesisUtterance(a);e.addEventListener("end",c),e.addEventListener("error",c),e.lang=navigator.language||"en-GB",Ie.speechSynthesis.speak(e),d=setInterval(function(){Ie.speechSynthesis.pending||Ie.speechSynthesis.speaking||c()},250)}catch(f){Ie.console&&Ie.console.log(f),c()}}function Tc(){a.each(["toggle","show","hide"],function(b,c){var d=a.fn[c];a.fn[c]=function(b,c,e){var f=arguments;!f.length&&this.hasClass("turtle")&&(this.length>1||!a._data(this[0],"fxshow"))&&(f=[0]),d.apply(this,f)}})}function Uc(c,d){if(d||(d="fx"),"IMG"==c.tagName&&c.src&&!c.complete){var e=a.queue(c,d);0==e.length&&(a.queue(c,d,function(a){Ib(c,null,a)}),b(c,d))}}function Vc(b){if(!(a.turtle.hangtime==1/0||kf++<100)){kf=0;var c=(new Date).getTime();return mf?void(c-mf>a.turtle.hangtime&&(Sf.visible()&&Sf.html('Oops: program interrupted because it was hanging the browser. Try reducing the number of repetitions. Or try using await done defer() or tick to make an animation.'),a.turtle.interrupt("hung"))):(mf=c,clearTimeout(lf),void(lf=setTimeout(function(){clearTimeout(lf),lf=null,mf=null},0)))}}function Wc(b,c){if(!a.turtle.nowarn){var d,e=!0;for(d=0;e&&d=100&&(e=!1);e||(jf[b]||(jf[b]=1,Sf.visible()?Sf.html('Oops: '+b+' may not return useful results when motion is queued. Try speed Infinity or await done defer() first.'):console.warn(b+' may not return useful results when motion is queued. Try "speed Infinity" or "await done defer()".')),c.finish())}}function Xc(a,b,d){a[b]=function(){return b in jf||(Sf.html(''+b+" deprecated. Use "+d+"."),jf[b]=1),a[d].apply(this,arguments)},a[d].__super__&&c(a[b],a[d])}function Yc(){return pf&&a.queue(pf).length>0}function Zc(a){if(null===uf.pollTimer){var b=uf.sent[a],c=uf.waiting[a];c&&c.length&&b&&b.length&&(uf.pollTimer=setTimeout(function(){uf.pollTimer=null,c&&c.length&&b&&b.length&&(c.shift().apply(null,b.shift()),Zc(a))},0))}}function $c(a,b){if("function"!=typeof b&&"undefined"!=typeof b||!/^\w+\s*$/.test(a)){if("undefined"==typeof b&&/^help\s+\S+$/.test(a))return oc(/^help\s+(\S+)$/.exec(a)[1]),!0}else{if(b&&b.helptext)return oc(b),!0;if(a in tf)return oc(a),!0}return!1}function _c(a,b,c,d){return a.helptext?d.helptext=a.helptext:b in c&&(d.helptext=c[b].helptext),d.method=a,d.helpname=b,d}function ad(a,b){var c=[];for(var d in b)!b.hasOwnProperty(d)||d in Ie||(c.push(d),Ie[d]=function(b){var c=a[b],d=a;return _c(c,b,tf,function(){return c.apply(d,arguments)})}(d));return c}function bd(){pf=null;for(var a=0;a=0;i--)null===h[i]?(i--,c.moveTo(d-h[i][0],e+h[i][1])):c.lineTo(d-h[i][0],e+h[i][1])}return c.lineWidth=1.1,c.strokeStyle="rgba(255,255,255,0.75)",c.stroke(),c.beginPath(),c.arc(d,e,15.5,0,2*Math.PI,!1),c.closePath(),c.strokeStyle="rgba(0,0,0,0.4)",c.stroke(),b.toDataURL()}function gd(a){var b=Ga(40,48),c=b.getContext("2d");return c.beginPath(),c.moveTo(0,48),c.lineTo(20,0),c.lineTo(40,48),c.lineTo(20,36),c.closePath(),c.fillStyle=a,c.fill(),b.toDataURL()}function hd(a){var b=Ga(40,40),c=b.getContext("2d");return c.beginPath(),c.arc(20,20,18,-5*Math.PI/2,-Math.PI/2),c.closePath(),c.lineTo(20,20),c.stroke(),c.strokeStyle=a,c.lineWidth=4,c.stroke(),b.toDataURL()}function id(a,b){b=b||12;var c=Ga(b,b),d=c.getContext("2d"),e=b/2;return d.beginPath(),d.arc(e,e,e,0,2*Math.PI),d.closePath(),d.fillStyle=a,d.fill(),c.toDataURL()}function jd(a){function b(){e.moveTo(19.5,43),e.lineTo(20.5,43),e.lineTo(21.5,43.5),e.lineTo(25.5,36.2),e.lineTo(24,35.5),e.lineTo(23,35.5),e.lineTo(20.5,36.5),e.lineTo(19.5,36.5),e.lineTo(17,35.5),e.lineTo(16,35.5),e.lineTo(14.5,36.2),e.lineTo(18.5,43.5),e.closePath()}function c(){e.moveTo(25.5,12),e.lineTo(25.5,8),e.lineTo(14.5,8),e.lineTo(14.5,12),e.closePath()}var d=Ga(40,48),e=d.getContext("2d");return e.beginPath(),b(),e.fillStyle="#ffcb6b",e.fill(),e.beginPath(),c(),e.fillStyle="#d1ebff",e.fill(),e.beginPath(),e.moveTo(19.5,48),e.lineTo(13,36),e.lineTo(13,1),e.lineTo(14,0),e.lineTo(26,0),e.lineTo(27,1),e.lineTo(27,36),e.lineTo(20.5,48),e.closePath(),b(),e.moveTo(25.5,12),e.lineTo(25.5,8),e.lineTo(14.5,8),e.lineTo(14.5,12),e.closePath(),e.fillStyle=a,e.fill(),d.toDataURL()}function kd(a,b,c){return c||(c=1),function(d){var e=document.createElement("canvas");e.width=a,e.height=b;var f=e.getContext("2d");d||(d="rgba(128,128,128,0.125)"),"transparent"!=d&&(f.fillStyle=d,f.fillRect(0,0,a,b));var g=a/c,h=b/c,i={width:g,height:h,transformOrigin:g/2+"px + "+h/2+"px",opacity:1};return 1>c&&(i.imageRendering="pixelated"),{img:e,css:i}}}function ld(a){if(!a)return null;if(a in yf)return yf[a];var b=a.match(/^(\d+)x(\d+)(?:\/(\d+))?$/);return b?kd(parseFloat(b[1]),parseFloat(b[2]),b[3]&&parseFloat(b[3])):null}function md(a,b){var c=a.width||a.height||256,d=a.height||a.width||256,e=a.subpixel||1/(a.scale||1),f=a.color||"transparent",g=kd(c,d,e);return g(f)}function nd(b,c){if(!b)return null;if(a.isPlainObject(b))return md(b,c);if(a.isFunction(b)&&(b.helpname||b.name)&&(b=b.helpname||b.name),b.constructor===jQuery){if(!b.length)return null;b=b.get(0)}if(b.tagName)return"CANVAS"!=b.tagName&&"IMG"!=b.tagName&&"VIDEO"!=b.tagName?null:{img:b,css:{opacity:1}};var d=b.toString().trim().split(/\s+/),e=null,f=null;if(d.length&&(f=ld(d[d.length-1]),f&&d.pop()),d.length&&cd(d.join(" "))&&(e=d.join(" "),d.length=0),!f&&e&&(f=ld(c)),f)return f(e);if(/\//.test(b)||(b=Fb(b)),/\//.test(b)){var g=Ab(b).hostname;return!Cb(g)&&Cb(Ie.location.hostname)&&(b=Ie.location.protocol+"//"+Ie.location.host+"/proxy/"+Bb(b)),{url:b,css:{transformOrigin:"50% 50%",opacity:1}}}return null}function od(a){return null==a?"":String(a).replace(/[&<>"]/g,function(a){return zf[a]})}function pd(b,c,d){var e=b&&/^[a-zA-Z]\w*$/.exec(b),f=b&&/^<.*>$/.exec(b),g=nd(b,d)||null==b&&nd(d);e&&a("#"+b).length&&(e=!1);var h;g?(h=a(""),hb(h,g)):h=a(f?b:"
"+od(b)+"
"),b&&"object"==typeof b&&("id"in b&&h.attr("id",b.id),"class"in b&&h.addClass(b["class"])),h.css({position:"absolute",display:"table",top:0,left:0}),(!c||9==c.nodeType||a.isWindow(c))&&(c=za()),h.appendTo(c);var i=y(h[0]);return h.css({top:-i[1],left:-i[0]}),h.css({turtlePosition:U(h[0],a(c).pagexy(),null,0,0),turtleRotation:0,turtleScale:1}),h.addClass("turtle"),e&&(h.attr("id",b),rf&&!Ie.hasOwnProperty(b)&&(Ie[b]=h)),h}function qd(a,b){if("number"==typeof a)return a=Math.ceil(a),"number"==typeof b?(b=Math.ceil(b),Math.floor(Math.random()*(b-a)+a)):Math.floor(Math.random()*a);if("object"==typeof a&&a&&a.length&&a.slice)return a[Math.floor(Math.random()*a.length)];if("normal"==a){var c,d,e,f,g;do c=Math.random(),d=1.7156*(Math.random()-.5),e=c-.449871,f=Math.abs(d)+.386595,g=e*e+f*(.196*f-.25472*e);while(g>.27597&&(g>.27846||d*d>-4*Math.log(c)*c*c));return d/c}return"position"==a?{pageX:qd(K()+1),pageY:qd(J()+1)}:"color"==a?"hsl("+Math.floor(360*Math.random())+",100%,50%)":"gray"==a?"hsl(0,0,"+Math.floor(100*Math.random())+"%)":a===!0?Math.random()>=.5:Math.random()}function rd(b,c){c||"function"!=typeof b||(c=b,b=30);var d=null,e=Math.max(Math.floor(1e3/Math.max(1/86400,b)),0);if(Yc()){var f=a(pf);f.plan(function(){d=c})}else d=c;var g={fn:c,timer:setInterval(function(){if(d)try{Df++,Bf.push(g),d()}finally{Df--,Bf.pop(g)}},e)};return Af.push(g),g.timer}function sd(a){for(var b=[],c=0;c0?1e3/b:0)}function wd(b){b===He&&(b=""),a("[id]").each(function(c,d){Ie[b+d.id]=a("#"+d.id)}),rf=!0}function xd(b){if(b===He&&(b="last"),Ef&&a(Ie).off(a.map(of,function(a,b){return b}).join(" "),Ef),b||""===b){Ef=function(a){var c,d=[b+a.type];for((a.originalEvent||a)instanceof MouseEvent&&d.push(b+"mouse"),c=0;c=a("html").outerHeight(!0);if(b(),e){var f=a(Ie).scrollTop(),g=Math.min(d,a("html").outerHeight(!0)-a(Ie).height());g>f&&a(Ie).scrollTop(g)}}function zd(){if(!Ff.timer){Ff.timer=setTimeout(function(){Ff.timer=null},0);var b=a("body").offset(),c=b?b.top:8;Ff.bottomSeen=Math.min(a(Ie).height()+a(Ie).scrollTop(),a("body").height()+c)}return Ff.bottomSeen}function Ad(b){var c=a(Ie).scrollTop();b(),a(Ie).scrollTop(c)}function Bd(){var a=document.body.lastChild;return a&&"PRE"==a.tagName||(a=document.createElement("pre"),document.body.appendChild(a)),a}function Cd(){var a=arguments;yd(function(){for(var b=Bd(),c=0;c").css({display:"inline-block",verticalAlign:"top",textAlign:"center",height:"1.2em",width:"1.2em",maxWidth:"1.2em",overflow:"hidden"}).appendTo(Bd()),e=function(){null!=b&&d.css({background:b}),null!=c&&d.text(c)};if(pf){var f=a(pf);Ec.call(f,null,d),f.eq(0).plan(e)}else e()}function Ed(){var a=this;yd(function(){a.result.appendTo("body"),a.setup&&a.setup()})}function Fd(b,c){var d="<"+c+' style="display:table">',e="";if(b===He||null===b)return{result:a(d+"
"+e)};if(b.jquery||b instanceof Element&&(b=a(b)))return{result:b};var f=null;return b=""+b,/^\s*<.*>\s*$/.test(b)&&(f=a(b)),(null==f||1!=f.length||1!=f[0].nodeType)&&(f=a(d+b+e)),{result:f}}function Gd(b,c){function d(b){return function(d){j||m&&"change"==d.type||(j=!0,a(this).prop("checked",!0),i.find("input[type=radio]").prop("disabled",!0),c(b))}}function e(a){return function(){j||(l=a,f())}}function f(a){a||(m+=1,setTimeout(function(){m-=1},0),i.find("input").eq(l).prop("checked",!0)),i.find("input").eq(l).focus()}function g(b,c){a.isFunction(b)&&(b=(k+1).toString());var f=a.isFunction(c)||null==c?b:c,g=a('').attr("value",f).on("change click",d(c)),h=a('