Commits

Alexander Tsepkov committed e6944bf

Lots of fixes, also added re, math, random and unittest libraries

Comments (0)

Files changed (14)

 RapydScript already adds several modules you can import by default, like `stdlib` and `yql`. Check out the examples or the documentation in the modules themselves for usage.
 
 
+Available Libraries
+-------------------
+One of Python's main strengths is the number of libraries available to the developer. This is something very few other `Python-in-a-browser` frameworks understand. In the browser JavaScript is king, and no matter how many libraries the community for the given project will write, the readily-available JavaScript libraries will always outnumber them. This is why RapydScript was designed with JavaScript and DOM integration in mind from the beginning. Indeed, plugging `underscore.js` in place of RapydScript's `stdlib` will work just as well, and some developers may choose to do so, after all, `underscore.js` is very Pythonic and very complete. Likewise, `sprintf.js` (<https://npmjs.org/package/sprintf-js>) can be used with RapydScript to replicate Python's string interpolation.
+
+It is for that reason that I try to keep RapydScript bells and whistles to a minimum. RapydScript's main strength is easy integration with JavaScript and DOM, which allows me to stay sane and not rewrite my own versions of the libraries that are already available. That doesn't mean, however, that pythonic libraries can't be written for RapydScript. To prove that, I have implemented lightweight clones of several popular Python libraries and bundled them into RapydScript, you can find them in `src` directory. The following libraries are included:
+
+	stdlib/stdlib2		# see stdlib section
+	math				# replicates almost all of the functionality from Python's math library
+	re					# replicates almost all of the functionality from Python's re library
+	unittest			# replicates almost all of the functionality from Python's unittest library
+	random				# replicates most of the functionality from Python's random library
+	yql					# lightweight library for performing Yahoo Query Language requests
+
+For the most part, the logic implemented in these libraries functions identically to the Python versions. One notable exception is that unittest library requires that classes be bound to the `global` (nodejs) or `window` (browser) object to be picked up by `unittest.main()`. An example in `unitetest.pyj` shows this usage. I'd be happy to include more libraries, if other members of the community want to implement them (it's fun to do, `re.pyj` is a good example), but I want to reemphasize that unlike most other Python-to-JavaScript compilers, RapydScript doesn't need them to be complete since there are already tons of available JavaScript libraries that it can use natively.
+
+
 Advanced Usage Topics
 ---------------------
 This section contains various topics which might be of interest to the programmer writing large projects using RapydScript, but might not be relevant to a programmer who is just getting started with RapydScript. The topics in this section focus on coding conventions to keep your code clean, optimizations, and additional libraries that come with RapydScript, as well as suggestions for writing your own libraries.
 
 This is especially useful with function definitions, since you will immediately know what kind of object the function takes in just by skimming its signature.
 
+#### Libraries
+I recommend that developers rely on native JavaScript logic when possible, rather than libraries like `math.pyj` and `re.pyj`. While they mimic Python without problems and work quite well, they introduce extra overhead that your web app doesn't need. Additionally, I think `re` module in Python is unnecessarily complex, and JavaScript's `RegExp` object is much easier to use. With that said, these libraries can be extremely useful for porting large applications from Python to the web, but if you're writing new code, it will probably be easier to maintain if you decide to use native JavaScript alternatives (such as `Math` and `RegExp`) instead.
+
 
 Quirks
 ------

c.js

-assert = require("assert");
-(function(){
-    function _$rapyd$_bind(fn, thisArg) {
-        if (fn.orig) fn = fn.orig;
-        var ret = function() {
-            return fn.apply(thisArg, arguments);
-        }
-        ret.orig = fn;
-        return ret;
-    }
-    function _$rapyd$_unbindAll(thisArg, rebind) {
-        for (var p in thisArg) {
-            if (thisArg[p] && thisArg[p].orig) {
-                if (rebind) thisArg[p] = _$rapyd$_bind(thisArg[p], thisArg);
-                else thisArg[p] = thisArg[p].orig;
-            }
-        }
-    }
-    function hasattr(obj, name) {
-        return name in obj;
-    }
-    function getattr(obj, name) {
-        return obj[name];
-    }
-    function setattr(obj, name, value) {
-        obj[name] = value;
-    }
-    var blank, bob, joe, angela, bound, st, c, inc, m;
-    function Blank() {
-        if (!(this instanceof arguments.callee)){
-            return new arguments.callee(Array.prototype.slice.call(arguments));
-        }
-    }
-
-    blank = Blank();
-
-    assert.ok(blank instanceof Blank);
-
-    function Human(){
-        var self = this;
-        if (!(this instanceof arguments.callee)){
-            return new arguments.callee(Array.prototype.slice.call(arguments));
-        }
-        var name = arguments[0];
-        _$rapyd$_unbindAll(this, true);
-        this.greet = _$rapyd$_bind(this.greet, this);
-        self.name = name;
-    };
-    Human.prototype.greet = function(){
-        var self = this;
-        return "Hello, I'm " + self.name;
-    };
-    Human.getTypicalWeight = function(){
-        return "150";
-    };
-
-    function Friend() {
-        if (!(this instanceof arguments.callee)){
-            return new arguments.callee(Array.prototype.slice.call(arguments));
-        }
-        this.greet = _$rapyd$_bind(this.greet, this);
-        this.nickname = _$rapyd$_bind(this.nickname, this);
-        Human.prototype.constructor.apply(this, arguments);
-    }
-    Friend.prototype = new Human();
-    Friend.prototype.constructor = Friend;
-    _$rapyd$_unbindAll(Friend.prototype);
-    Friend.prototype.greet = function(){
-        var self = this;
-        return "Yo, it's me, " + self.name;
-    };
-    Friend.prototype.nickname = function(name){
-        var self = this;
-        self.name = name;
-    };
-
-    function OldFriend(){
-        var self = this;
-        if (!(this instanceof arguments.callee)){
-//            return new arguments.callee(name, duration);
-            return new arguments.callee(Array.prototype.slice.call(arguments));
-        }
-        var name = arguments[0];
-        var duration = arguments[1];
-        _$rapyd$_unbindAll(this, true);
-        this.how_long = _$rapyd$_bind(this.how_long, this);
-        this.get_bound_method = _$rapyd$_bind(this.get_bound_method, this);
-        self.duration = duration;
-        Friend.prototype.constructor.call(self, name);
-    };
-    OldFriend.prototype = new Friend();
-    OldFriend.prototype.constructor = OldFriend;
-    _$rapyd$_unbindAll(OldFriend.prototype);
-    OldFriend.prototype.how_long = function(){
-        var self = this;
-        return "I've known you for " + self.duration + " years";
-    };
-    OldFriend.prototype.get_bound_method = function(){
-        var self = this;
-        return self.how_long;
-    };
-
-    bob = Human("Bob");
-
-    assert.equal(bob.greet(), "Hello, I'm Bob");
-
-    assert.equal(Human.prototype.greet.call(bob), "Hello, I'm Bob");
-
-    assert.equal(Human.getTypicalWeight(), "150");
-
-    joe = Friend("Joe");
-
-    assert.equal(joe.greet(), "Yo, it's me, Joe");
-
-    assert.ok(joe instanceof Friend);
-
-    assert.ok(joe instanceof Human);
-
-    angela = OldFriend("Angela", 8);
-
-    assert.equal(angela.greet(), "Yo, it's me, Angela");
-
-    assert.equal(angela.how_long(), "I've known you for 8 years");
-
-    bound = angela.get_bound_method();
-
-    assert.equal(bound(), angela.how_long());
-
-    angela.nickname("Angie");
-
-    assert.equal(angela.greet(), "Yo, it's me, Angie");
-
-    (function module() {
-        function Stranger() {
-            if (!(this instanceof arguments.callee)){
-                return new arguments.callee(Array.prototype.slice.call(arguments));
-            }
-            this.greet = _$rapyd$_bind(this.greet, this);
-            Human.prototype.constructor.apply(this, arguments);
-        }
-        Stranger.prototype = new Human();
-        Stranger.prototype.constructor = Stranger;
-        _$rapyd$_unbindAll(Stranger.prototype);
-        Stranger.prototype.greet = function(){
-            var self = this;
-            return Friend.prototype.greet.call(self);
-        };
-        dude = Stranger("some guy");
-    })();
-
-    assert.equal(dude.greet(), "Yo, it's me, some guy");
-
-    assert.throws(function() {
-        Friend("another friend");
-        Stranger("another guy");
-    }, /Stranger is not defined/);
-
-    assert.ok(hasattr(dude, "greet"));
-
-    assert.equal(getattr(dude, "greet")(), "Yo, it's me, some guy");
-
-    assert.equal(hasattr(dude, "stuff"), false);
-
-    setattr(dude, "stuff", true);
-
-    assert.ok(hasattr(dude, "stuff"));
-
-    st = String("test");
-
-    assert.equal(st, "test");
-
-    assert.equal(st.toUpperCase(), "TEST");
-
-    assert.equal(String.prototype.toUpperCase.call(st), "TEST");
-
-    assert.equal(String.fromCharCode(65), "A");
-
-    function Counter(n){
-        var s = this;
-        if (!(this instanceof arguments.callee)){
-            return new arguments.callee(n);
-//            return new arguments.callee(Array.prototype.slice.call(arguments));
-        }
-        if (typeof n === "undefined") n = 0;
-        _$rapyd$_unbindAll(this, true);
-        this.getIncrementer = _$rapyd$_bind(this.getIncrementer, this);
-        s.count = n;
-    };
-    Counter.prototype.getIncrementer = function(){
-        var self = this;
-        return function() {
-            self.count += 1;
-        };
-    };
-
-    c = Counter(5);
-
-    inc = c.getIncrementer();
-
-    inc();
-
-    assert.equal(c.count, 6);
-
-    function negate(fn) {
-        function wrapped() {
-            var args = [].slice.call(arguments, 0);
-            return -fn.apply(this, [].concat(args));
-        }
-        return wrapped;
-    }
-
-    function add_pi(cls) {
-        cls.prototype.pi = 3.14;
-        return cls;
-    }
-
-    
-
-    function Math() {
-        if (!(this instanceof arguments.callee)){
-            return new arguments.callee(Array.prototype.slice.call(arguments));
-        }
-        this.sum = _$rapyd$_bind(this.sum, this);
-        this.concatSum = _$rapyd$_bind(this.concatSum, this);
-        this.plus = _$rapyd$_bind(this.plus, this);
-    }
-    Math.prototype.sum = function(){
-        var s = this;
-        var args = [].slice.call(arguments, 0);
-        var ttl, ttl, i;
-        ttl = 0;
-        var _$rapyd$_Iter0 = args;
-        for (var _$rapyd$_Index0 = 0; _$rapyd$_Index0 < _$rapyd$_Iter0.length; _$rapyd$_Index0++) {
-            i = _$rapyd$_Iter0[_$rapyd$_Index0];
-            ttl += i;
-        }
-        return ttl;
-    };
-    Math.prototype.concatSum = function(){
-        var s = this;
-        var string = arguments[0];
-        var nums = [].slice.call(arguments, 1);
-        return string + s.sum.apply(s, [].concat(nums));
-    };
-    Math.prototype.plus = function(a, b){
-        var s = this;
-        return a + b;
-    };
-    Math.prototype.plus = negate(Math.prototype.plus);
-    Math = add_pi(Math);
-
-    m = Math();
-
-    assert.equal(m.sum(1, 2, 3), 6);
-
-    assert.equal(m.sum.apply(m, [1].concat([ 2, 3 ])), 6);
-
-    assert.equal(m.concatSum("foo", 1, 2, 5), "foo8");
-
-    assert.equal(m.plus(2, 5), -7);
-
-    assert.equal(m.pi, 3.14);
-})();
 });
 
 var AST_TupleUnpack = DEFNODE("TupleUnpack", "elements right", {
-    $documentation: "An array literal",
+    $documentation: "An object used to represent tuple unpacking",
     $propdoc: {
         elements: "[AST_Node*] array of elements being assigned to",
         right: "[AST_Node] right-hand side expression"
+function abs(n) {
+    return Math.abs(n);
+}
 function enumerate(item) {
     var arr = [];
     for (var i = 0; i < item.length; i++) {
     ret.orig = fn;
     return ret;
 };
-function _$rapyd$_unbindAll(thisArg, rebind) {
+function _$rapyd$_rebindAll(thisArg, rebind) {
     for (var p in thisArg) {
         if (thisArg[p] && thisArg[p].orig) {
             if (rebind) thisArg[p] = _$rapyd$_bind(thisArg[p], thisArg);
 
         // --- actual lib-creating logic ---
         var lib = {
+            "abs": function(){
+                //function abs(n){
+                //  return Math.abs(n);
+                //}
+                return func_gen("abs", {
+                    args: ['n'],
+                    body: [
+                        ['return', 'Math.abs', {call: [{sequence: ['n']}]}]
+                    ]
+                });
+            },
             "bind": function(){
                 //function _$rapyd$_bind(fn, thisArg){
                 //  if (fn.orig) fn = fn.orig;
                     if (opt && (opt.operator == "=") && !(opt.right instanceof AST_Scope))
                         vars = vars.concat(scan_for_local_vars(opt.right, is_module));
                 });
+
                 // pick up iterators from loops
                 if (!is_module && body[stmt] instanceof AST_ForIn) {
 //                    vars.push("_$rapyd$_Iter");
-                    if (body[stmt].init instanceof AST_Array)
+                    if (body[stmt].init instanceof AST_Array) {
+                        vars.push('_$rapyd$_Unpack');
                         body[stmt].init.elements.forEach(function(elem){
                             if (vars.indexOf(elem.name) == -1) vars.push(elem.name);
                         });
-                    else if (vars.indexOf(body[stmt].init.name) == -1)
+                    } else if (vars.indexOf(body[stmt].init.name) == -1)
                         vars.push(body[stmt].init.name);
                 }
             }
             if (body.alternative)
                 vars = vars.concat(scan_for_local_vars(body.alternative, is_module));
         } else if (body instanceof AST_Assign) {
-            if (body.left instanceof AST_Array)
+            if (body.left instanceof AST_Array) {
+                vars.push('_$rapyd$_Unpack');
                 body.left.elements.forEach(function(elem){
-                    if (vars.indexOf(elem.name) == -1) vars.push(elem.name);
+                    if (!(elem instanceof AST_PropAccess) && vars.indexOf(elem.name) == -1) vars.push(elem.name);
                 });
-            else if (body.left.name && vars.indexOf(body.left.name) == -1)
+            } else if (body.left.name && vars.indexOf(body.left.name) == -1)
                 vars.push(body.left.name);
         }
         return vars;
             parent: (function(){
                 if (is("punc", "(")) {
                     next();
-                    var a = as_symbol(AST_SymbolFunarg);
+                    var a = expr_atom(false);
                     expect(")");
                     return a;
                 } else {
                     }), true);
                 } else if (expr instanceof AST_SymbolRef) {
                     switch (expr.name) {
+                        case "abs":
                         case "enumerate":
                         case "len":
                         case "print":
   "description": "RapydScript to JavaScript compiler",
   "homepage": "http://rapydscript.pyjeon.com",
   "main": "tools/node.js",
-  "version": "0.1.8",
+  "version": "0.1.9",
   "engines": {
     "node": ">=0.4.0"
   },
+###########################################################
+# RapydScript Standard Library
+# Author: Alexander Tsepkov
+# Copyright 2013 Pyjeon Software LLC
+# License: Apache License    2.0
+# This library is covered under Apache license, so that
+# you can distribute it with your RapydScript applications.
+###########################################################
+
+
+# basic implementation of Python's 'math' library
+
+# NOTE: this is only meant to aid those porting lots of Python code into RapydScript,
+# if you're writing a new RapydScript application, in most cases you probably want to
+# use JavaScript's Math module directly instead
+
+
+import stdlib
+
+
+module math:
+    pi = Math.PI
+    e = Math.E
+
+    ########################################
+    # Number-theoretic and representation functions
+    ########################################
+    def ceil(x):
+        return Math.ceil(x)
+    def copysign(x, y):
+        x = Math.abs(x)
+        if y < 0:
+            return -x
+        else:
+            return x
+    def fabs(x):
+        return Math.abs(x)
+    def factorial(x):
+        if Math.abs(int(x)) != x:
+            raise ValueError("factorial() only accepts integral values")
+        factorial.cache = []
+        r = def(n):
+            if n == 0 or n == 1:
+                return 1
+            if not factorial.cache[n]:
+                factorial.cache[n] = r(n-1) * n
+            return factorial.cache[n]
+        return r(x)
+    def floor(x):
+        return Math.floor(x)
+    def fmod(x, y):
+        # javascript's % operator isn't consistent with C fmod implementation, this function is
+        while y <= x:
+            x -= y
+        return x
+    def fsum(iterable):
+        # like Python's fsum, this method is much more resilient to rounding errors than regular sum
+        partials = []   # sorted, non-overlapping partial sums
+        for x in iterable:
+            i = 0
+            for y in partials:
+                if Math.abs(x) < Math.abs(y):
+                    x, y = y, x
+                hi = x + y
+                lo = y - (hi - x)
+                if lo:
+                    partials[i] = lo
+                    i += 1
+                x = hi
+            #partials[i:] = [x]
+            partials.splice(i, partials.length-i, x)
+        return sum(partials)
+    def isinf(x):
+        return not isFinite(x)
+    def isnan(x):
+        return isNaN(x)
+    def modf(x):
+        m = fmod(x, 1)
+        return m, x-m
+    def trunc(x):
+        return x | 0
+
+    ########################################
+    # Power and logarithmic functions
+    ########################################
+    def exp(x):
+        return Math.exp(x)
+    def expm1(x):
+        # NOTE: Math.expm1() is currently only implemented in Firefox, this provides alternative implementation
+        # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/expm1
+        #return Math.expm1(x)
+        if Math.abs(x) < 1e-5:
+            return x + 0.5*x*x
+        else:
+            return Math.exp(x) - 1
+    def log(x, base=e):
+        return Math.log(x)/Math.log(base)
+    def log1p(x):
+        # NOTE: Math.log1p() is currently only implemented in Firefox, this provides alternative implementation
+        # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log1p
+        # this version has been taken from http://phpjs.org/functions/log1p/
+        # admittedly it's not as accurate as MDN version, as you can see from math.log1p(1) result
+        ret = 0
+        n = 50
+        if x <= -1:
+            return Number.NEGATIVE_INFINITY
+        if x < 0 or x > 1:
+            return Math.log(1 + x)
+        for i in range(1, n):
+            if i % 2 == 0:
+                ret -= Math.pow(x, i) / i
+            else:
+                ret += Math.pow(x, i) / i
+        return ret
+    def log10(x):
+        # NOTE: Math.log10() is currently only implemented in Firefox, this provides alternative implementation
+        # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log10
+        # I didn't find a more accurate algorithm so I'm using the basic implementation
+        return Math.log(x)/Math.LN10
+    def pow(x, y):
+        if x < 0 and int(y) != y:
+            raise ValueError('math domain error')
+        if isnan(y) and x == 1:
+            return 1
+        return Math.pow(x, y)
+    def sqrt(x):
+        return Math.sqrt(x)
+
+    ########################################
+    # Trigonometric functions
+    ########################################
+    def acos(x):        return Math.acos(x)
+    def asin(x):        return Math.asin(x)
+    def atan(x):        return Math.atan(x)
+    def atan2(y, x):    return Math.atan2(y, x)
+    def cos(x):         return Math.cos(x)
+    def sin(x):         return Math.sin(x)
+    def hypot(x, y):    return Math.sqrt(x*x + y*y)
+    def tan(x):         return Math.tan(x)
+
+    ########################################
+    # Angular conversion
+    ########################################
+    def degrees(x):     return x*180/pi;
+    def radians(x):     return x*pi/180
+
+    ########################################
+    # Hyperbolic functions
+    ########################################
+    def acosh(x):
+        # NOTE: will be replaced with official, when it becomes mainstream
+        # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/acosh
+        return Math.log(x + Math.sqrt(x*x - 1))
+    def asinh(x):
+        # NOTE: will be replaced with official, when it becomes mainstream
+        # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/asinh
+        return Math.log(x + Math.sqrt(x*x + 1))
+    def atanh(x):
+        # NOTE: will be replaced with official, when it becomes mainstream
+        # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atanh
+        return 0.5 * Math.log((1 + x) / (1 - x))
+    def cosh(x):
+        # NOTE: will be replaced with official, when it becomes mainstream
+        # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cosh
+        return (Math.exp(x) + Math.exp(-x)) / 2
+    def sinh(x):
+        # NOTE: will be replaced with official, when it becomes mainstream
+        # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sinh
+        return (Math.exp(x) - Math.exp(-x)) / 2
+    def tanh(x):
+        # NOTE: will be replaced with official, when it becomes mainstream
+        # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/tanh
+        return (Math.exp(x) - Math.exp(-x)) / (Math.exp(x) + Math.exp(-x))
+
+
+
+#console.log(math.ceil(4.2))
+#console.log(math.floor(4.2))
+#console.log(math.fabs(-6))
+#console.log(math.copysign(-5, 7))
+#console.log(math.factorial(4))
+#console.log(math.fmod(-1e100, 1e100))
+#
+#d = [0.9999999, 1, 2, 3]
+#console.log(sum(d), math.fsum(d))
+#console.log(math.isinf(5), math.isinf(Infinity))
+#console.log(math.modf(5.5))
+#console.log(math.trunc(2.6), math.trunc(-2.6))
+#console.log(math.exp(1e-5), math.expm1(1e-5))
+#console.log(math.log(10), math.log(10, 1000))
+#console.log(math.log1p(1e-15), math.log1p(1))
+#console.log(math.log10(1000), math.log(1000, 10))
+#console.log(math.pow(1, 0), math.pow(1, NaN), math.pow(0, 0), math.pow(NaN, 0), math.pow(4,3), math.pow(100, -2))
+#console.log(math.hypot(3,4))
+#console.log(math.acosh(2), math.asinh(1), math.atanh(0.5), math.cosh(1), math.cosh(-1), math.sinh(1), math.tanh(1))
+###########################################################
+# RapydScript Standard Library
+# Author: Alexander Tsepkov
+# Copyright 2013 Pyjeon Software LLC
+# License: Apache License    2.0
+# This library is covered under Apache license, so that
+# you can distribute it with your RapydScript applications.
+###########################################################
+
+
+# basic implementation of Python's 'random' library
+
+# JavaScript's Math.random() does not allow seeding its random generator, to bypass that, this module implements its own
+# version that can be seeded. I decided on RC4 algorithm for this.
+module random:
+
+    # please don't mess with this from the outside
+    _$rapyd$_seed_state = {
+        key: [],
+        key_i: 0,
+        key_j: 0
+    }
+    _$rapyd$_get_random_byte = def():
+        _$rapyd$_seed_state.key_i = (_$rapyd$_seed_state.key_i + 1) % 256
+        _$rapyd$_seed_state.key_j = (_$rapyd$_seed_state.key_j + _$rapyd$_seed_state.key[_$rapyd$_seed_state.key_i]) % 256
+        _$rapyd$_seed_state.key[_$rapyd$_seed_state.key_i], _$rapyd$_seed_state.key[_$rapyd$_seed_state.key_j] = \
+                _$rapyd$_seed_state.key[_$rapyd$_seed_state.key_j], _$rapyd$_seed_state.key[_$rapyd$_seed_state.key_i]
+        return _$rapyd$_seed_state.key[(_$rapyd$_seed_state.key[_$rapyd$_seed_state.key_i] + \
+                _$rapyd$_seed_state.key[_$rapyd$_seed_state.key_j]) % 256]
+
+    def seed(x=Date().getTime()):
+        if type(x) is 'number':
+            x = x.toString()
+        elif type(x) is not 'string':
+            raise TypeError("unhashable type: '" + type(x) + "'")
+        for i in range(256):
+            _$rapyd$_seed_state.key[i] = i
+        j = 0
+        for i in range(256):
+            j = (j + _$rapyd$_seed_state.key[i] + x.charCodeAt(i % x.length)) % 256
+            _$rapyd$_seed_state.key[i], _$rapyd$_seed_state.key[j] = _$rapyd$_seed_state.key[j], _$rapyd$_seed_state.key[i]
+    seed()
+
+    def random():
+        n = 0
+        m = 1
+        for i in range(8):
+            n += _$rapyd$_get_random_byte() * m
+            m *= 256
+        return n / 18446744073709551616
+
+    # unlike the python version, this DOES build a range object, feel free to reimplement
+    def randrange():
+        return choice(range.apply(this, arguments))
+
+    def randint(a, b):
+        return int(random()*(b-a+1) + a)
+
+    def uniform(a, b):
+        return random()*(b-a) + a
+
+    def choice(seq):
+        if seq.length > 0:
+            return seq[Math.floor(random()*seq.length)]
+        else:
+            raise IndexError()
+
+    # uses Fisher-Yates algorithm to shuffle an array
+    def shuffle(x, random_f=random):
+        for i in range(x.length):
+            j = Math.floor(random_f() * (i+1))
+            x[i], x[j] = x[j], x[i]
+        return x
+
+    # similar to shuffle, but only shuffles a subset and creates a copy
+    def sample(population, k):
+        x = population.slice()
+        for i in range(population.length-1, population.length-k-1, -1):
+            j = Math.floor(random() * (i+1))
+            x[i], x[j] = x[j], x[i]
+        return x.slice(population.length-k)
+
+
+#a = range(50)
+#random.seed(5)
+#console.log(random.choice(a))
+#console.log(random.shuffle(a))
+#console.log(random.randrange(10))
+#console.log(random.randint(1,5))
+#console.log(random.uniform(1,5))
+#console.log(random.sample(range(20),5))
+###########################################################
+# RapydScript Standard Library
+# Author: Alexander Tsepkov
+# Copyright 2013 Pyjeon Software LLC
+# License: Apache License    2.0
+# This library is covered under Apache license, so that
+# you can distribute it with your RapydScript applications.
+###########################################################
+
+
+# basic implementation of Python's 're' library
+
+# NOTE: this is only meant to aid those porting lots of Python code into RapydScript,
+# if you're writing a new RapydScript application, in most cases you probably want to
+# use JavaScript's native RegExp object
+
+
+
+module re:
+    I = IGNORECASE = 1
+    M = MULTILINE = 2
+
+    # JavaScript doesn't really have a DOTALL-equivalent, I will hack around that by replacing dots with [\s\S]
+    D = DOTALL = 4
+
+    class MatchObject:
+        def __init__(self, regex, match):
+            self.re = regex
+            self.string = match.input
+            self._groups = match
+
+            # compute start/end for each group
+            self._start = []
+            self._end = []
+            offset = 0
+            remainder = match.input
+            i = 0
+            while type(match[i]) !== "undefined":
+                loc = remainder.search(match[i])
+                self._start.push(loc+offset)
+                self._end.push(loc+offset+match[i].length-1)
+                remainder = remainder[loc:]
+                i += 1
+
+        def groups(self):
+            return self._groups[:] # protect original
+
+        def group(self, g=0):
+            return self._groups[g]
+
+        def start(g=0):
+            return self._start[g]
+
+        def end(g=0):
+            return self._end[g]
+
+    class RegexObject(RegExp):
+        def __init__(self, pattern, flags):
+            if isinstance(pattern, RegexObject):
+                self.pattern = pattern.pattern
+                self.flags = pattern.flags | flags
+            else:
+                self.pattern = pattern # this isn't the real pattern, but rather the original string, for consistency with Python
+                self.flags = flags
+
+            modifiers = ''
+            if self.flags & IGNORECASE: modifiers += 'i'
+            if self.flags & MULTILINE: modifiers += 'm'
+            if self.flags & DOTALL:
+                pattern = pattern.replace(RegExp('\\.', 'g'), '[\\s\\S]')
+            self._modifiers = modifiers
+
+            # now create the real pattern
+            self._pattern = RegExp(pattern, modifiers)
+
+        def search(self, string):
+            n = string.match(self._pattern)
+            if n is None:
+                return None
+            return MatchObject(self, n)
+
+        def match(self, string):
+            n = string.match(RegExp('^' + self.pattern, self._modifiers))
+            if n is None:
+                return None
+            return MatchObject(self, n)
+
+        def split(self, string, maxsplit=None):
+            if maxsplit is not None:
+                return string.split(self._pattern, maxsplit)
+            else:
+                return string.split(self._pattern)
+
+        def findall(self, string):
+            matches = string.match(RegExp(self.pattern, self._modifiers + 'g'))
+            i = 0
+            ret = []
+            while type(matches[i]) !== "undefined":
+                ret.push(matches[i]) # a hack to avoid including non-array like portions of regex match
+                i += 1
+            return ret
+
+        def sub(self, repl, string, count=0):
+            if count == 0:
+                return string.replace(RegExp(self.pattern, self._modifiers + 'g'), repl)
+
+            for i in range(count):
+                string = string.replace(self._pattern, repl)
+            return string
+
+        def subn(self, repl, string, count=0):
+            n = 0
+            if count == 0:
+                count = Number.MAX_VALUE
+
+            new_string = string
+            do:
+                string = new_string
+                new_string = string.replace(self._pattern, repl)
+                if new_string != string:
+                    n += 1
+                    count -= 1
+            .while new_string != string and count > 0
+
+            return string, n
+
+    def compile(pattern, flags=0):
+        return RegexObject(pattern, flags)
+
+    def search(pattern, string, flags=0):
+        return RegexObject(pattern, flags).search(string)
+
+    def match(pattern, string, flags=0):
+        return RegexObject(pattern, flags).match(string)
+
+    def split(pattern, string, maxsplit=0, flags=0):
+        return RegexObject(pattern, flags).split(string)
+
+    def findall(pattern, string, flags=0):
+        return RegexObject(pattern, flags).findall(string)
+
+    def sub(pattern, repl, string, count=0, flags=0):
+        return RegexObject(pattern, flags).sub(repl, string, count)
+
+    def subn(pattern, repl, string, count=0, flags=0):
+        return RegexObject(pattern, flags).subn(repl, string, count)
+
+
+
+
+#a = re.compile('test.*one', re.I + re.M + re.D)
+#console.log(a)
+#s = "Isaac Newton, physicist"
+#c = re.search("(\\w+) (\\w+)", s)
+#console.log(c)
+#c = re.match("(\\w+) (\\w+)", s)
+#console.log(c)
+#console.log(re.split('\\s', s))
+#console.log(re.findall('s[a-z]', s))
+#console.log(re.sub('[A-Z]', '_', s))
+#console.log(re.subn('[A-Z]', '_', s))
 # RapydScript Standard Library
 # Author: Alexander Tsepkov
 # Copyright 2013 Pyjeon Software LLC
-# License: Apache License	2.0
+# License: Apache License    2.0
 # This library is covered under Apache license, so that
 # you can distribute it with your RapydScript applications.
 ###########################################################
 
 
-###########################################################
-# Basic Functionality
-###########################################################
-
-JSON = JSON or {}
-
-# implement JSON.stringify in older browsers, if doesn't already exist
-if not JSON.stringify:
-	JS("""
-	JSON.stringify = function(obj) {
-		var t = typeof (obj);
-		if (t != "object" || obj === null) {
-			// simple data type
-			if (t == "string")
-				obj = '"' + obj + '"';
-			if (t == "function")
-				return; // return undefined
-			else
-				return String(obj);
-		} else {
-			// recurse array or object
-			var n, v, json = []
-			var arr = (obj && obj.constructor == Array);
-			for (n in obj) {
-				v = obj[n];
-				t = typeof (v);
-				if (t != "function" && t != "undefined") {
-					if (t == "string")
-						v = '"' + v + '"';
-					else if ((t == "object" || t == "function") && v !== null)
-						v = JSON.stringify(v);
-					json.push((arr ? "" : '"' + n + '":') + String(v));
-				}
-			}
-			return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
-		}
-	};
-	""")
-
-# Pythonic shortcut for converting an object to string
-str = JSON.stringify
-
-
-###########################################################
-# Errors
-###########################################################
-class ValueError(Error):
-	def __init__(self, message):
-		self.name = "ValueError"
-		self.message = message
+import stdlib_common
 
 
 ###########################################################
 String.prototype.lstrip = String.prototype.trimLeft
 String.prototype.rstrip = String.prototype.trimRight
 String.prototype.join = def(iterable):
-	return iterable.join(this)
+    return iterable.join(this)
 String.prototype.zfill = def(size):
-	s = this
-	while s.length < size:
-		s = "0" + s
-	return s
+    s = this
+    while s.length < size:
+        s = "0" + s
+    return s
 
 
 ###########################################################
 # Array Methods
 ###########################################################
 def list(iterable=[]):
-	result = []
-	for i in iterable:
-		result.append(i)
-	return result
+    result = []
+    for i in iterable:
+        result.append(i)
+    return result
 Array.prototype.append = Array.prototype.push
 Array.prototype.find = Array.prototype.indexOf
 Array.prototype.index = def(index):
-	val = this.find(index)
-	if val == -1:
-		raise ValueError(str(index) + " is not in list")
-	return val
+    val = this.find(index)
+    if val == -1:
+        raise ValueError(str(index) + " is not in list")
+    return val
 Array.prototype.insert = def(index, item):
-	this.splice(index, 0, item)
+    this.splice(index, 0, item)
 Array.prototype.pop = def(index=this.length-1):
-	return this.splice(index, 1)[0]
+    return this.splice(index, 1)[0]
 Array.prototype.extend = def(array2):
-	this.push.apply(this, array2)
+    this.push.apply(this, array2)
 Array.prototype.remove = def(item):
-	index = this.find(item)
-	this.splice(index, 1)
+    index = this.find(item)
+    this.splice(index, 1)
 Array.prototype.copy = def():
-	return this.slice(0)
-if not Array.prototype.map:
-	# declare map() method for older browsers
-	JS("""
-	Array.prototype.map = function(callback, thisArg) {
-		var T, A, k;
-		if (this == null) {
-			throw new TypeError(" this is null or not defined");
-		}
-		var O = Object(this);
-		var len = O.length >>> 0;
-		if ({}.toString.call(callback) != "[object Function]") {
-			throw new TypeError(callback + " is not a function");
-		}
-		if (thisArg) {
-			T = thisArg;
-		}
-		A = new Array(len);
-		for (var k = 0; k < len; k++) {
-			var kValue, mappedValue;
-			if (k in O) {
-				kValue = O[k];
-				mappedValue = callback.call(T, kValue);
-				A[k] = mappedValue;
-			}
-		}
-		return A;
-	};
-	""")
-def map(oper, arr):
-	return arr.map(oper)
-if not Array.prototype.filter:
-	# declare filter() method for older browsers
-	JS("""
-	Array.prototype.filter = function(filterfun, thisArg) {
-		"use strict";
-		if (this == null) {
-			throw new TypeError(" this is null or not defined");
-		}
-		var O = Object(this);
-		var len = O.length >>> 0;
-		if ({}.toString.call(filterfun) != "[object Function]") {
-			throw new TypeError(filterfun + " is not a function");
-		}
-		if (thisArg) {
-			T = thisArg;
-		}
-		var A = [];
-		var thisp = arguments[1];
-		for (var k = 0; k < len; k++) {
-			if (k in O) {
-				var val = O[k]; // in case fun mutates this
-				if (filterfun.call(T, val))
-					A.push(val);
-			}
-		}
-		return A;
-	};
-	""")
-def filter(oper, arr):
-	return arr.filter(oper)
+    return this.slice(0)
 
 
 ###########################################################
 # dict (this is a bit of a hack for now, to avoid overwriting the Object)
 # the methods below must be used via dict.method(object) instead of object.method()
 def dict(iterable):
-	result = {}
-	for key in iterable:
-		result[key] = iterable[key]
-	return result
+    result = {}
+    for key in iterable:
+        result[key] = iterable[key]
+    return result
 
 if type(Object.getOwnPropertyNames) is not "function":
-	# IE and older browsers
-	dict.keys = def(hash):
-		keys = []
+    # IE and older browsers
+    dict.keys = def(hash):
+        keys = []
 
-		# Use a standard for in loop
-		JS("""
-		for (var x in hash) {
-			if (hash.hasOwnProperty(x)) {
-				keys.push(x);
-			}
-		}
-		""")
-		return keys
+        # Use a standard for in loop
+        JS("""
+        for (var x in hash) {
+            if (hash.hasOwnProperty(x)) {
+                keys.push(x);
+            }
+        }
+        """)
+        return keys
 else:
-	# normal browsers
-	dict.keys = def(hash):
-		return Object.getOwnPropertyNames(hash)
+    # normal browsers
+    dict.keys = def(hash):
+        return Object.getOwnPropertyNames(hash)
 
 dict.values = def(hash):
-	vals = []
-	for key in dict.keys(hash):
-		vals.append(hash[key])
-	return vals
+    vals = []
+    for key in dict.keys(hash):
+        vals.append(hash[key])
+    return vals
 
 dict.items = def(hash):
-	items = []
-	for key in dict.keys(hash):
-		items.append((key, hash[key]))
-	return items
+    items = []
+    for key in dict.keys(hash):
+        items.append((key, hash[key]))
+    return items
 
 dict.copy = dict
 
 dict.clear = def(hash):
-	for key in dict.keys(hash):
-		del hash[key]
+    for key in dict.keys(hash):
+        del hash[key]
 ###########################################################
 
 
-###########################################################
-# Basic Functionality
-###########################################################
-
-JSON = JSON or {}
-
-# implement JSON.stringify in older browsers, if doesn't already exist
-if not JSON.stringify:
-	JS("""
-	JSON.stringify = function(obj) {
-		var t = typeof (obj);
-		if (t != "object" || obj === null) {
-			// simple data type
-			if (t == "string")
-				obj = '"' + obj + '"';
-			if (t == "function")
-				return; // return undefined
-			else
-				return String(obj);
-		} else {
-			// recurse array or object
-			var n, v, json = []
-			var arr = (obj && obj.constructor == Array);
-			for (n in obj) {
-				v = obj[n];
-				t = typeof (v);
-				if (t != "function" && t != "undefined") {
-					if (t == "string")
-						v = '"' + v + '"';
-					else if ((t == "object" || t == "function") && v !== null)
-						v = JSON.stringify(v);
-					json.push((arr ? "" : '"' + n + '":') + String(v));
-				}
-			}
-			return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
-		}
-	};
-	""")
-
-
-###########################################################
-# Errors
-###########################################################
-class ValueError(Error):
-	def __init__(self, message):
-		self.name = "ValueError"
-		self.message = message
+import stdlib_common
 
 
 ###########################################################
 		# this is a bit of a hack now, stringify doesn't return correct array representation
 		return '[' + self + ']'
 
-if not Array.prototype.map:
-	# declare map() method for older browsers
-	JS("""
-	Array.prototype.map = function(callback, thisArg) {
-		var T, A, k;
-		if (this == null) {
-			throw new TypeError(" this is null or not defined");
-		}
-		var O = Object(this);
-		var len = O.length >>> 0;
-		if ({}.toString.call(callback) != "[object Function]") {
-			throw new TypeError(callback + " is not a function");
-		}
-		if (thisArg) {
-			T = thisArg;
-		}
-		A = new Array(len);
-		for (var k = 0; k < len; k++) {
-			var kValue, mappedValue;
-			if (k in O) {
-				kValue = O[k];
-				mappedValue = callback.call(T, kValue);
-				A[k] = mappedValue;
-			}
-		}
-		return A;
-	};
-	""")
-def map(oper, arr):
-	return list(arr.map(oper))
-
-if not Array.prototype.filter:
-	# declare filter() method for older browsers
-	JS("""
-	Array.prototype.filter = function(filterfun, thisArg) {
-		"use strict";
-		if (this == null) {
-			throw new TypeError(" this is null or not defined");
-		}
-		var O = Object(this);
-		var len = O.length >>> 0;
-		if ({}.toString.call(filterfun) != "[object Function]") {
-			throw new TypeError(filterfun + " is not a function");
-		}
-		if (thisArg) {
-			T = thisArg;
-		}
-		var A = [];
-		var thisp = arguments[1];
-		for (var k = 0; k < len; k++) {
-			if (k in O) {
-				var val = O[k]; // in case fun mutates this
-				if (filterfun.call(T, val))
-					A.push(val);
-			}
-		}
-		return A;
-	};
-	""")
-def filter(oper, arr):
-	return list(arr.filter(oper))
-
 
 ###########################################################
 # Python dict object

src/stdlib_common.pyj

+###########################################################
+# RapydScript Standard Library
+# Author: Alexander Tsepkov
+# Copyright 2013 Pyjeon Software LLC
+# License: Apache License    2.0
+# This library is covered under Apache license, so that
+# you can distribute it with your RapydScript applications.
+###########################################################
+
+
+###########################################################
+# Basic Functionality
+###########################################################
+JSON = JSON or {}
+
+# implement JSON.stringify in older browsers, if doesn't already exist
+if not JSON.stringify:
+    JS("""
+    JSON.stringify = function(obj) {
+        var t = typeof (obj);
+        if (t != "object" || obj === null) {
+            // simple data type
+            if (t == "string")
+                obj = '"' + obj + '"';
+            if (t == "function")
+                return; // return undefined
+            else
+                return String(obj);
+        } else {
+            // recurse array or object
+            var n, v, json = []
+            var arr = (obj && obj.constructor == Array);
+            for (n in obj) {
+                v = obj[n];
+                t = typeof (v);
+                if (t != "function" && t != "undefined") {
+                    if (t == "string")
+                        v = '"' + v + '"';
+                    else if ((t == "object" || t == "function") && v !== null)
+                        v = JSON.stringify(v);
+                    json.push((arr ? "" : '"' + n + '":') + String(v));
+                }
+            }
+            return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
+        }
+    };
+    """)
+
+# Pythonic shortcut for converting an object to string
+str = JSON.stringify
+
+
+
+###########################################################
+# Errors
+###########################################################
+class IndexError(Error):
+    def __init__(self, message="list index out of range"):
+        self.name = "IndexError"
+        self.message = message
+
+class TypeError(Error):
+    def __init__(self, message):
+        self.name = "TypeError"
+        self.message = message
+
+class ValueError(Error):
+    def __init__(self, message):
+        self.name = "ValueError"
+        self.message = message
+
+class AssertionError(Error):
+    def __init__(self, message=""):
+        self.name = "AssertionError"
+        self.message = message
+
+
+###########################################################
+# Arrays
+###########################################################
+if not Array.prototype.map:
+	# declare map() method for older browsers
+	JS("""
+	Array.prototype.map = function(callback, thisArg) {
+		var T, A, k;
+		if (this == null) {
+			throw new TypeError(" this is null or not defined");
+		}
+		var O = Object(this);
+		var len = O.length >>> 0;
+		if ({}.toString.call(callback) != "[object Function]") {
+			throw new TypeError(callback + " is not a function");
+		}
+		if (thisArg) {
+			T = thisArg;
+		}
+		A = new Array(len);
+		for (var k = 0; k < len; k++) {
+			var kValue, mappedValue;
+			if (k in O) {
+				kValue = O[k];
+				mappedValue = callback.call(T, kValue);
+				A[k] = mappedValue;
+			}
+		}
+		return A;
+	};
+	""")
+def map(oper, arr):
+	return list(arr.map(oper))
+
+if not Array.prototype.filter:
+	# declare filter() method for older browsers
+	JS("""
+	Array.prototype.filter = function(filterfun, thisArg) {
+		"use strict";
+		if (this == null) {
+			throw new TypeError(" this is null or not defined");
+		}
+		var O = Object(this);
+		var len = O.length >>> 0;
+		if ({}.toString.call(filterfun) != "[object Function]") {
+			throw new TypeError(filterfun + " is not a function");
+		}
+		if (thisArg) {
+			T = thisArg;
+		}
+		var A = [];
+		var thisp = arguments[1];
+		for (var k = 0; k < len; k++) {
+			if (k in O) {
+				var val = O[k]; // in case fun mutates this
+				if (filterfun.call(T, val))
+					A.push(val);
+			}
+		}
+		return A;
+	};
+	""")
+def filter(oper, arr):
+	return list(arr.filter(oper))
+def sum(arr, start=0):
+    return arr.reduce(
+        def(prev, cur): return prev+cur;,
+        start
+    )
+
+
+###########################################################
+# Deep Equality Comparison
+###########################################################
+def deep_eq(a, b):
+    """
+    Equality comparison that works with all data types, returns true if structure and
+    contents of first object equal to those of second object
+
+    Arguments:
+        a: first object
+        b: second object
+    """
+    if a is b:
+        # simple object
+        return True
+
+    if (isinstance(a, Array) and isinstance(b, Array)) or (isinstance(a, Object) and isinstance(b, Object)):
+        # if length ot type doesn't match, they can't be equal
+        if a.constructor is not b.constructor or a.length is not b.length:
+            return False
+
+        # compare individual properties (order doesn't matter if it's a hash)
+        for i in dict.keys(a):
+            if b.hasOwnProperty(i):
+                # recursively test equality of object children
+                if not deep_eq(a[i], b[i]):
+                    return False
+            else:
+                return False
+        return True
+    return False
+###########################################################
+# RapydScript Standard Library
+# Author: Alexander Tsepkov
+# Copyright 2013 Pyjeon Software LLC
+# License: Apache License    2.0
+# This library is covered under Apache license, so that
+# you can distribute it with your RapydScript applications.
+###########################################################
+
+
+# basic implementation of Python's 'unittest' library
+
+
 import stdlib
 
-def deepEqual(a, b):
-	"""
-	Equality comparison that works with all data types, returns true if structure and
-	contents of first object equal to those of second object
 
-	Arguments:
-		a: first object
-		b: second object
-	"""
-	if a is b:
-		# simple object
-		return True
+module unittest:
 
-	if (isinstance(a, Array) and isinstance(b, Array)) or (isinstance(a, Object) and isinstance(b, Object)):
-		# if length ot type doesn't match, they can't be equal
-		if a.constructor is not b.constructor or a.length is not b.length:
-			return False
+    assert = def(result):
+        if not result:
+            raise AssertionError()
 
-		# compare individual properties (order doesn't matter if it's a hash)
-		for i in dict.keys(a):
-			if b.hasOwnProperty(i):
-				# recursively test equality of object children
-				if not deepEqual(a[i], b[i]):
-					return False
-			else:
-				return False
-		return True
-	return False
+    def main():
+        num_tests = 0
+        bad_tests = 0
+        overall = 'OK'
+        # NOTE: the timing mechanism is currently naive, this might change in the future if higher accuracy is needed
+        start_time = Date()
+        for object in Object.getOwnPropertyNames(global):
+            if global[object] and isinstance(global[object].prototype, TestCase):
+                obj = new global[object]()
+                for prop in Object.getOwnPropertyNames(obj):
+                    if prop[:4] == 'test':
+                        num_tests += 1
+                        # create a new instance of the test object for each case to ensure independence
+                        # TODO: make this case not require 'new' keyword in the future, it needs it because
+                        # compiler isn't smart enough to realize that global[object] == object
+                        new_obj = new global[object]()
+                        if type(new_obj.setUp) is 'function':
+                            new_obj.setUp()
+                        try:
+                            new_obj[prop]()
+                            result = 'ok'
+                        except AssertionError as e:
+                            result = 'FAIL'
+                            bad_tests += 1
+                        console.log(prop + ' (' + object + ') ... ' + result)
+                        if type(new_obj.tearDown) is 'function':
+                            new_obj.tearDown()
+        elapsed = (Date() - start_time)/1000
+        console.log('--------------------------------------------------------------')
+        console.log('Ran ' + str(num_tests) + ' tests in ' + elapsed + 's\n')
+        if bad_tests:
+            overall = 'FAILED (failures=' + str(bad_tests) + ')'
+        console.log(overall)
 
-class AssertionError(Error):
-	def __init__(self, message=""):
-		self.name = "AssertionError"
-		self.message = message
+    class TestCase:
+        def __init__(self):
+            pass
+        def assertEqual(self, a, b):
+            # this function is smart enough to correctly test equality even for arrays
+            assert(deep_eq(a, b))
+        def assertNotEqual(self, a, b):
+            # this function is smart enough to correctly test equality even for arrays
+            assert(not deep_eq(a, b))
+        def assertTrue(self, a):
+            assert(a)
+        def assertFalse(self, a):
+            assert(not a)
+        def assertAlmostEqual(self, a, b, precision):
+            epsilon = 1/Math.pow(10, precision)
+            assert(Math.abs(a-b) < epsilon)
+        def assertNotAlmostEqual(self, a, b, precision):
+            try:
+                self.assertAlmostEqual(a, b, precision)
+            except AssertionError:
+                return
+            raise AssertionError()
+        def assertRaises(self, exception, callable, *args):
+            try:
+                callable(*args)
+            except exception:
+                return
 
-assert = def(result):
-	if not result:
-		raise AssertionError()
 
-class _$rapyd$_TestCase:
-	def __init__(self):
-		pass
-	def assertEqual(self, a, b):
-		# this function is smart enough to correctly test equality even for arrays
-		assert(deepEqual(a, b))
-	def assertNotEqual(self, a, b):
-		# this function is smart enough to correctly test equality even for arrays
-		assert(not deepEqual(a, b))
-	def assertTrue(self, a):
-		assert(a)
-	def assertFalse(self, a):
-		assert(not a)
-	def assertAlmostEqual(self, a, b, precision):
-		epsilon = 1/Math.pow(10, precision)
-		assert(Math.abs(a-b) < epsilon)
-	def assertNotAlmostEqual(self, a, b, precision):
-		try:
-			self.assertAlmostEqual(a, b, precision)
-		except AssertionError:
-			return
-		raise AssertionError()
 
-def output(string):
-	console.log(string)
-
-unittest = {
-	main: def():
-		num_tests = 0
-		bad_tests = 0
-		overall = 'OK'
-		# NOTE: the timing mechanism is currently naive, this might change in the future if higher accuracy is needed
-		start_time = Date()
-		for object in global:
-			if isinstance(global[object].prototype, _$rapyd$_TestCase):
-				obj = new global[object]()
-				for prop in obj:
-					if prop[:4] == 'test':
-						num_tests += 1
-						# create a new instance of the test object for each case to ensure independence
-						# TODO: make this case not require 'new' keyword in the future, it needs it because
-						# compiler isn't smart enough to realize that global[object] == object
-						new_obj = new global[object]()
-						if type(new_obj.setUp) is 'function':
-							new_obj.setUp()
-						try:
-							new_obj[prop]()
-							result = 'ok'
-						except AssertionError as e:
-							result = 'FAIL'
-							bad_tests += 1
-						output(prop + ' (' + object + ') ... ' + result)
-						if type(new_obj.tearDown) is 'function':
-							new_obj.tearDown()
-		elapsed = (Date() - start_time)/1000
-		output('--------------------------------------------------------------')
-		output('Ran ' + str(num_tests) + ' in ' + elapsed + 's\n')
-		if bad_tests:
-			overall = 'FAILED (failures=' + str(bad_tests) + ')'
-		output(overall)
-	,
-	TestCase: _$rapyd$_TestCase
-}
+#import random
+#import unittest
+#
+#class TestSequenceFunctions(unittest.TestCase):
+#
+#    def setUp(self):
+#        self.seq = range(10)
+#
+#    def test_shuffle(self):
+#        # make sure the shuffled sequence does not lose any elements
+#        random.shuffle(self.seq)
+#        self.seq.sort()
+#        self.assertEqual(self.seq, range(10))
+#
+#        # should raise an exception for an immutable sequence
+#        self.assertRaises(TypeError, random.shuffle, (1,2,3))
+#
+#    def test_choice(self):
+#        element = random.choice(self.seq)
+#        self.assertTrue(element in self.seq)
+#
+#    def test_sample(self):
+#        self.assertRaises(ValueError, random.sample, (self.seq, 20))
+#        for element in random.sample(self.seq, 5):
+#            self.assertTrue(element in self.seq)
+#
+## there is no way to make this work without explicitly binding it to global scope
+#global.TestSequenceFunctions = TestSequenceFunctions
+#
+#unittest.main()