<commit_before>/**
  Copyright 2010-2011 Mateusz Paprocki <mattpap@gmail.com>
  Copyright 2011 Christian Iversen <ci@sikkerhed.org>

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
**/

/*
 * Bastardized javascript-python builtins. Will be moved in the future
 */
__builtins__.js_getattr = function(obj, name, value) {
    var val = obj[name];

    if (val !== undefined) {
        return val;
    } else {
        if (value !== undefined) {
            return value;
        } else {
            throw __builtins__.PY$AttributeError("Object " + js(str(obj)) + " does not have attribute " + name);
        }
    }
};

__builtins__.js_setattr = function(obj, name, value) {
    obj[name] = value;
};

/*
 * Python __builtins__
 */

__builtins__.PY$abs = $PY.c_nif;
__builtins__.PY$all = $PY.c_nif;
__builtins__.PY$any = $PY.c_nif;
__builtins__.PY$apply = $PY.c_nif;
__builtins__.PY$bin = $PY.c_nif;
__builtins__.PY$buffer = $PY.c_nif;
__builtins__.PY$bytearray = $PY.c_nif;
__builtins__.PY$bytes = $PY.c_nif;
__builtins__.PY$callable = $PY.c_nif;
__builtins__.PY$chr = $PY.c_nif;
__builtins__.PY$classmethod = $PY.c_nif;

__builtins__.PY$cmp = function(x, y) {
  return x.PY$__cmp__(y);
};

__builtins__.PY$coerce = $PY.c_nif;
__builtins__.PY$compile = $PY.c_nif;
__builtins__.PY$complex = $PY.c_nif;
__builtins__.PY$copyright = $PY.c_nif;
__builtins__.PY$credits = $PY.c_nif;

__builtins__.PY$delattr = function(obj, name) {
    name = js(name);
    if (obj["PY$" + name] !== undefined) {
        delete obj["PY$" + name];
    } else {
        throw __builtins__.PY$AttributeError("Object " + js(str(obj)) + " does not have attribute " + name);
    }
};

__builtins__.PY$dir = function(obj) {
    var res = list();
    for (var i in obj) {
        if (i.indexOf('PY$') === 0) {
            res.PY$append(__builtins__.PY$str(i.substr(3)));
        }
    }
    res.PY$sort();
    return res;
};

__builtins__.PY$divmod = $PY.c_nif;

__builtins__.PY$enumerate = function(obj) {
    if (arguments.length != 1) {
        throw __builtins__.PY$NotImplementedError("enumerate() only supports 1 argument");
    }
    var items = list();
    var count = 0;
    iterate(obj, function(elm) {
                items.PY$append(tuple([count++, elm]));
            });
    return items;
};

__builtins__.PY$eval = $PY.c_nif;
__builtins__.PY$execfile = $PY.c_nif;
__builtins__.PY$exit = $PY.c_nif;
__builtins__.PY$file = $PY.c_nif;

__builtins__.PY$filter = function(f, l) {
   var res = list();
   iterate(l, function(item) {
     if (f(item) === True) {
       res.PY$append(item);
     }
   });
   return res;
};

__builtins__.PY$format = $PY.c_nif;
__builtins__.PY$frozenset = $PY.c_nif;

__builtins__.PY$getattr = function(obj, name, value) {
    name = js(name);
    var val = obj["PY$" + name];

    if (val !== undefined) {
        return val;
    } else {
        if (value !== undefined) {
            return value;
        } else {
            throw __builtins__.PY$AttributeError("Object " + js(str(obj)) + " does not have attribute " + name);
        }
    }
};

__builtins__.PY$globals = $PY.c_nif;

__builtins__.PY$hasattr = function(obj, name) {
    name = js(name);
    return obj["PY$" + name] === undefined ? False : True;
};

__builtins__.PY$hash = function(obj) {
    if (obj.PY$__hash__ !== undefined) {
        return obj.PY$__hash__();
    } else if (typeof(obj) === 'number') {
        return obj === -1 ? -2 : obj;
    } else {
        throw __builtins__.PY$AttributeError('__hash__');
    }
};

__builtins__.PY$help = $PY.c_nif;
__builtins__.PY$hex = $PY.c_nif;
__builtins__.PY$id = $PY.c_nif;
__builtins__.PY$input = $PY.c_nif;
__builtins__.PY$intern = $PY.c_nif;

__builtins__.PY$isinstance = function(obj, cls) {
    if (cls.PY$__class__ === tuple) {
        var length = cls.PY$__len__();

        if (length.PY$__eq__($c0) === True) {
            return False;
        }

        for (var i = 0; i < length; i++) {
            var _cls = cls.PY$__getitem__(i);

            if ($PY.isinstance(obj, _cls)) {
                return True;
            }
        }

        return False;
    } else {
        var c = obj.PY$__class__;
        while (c) {
            if (c === cls)
                return True;
            c = c.PY$__super__;
        }
        return False;
    }
};

__builtins__.PY$issubclass = $PY.c_nif;

__builtins__.PY$len = function(obj) {
    if (obj.PY$__len__ !== undefined) {
        return obj.PY$__len__();
    } else {
        throw __builtins__.PY$AttributeError('__len__');
    }
};

__builtins__.PY$license = $PY.c_nif;
__builtins__.PY$locals = $PY.c_nif;
__builtins__.PY$long = $PY.c_nif;

__builtins__.PY$map = function() {
    if (arguments.length < 2) {
        throw __builtins__.PY$TypeError("__builtins__.PY$map() requires at least two args");
    }

    if (arguments.length > 2) {
        throw __builtins__.PY$NotImplementedError("only one sequence allowed in __builtins__.PY$map()");
    }

    var func = arguments[0];
    var items = list();

    iterate(arguments[1], function(item) {
        items.PY$append(func(item));
    });

    if (__builtins__.PY$__python3__)
        return iter(items);
    else
        return items;
};

__builtins__.PY$max = function(list) {
    if (__builtins__.PY$len(list).PY$__eq__($c0) === True)
        throw __builtins__.PY$ValueError("max() arg is an empty sequence");
    else {
        var result = null;

        iterate(list, function(item) {
                if ((result === null) || js(item.PY$__gt__(result)))
                    result = item;
        });

        return result;
    }
};

__builtins__.PY$memoryview = $PY.c_nif;

__builtins__.PY$min = function(list) {
    if (__builtins__.PY$len(list).PY$__eq__($c0) === True)
        throw __builtins__.PY$ValueError("min() arg is an empty sequence");
    else {
        var result = null;

        iterate(list, function(item) {
                if ((result === null) || js(item.PY$__lt__(result)))
                    result = item;
        });

        return result;
    }
};

__builtins__.PY$next = $PY.c_nif;
__builtins__.PY$oct = $PY.c_nif;
__builtins__.PY$open = $PY.c_nif;
__builtins__.PY$ord = $PY.c_nif;
__builtins__.PY$pow = $PY.c_nif;

if (typeof console !== 'undefined' && console.log !== undefined) {
    if (console.log.apply !== undefined) {
        __builtins__.PY$print = function()  {
            console.log.apply(console, arguments);
        };
    } else {
        __builtins__.PY$print = function()  {
            var args = js(str(" ").PY$join(tuple(Array.prototype.slice.call(arguments))));
            console.log(args);
        };
    }
} else if (typeof WScript !== 'undefined') {
    __builtins__.PY$print = function() {
        var args = js(str(" ").PY$join(tuple(Array.prototype.slice.call(arguments))));
        WScript.Echo(args);
    };
} else if (typeof window === 'undefined' || window.print !== print) {
    __builtins__.PY$print = function() {
        if (arguments.length <= 1) {
            if (arguments[0] !== undefined) {
                print(__builtins__.PY$str(arguments[0]));
            } else {
                print("");
            }
        } else {
            print.apply(null, arguments);
        }
    };
} else {
    __builtins__.PY$print = function() {
        var args = tuple(Array.prototype.slice.call(arguments));
        alert(js(__builtins__.PY$str(" ").PY$join(__builtins__.PY$map(__builtins__.PY$repr, args))));
    };
}

__builtins__.PY$property = $PY.c_nif;
__builtins__.PY$quit = $PY.c_nif;

__builtins__.PY$range = function(start, end, step) {
    start = js(start);

    if (end === undefined) {
        end = start;
        start = 0;
    } else {
        end = js(end);
    }

    if (step === undefined) {
        step = 1;
    } else {
        step = js(step);
    }

    var seq = [];

    for (var i = start; i < end; i += step) {
        seq.push(i);
    }

    if (__builtins__.PY$__python3__)
        return iter(seq);
    else
        return list(seq);
};

__builtins__.PY$raw_input = $PY.c_nif;

__builtins__.PY$reduce = function(func, seq) {
    var initial;
    if (arguments.length === 3) {
        initial = arguments[2];
    } else {
        initial = null;
    }
    if (__builtins__.PY$len(seq)._js_() < 2) {
        return initial;
    }
    var accum, start;
    if (arguments.length === 3) {
        accum = initial;
        start = 0;
    } else {
        accum = func(seq.PY$__getitem__(0), seq.PY$__getitem__(1));
        start = 2;
    }
    for (var i = start; i < __builtins__.PY$len(seq)._js_(); i++) {
        accum = func(accum, seq.PY$__getitem__(i));
    }
    return accum;
};

__builtins__.PY$reload = $PY.c_nif;

__builtins__.PY$repr = function(obj) {
    if (obj === undefined) {
        return str("None");
    } else if (obj.PY$__class__ === undefined) {
        return object.PY$__repr__.call(obj);
    } else if (obj.PY$__repr__ !== undefined) {
        return obj.PY$__repr__(obj);
    } else if (obj.PY$__str__ !== undefined) {
        return obj.PY$__str__(obj);
    } else {
        throw __builtins__.PY$AttributeError('__repr__ or __str__ not found on ' + typeof(obj));
    }
};

__builtins__.PY$reversed = $PY.c_nif;
__builtins__.PY$round = $PY.c_nif;
__builtins__.PY$set = $PY.c_nif;

__builtins__.PY$setattr = function(obj, name, value) {
    name = js(name);
    obj["PY$" + name] = value;
};

__builtins__.PY$sorted = function(iterable) {
    var l = list(iterable);
    l.PY$sort();
    return l;
};

__builtins__.PY$staticmethod = function(func) {
    var res = function () {
        return func.apply(null, [null].concat(Array.prototype.slice.call(arguments)));
    };
    res.__static = true;
    return res;
};

__builtins__.PY$sum = function(list) {
    var result = 0;

    iterate(list, function(item) {
        result += js(item);
    });

    return result;
};

__builtins__.PY$type = $PY.c_nif;
__builtins__.PY$unichr = $PY.c_nif;
__builtins__.PY$vars = $PY.c_nif;

__builtins__.PY$xrange = function(start, end, step) {
    return iter(__builtins__.PY$range(start, end, step));
};

__builtins__.PY$zip = function() {
    if (!arguments.length) {
        return list();
    }

    var iters = list();
    var i;

    for (i = 0; i < arguments.length; i++) {
        iters.PY$append(iter(arguments[i]));
    }

    var items = list();

    while (true) {
        var item = list();

        for (i = 0; i < arguments.length; i++) {
            try {
                var value = iters.PY$__getitem__(i).PY$next();
            } catch (exc) {
                if (exc === $PY.c_stopiter || $PY.isinstance(exc, __builtins__.PY$StopIteration)) {
                    return items;
                } else {
                    throw exc;
                }
            }

            item.PY$append(value);
        }

        items.PY$append(tuple(item));
    }
    return None;
};
<commit_msg> + Implemented chr()<commit_after>/**
  Copyright 2010-2011 Mateusz Paprocki <mattpap@gmail.com>
  Copyright 2011 Christian Iversen <ci@sikkerhed.org>

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
**/

/*
 * Bastardized javascript-python builtins. Will be moved in the future
 */
__builtins__.js_getattr = function(obj, name, value) {
    var val = obj[name];

    if (val !== undefined) {
        return val;
    } else {
        if (value !== undefined) {
            return value;
        } else {
            throw __builtins__.PY$AttributeError("Object " + js(str(obj)) + " does not have attribute " + name);
        }
    }
};

__builtins__.js_setattr = function(obj, name, value) {
    obj[name] = value;
};

/*
 * Python __builtins__
 */

__builtins__.PY$abs = $PY.c_nif;
__builtins__.PY$all = $PY.c_nif;
__builtins__.PY$any = $PY.c_nif;
__builtins__.PY$apply = $PY.c_nif;
__builtins__.PY$bin = $PY.c_nif;
__builtins__.PY$buffer = $PY.c_nif;
__builtins__.PY$bytearray = $PY.c_nif;
__builtins__.PY$bytes = $PY.c_nif;
__builtins__.PY$callable = $PY.c_nif;

__builtins__.PY$chr = function(chr) {
    var s = String.fromCharCode(chr._js_());
    if (s === "\0") {
        throw __builtins__.PY$TypeError("an integer is required");
    } else {
        return __builtins__.PY$str(s);
    }
};

__builtins__.PY$classmethod = $PY.c_nif;

__builtins__.PY$cmp = function(x, y) {
    return x.PY$__cmp__(y);
};

__builtins__.PY$coerce = $PY.c_nif;
__builtins__.PY$compile = $PY.c_nif;
__builtins__.PY$complex = $PY.c_nif;
__builtins__.PY$copyright = $PY.c_nif;
__builtins__.PY$credits = $PY.c_nif;

__builtins__.PY$delattr = function(obj, name) {
    name = js(name);
    if (obj["PY$" + name] !== undefined) {
        delete obj["PY$" + name];
    } else {
        throw __builtins__.PY$AttributeError("Object " + js(str(obj)) + " does not have attribute " + name);
    }
};

__builtins__.PY$dir = function(obj) {
    var res = list();
    for (var i in obj) {
        if (i.indexOf('PY$') === 0) {
            res.PY$append(__builtins__.PY$str(i.substr(3)));
        }
    }
    res.PY$sort();
    return res;
};

__builtins__.PY$divmod = $PY.c_nif;

__builtins__.PY$enumerate = function(obj) {
    if (arguments.length != 1) {
        throw __builtins__.PY$NotImplementedError("enumerate() only supports 1 argument");
    }
    var items = list();
    var count = 0;
    iterate(obj, function(elm) {
                items.PY$append(tuple([count++, elm]));
            });
    return items;
};

__builtins__.PY$eval = $PY.c_nif;
__builtins__.PY$execfile = $PY.c_nif;
__builtins__.PY$exit = $PY.c_nif;
__builtins__.PY$file = $PY.c_nif;

__builtins__.PY$filter = function(f, l) {
   var res = list();
   iterate(l, function(item) {
     if (f(item) === True) {
       res.PY$append(item);
     }
   });
   return res;
};

__builtins__.PY$format = $PY.c_nif;
__builtins__.PY$frozenset = $PY.c_nif;

__builtins__.PY$getattr = function(obj, name, value) {
    name = js(name);
    var val = obj["PY$" + name];

    if (val !== undefined) {
        return val;
    } else {
        if (value !== undefined) {
            return value;
        } else {
            throw __builtins__.PY$AttributeError("Object " + js(str(obj)) + " does not have attribute " + name);
        }
    }
};

__builtins__.PY$globals = $PY.c_nif;

__builtins__.PY$hasattr = function(obj, name) {
    name = js(name);
    return obj["PY$" + name] === undefined ? False : True;
};

__builtins__.PY$hash = function(obj) {
    if (obj.PY$__hash__ !== undefined) {
        return obj.PY$__hash__();
    } else if (typeof(obj) === 'number') {
        return obj === -1 ? -2 : obj;
    } else {
        throw __builtins__.PY$AttributeError('__hash__');
    }
};

__builtins__.PY$help = $PY.c_nif;
__builtins__.PY$hex = $PY.c_nif;
__builtins__.PY$id = $PY.c_nif;
__builtins__.PY$input = $PY.c_nif;
__builtins__.PY$intern = $PY.c_nif;

__builtins__.PY$isinstance = function(obj, cls) {
    if (cls.PY$__class__ === tuple) {
        var length = cls.PY$__len__();

        if (length.PY$__eq__($c0) === True) {
            return False;
        }

        for (var i = 0; i < length; i++) {
            var _cls = cls.PY$__getitem__(i);

            if ($PY.isinstance(obj, _cls)) {
                return True;
            }
        }

        return False;
    } else {
        var c = obj.PY$__class__;
        while (c) {
            if (c === cls)
                return True;
            c = c.PY$__super__;
        }
        return False;
    }
};

__builtins__.PY$issubclass = $PY.c_nif;

__builtins__.PY$len = function(obj) {
    if (obj.PY$__len__ !== undefined) {
        return obj.PY$__len__();
    } else {
        throw __builtins__.PY$AttributeError('__len__');
    }
};

__builtins__.PY$license = $PY.c_nif;
__builtins__.PY$locals = $PY.c_nif;
__builtins__.PY$long = $PY.c_nif;

__builtins__.PY$map = function() {
    if (arguments.length < 2) {
        throw __builtins__.PY$TypeError("__builtins__.PY$map() requires at least two args");
    }

    if (arguments.length > 2) {
        throw __builtins__.PY$NotImplementedError("only one sequence allowed in __builtins__.PY$map()");
    }

    var func = arguments[0];
    var items = list();

    iterate(arguments[1], function(item) {
        items.PY$append(func(item));
    });

    if (__builtins__.PY$__python3__)
        return iter(items);
    else
        return items;
};

__builtins__.PY$max = function(list) {
    if (__builtins__.PY$len(list).PY$__eq__($c0) === True)
        throw __builtins__.PY$ValueError("max() arg is an empty sequence");
    else {
        var result = null;

        iterate(list, function(item) {
                if ((result === null) || js(item.PY$__gt__(result)))
                    result = item;
        });

        return result;
    }
};

__builtins__.PY$memoryview = $PY.c_nif;

__builtins__.PY$min = function(list) {
    if (__builtins__.PY$len(list).PY$__eq__($c0) === True)
        throw __builtins__.PY$ValueError("min() arg is an empty sequence");
    else {
        var result = null;

        iterate(list, function(item) {
                if ((result === null) || js(item.PY$__lt__(result)))
                    result = item;
        });

        return result;
    }
};

__builtins__.PY$next = $PY.c_nif;
__builtins__.PY$oct = $PY.c_nif;
__builtins__.PY$open = $PY.c_nif;
__builtins__.PY$ord = $PY.c_nif;
__builtins__.PY$pow = $PY.c_nif;

if (typeof console !== 'undefined' && console.log !== undefined) {
    if (console.log.apply !== undefined) {
        __builtins__.PY$print = function()  {
            console.log.apply(console, arguments);
        };
    } else {
        __builtins__.PY$print = function()  {
            var args = js(str(" ").PY$join(tuple(Array.prototype.slice.call(arguments))));
            console.log(args);
        };
    }
} else if (typeof WScript !== 'undefined') {
    __builtins__.PY$print = function() {
        var args = js(str(" ").PY$join(tuple(Array.prototype.slice.call(arguments))));
        WScript.Echo(args);
    };
} else if (typeof window === 'undefined' || window.print !== print) {
    __builtins__.PY$print = function() {
        if (arguments.length <= 1) {
            if (arguments[0] !== undefined) {
                print(__builtins__.PY$str(arguments[0]));
            } else {
                print("");
            }
        } else {
            print.apply(null, arguments);
        }
    };
} else {
    __builtins__.PY$print = function() {
        var args = tuple(Array.prototype.slice.call(arguments));
        alert(js(__builtins__.PY$str(" ").PY$join(__builtins__.PY$map(__builtins__.PY$repr, args))));
    };
}

__builtins__.PY$property = $PY.c_nif;
__builtins__.PY$quit = $PY.c_nif;

__builtins__.PY$range = function(start, end, step) {
    start = js(start);

    if (end === undefined) {
        end = start;
        start = 0;
    } else {
        end = js(end);
    }

    if (step === undefined) {
        step = 1;
    } else {
        step = js(step);
    }

    var seq = [];

    for (var i = start; i < end; i += step) {
        seq.push(i);
    }

    if (__builtins__.PY$__python3__)
        return iter(seq);
    else
        return list(seq);
};

__builtins__.PY$raw_input = $PY.c_nif;

__builtins__.PY$reduce = function(func, seq) {
    var initial;
    if (arguments.length === 3) {
        initial = arguments[2];
    } else {
        initial = null;
    }
    if (__builtins__.PY$len(seq)._js_() < 2) {
        return initial;
    }
    var accum, start;
    if (arguments.length === 3) {
        accum = initial;
        start = 0;
    } else {
        accum = func(seq.PY$__getitem__(0), seq.PY$__getitem__(1));
        start = 2;
    }
    for (var i = start; i < __builtins__.PY$len(seq)._js_(); i++) {
        accum = func(accum, seq.PY$__getitem__(i));
    }
    return accum;
};

__builtins__.PY$reload = $PY.c_nif;

__builtins__.PY$repr = function(obj) {
    if (obj === undefined) {
        return str("None");
    } else if (obj.PY$__class__ === undefined) {
        return object.PY$__repr__.call(obj);
    } else if (obj.PY$__repr__ !== undefined) {
        return obj.PY$__repr__(obj);
    } else if (obj.PY$__str__ !== undefined) {
        return obj.PY$__str__(obj);
    } else {
        throw __builtins__.PY$AttributeError('__repr__ or __str__ not found on ' + typeof(obj));
    }
};

__builtins__.PY$reversed = $PY.c_nif;
__builtins__.PY$round = $PY.c_nif;
__builtins__.PY$set = $PY.c_nif;

__builtins__.PY$setattr = function(obj, name, value) {
    name = js(name);
    obj["PY$" + name] = value;
};

__builtins__.PY$sorted = function(iterable) {
    var l = list(iterable);
    l.PY$sort();
    return l;
};

__builtins__.PY$staticmethod = function(func) {
    var res = function () {
        return func.apply(null, [null].concat(Array.prototype.slice.call(arguments)));
    };
    res.__static = true;
    return res;
};

__builtins__.PY$sum = function(list) {
    var result = 0;

    iterate(list, function(item) {
        result += js(item);
    });

    return result;
};

__builtins__.PY$type = $PY.c_nif;
__builtins__.PY$unichr = $PY.c_nif;
__builtins__.PY$vars = $PY.c_nif;

__builtins__.PY$xrange = function(start, end, step) {
    return iter(__builtins__.PY$range(start, end, step));
};

__builtins__.PY$zip = function() {
    if (!arguments.length) {
        return list();
    }

    var iters = list();
    var i;

    for (i = 0; i < arguments.length; i++) {
        iters.PY$append(iter(arguments[i]));
    }

    var items = list();

    while (true) {
        var item = list();

        for (i = 0; i < arguments.length; i++) {
            try {
                var value = iters.PY$__getitem__(i).PY$next();
            } catch (exc) {
                if (exc === $PY.c_stopiter || $PY.isinstance(exc, __builtins__.PY$StopIteration)) {
                    return items;
                } else {
                    throw exc;
                }
            }

            item.PY$append(value);
        }

        items.PY$append(tuple(item));
    }
    return None;
};
<|endoftext|>


<commit_before>CollectionAPI = function(options) {
  var self = this;

  self.version = '0.2.3';
  self._url = Npm.require('url');
  self._querystring = Npm.require('querystring');
  self._fiber = Npm.require('fibers');
  self._collections = {};
  self.options = {
    apiPath: 'collectionapi',
    standAlone: false,
    allowCORS: false,
    sslEnabled: false,
    listenPort: 3005,
    listenHost: undefined,
    authToken: undefined,
    privateKeyFile: 'privatekey.pem',
    certificateFile: 'certificate.pem'
  };
  _.extend(self.options, options || {});
};

CollectionAPI.prototype.addCollection = function(collection, path, options) {
  var self = this;

  var collectionOptions = {};
  collectionOptions[path] = {
    collection: collection,
    options: options || {}
  };
  _.extend(self._collections, collectionOptions);
};

CollectionAPI.prototype.start = function() {
  var self = this;
  var httpServer, httpOptions, scheme;

  var startupMessage = 'Collection API v' + self.version;

  if (self.options.standAlone === true) {
    if (self.options.sslEnabled === true) {
      scheme = 'https://';
      httpServer = Npm.require('https');
      var fs = Npm.require('fs');

      httpOptions = {
        key: fs.readFileSync(self.options.privateKeyFile),
        cert: fs.readFileSync(self.options.certificateFile)
      };
    } else {
      scheme = 'http://';
      httpServer = Npm.require('http');
    }

    self._httpServer = httpServer.createServer(httpOptions);
    self._httpServer.addListener('request', function(request, response) {
      new CollectionAPI._requestListener(self, request, response);
    });
    self._httpServer.listen(self.options.listenPort, self.options.listenHost);
    console.log(startupMessage + ' running as a stand-alone server on ' +  scheme + (self.options.listenHost || 'localhost') + ':' + self.options.listenPort + '/' + (self.options.apiPath || ''));
  } else {

    RoutePolicy.declare('/' + this.options.apiPath + '/', 'network');

    WebApp.connectHandlers.use(function(req, res, next) {
      if (req.url.split('/')[1] !== self.options.apiPath) {
        next();
        return;
      }
      self._fiber(function() {
        new CollectionAPI._requestListener(self, req, res);
      }).run();
    });

    console.log(startupMessage + ' running at /' + this.options.apiPath);
  }
};

CollectionAPI.prototype._collectionOptions = function(requestPath) {
  var self = this;
  return self._collections[requestPath.collectionPath] ? self._collections[requestPath.collectionPath].options : undefined;
};

CollectionAPI._requestListener = function(server, request, response) {
  var self = this;

  self._server = server;
  self._request = request;
  self._response = response;
  if (server.options.allowCORS === true) {
    response.setHeader('Access-Control-Allow-Origin', '*');
  }

  self._requestUrl = self._server._url.parse(self._request.url, true);

  // Check for the X-Auth-Token header or auth-token in the query string
  self._requestAuthToken = self._request.headers['x-auth-token'] ? self._request.headers['x-auth-token'] : self._server._querystring.parse(self._requestUrl.query)['auth-token'];

  var requestPath;
  var pathName = self._requestUrl.pathname;
  if (pathName.charAt(pathName.length - 1) === '/') {
    pathName = pathName.substring(0, pathName.length - 1);
  }

  if (self._server.options.standAlone === true && ! self._server.options.apiPath) {
    requestPath = pathName.split('/').slice(1);
  } else {
    requestPath = pathName.split('/').slice(2);
  }

  self._requestPath = {
    collectionPath: requestPath[0],
    collectionId: requestPath[1],
    fields: requestPath.slice(2),
    query: self._requestUrl.query
  };

  self._requestCollection = self._server._collections[self._requestPath.collectionPath] ? self._server._collections[self._requestPath.collectionPath].collection : undefined;

  if (!self._requestCollection) {
    return self._notFoundResponse('Collection Object Not Found');
  }

  if (!self._authenticate(self._requestAuthToken, self._request.method, self._requestPath)) {
    return self._unauthorizedResponse('Invalid/Missing Auth Token');
  }

  return self._handleRequest();
};

CollectionAPI._requestListener.prototype._authenticate = function() {
  var self = this;
  var collectionOptions = self._server._collectionOptions(self._requestPath);
  var authCount = 0;

  // Check the global auth token
  if (self._server.options.authToken) {
    authCount++;
    if (self._requestAuthToken === self._server.options.authToken) {
      return true;
    }
  }

  // Check the collection's auth token
  if (collectionOptions && collectionOptions.authToken) {
    authCount++;
    if(self._requestAuthToken === collectionOptions.authToken) {
      return true;
    }
  }

  if (!authCount && collectionOptions.authenticate && _.isFunction(collectionOptions.authenticate)) {
    authCount++;
    if (collectionOptions.authenticate.apply(self, arguments)) {
      return true;
    }
  }

  return authCount === 0;
};

CollectionAPI._requestListener.prototype._handleRequest = function() {
  var self = this;

  if (!self._requestMethodAllowed(self._request.method)) {
    return self._notSupportedResponse();
  }

  switch (self._request.method) {
  case 'GET':
    return self._getRequest();
  case 'POST':
    return self._postRequest();
  case 'PUT':
    return self._putRequest();
  case 'DELETE':
    return self._deleteRequest();
  default:
    return self._notSupportedResponse();
  }
};

CollectionAPI._requestListener.prototype._requestMethodAllowed = function(method) {
  var self = this;
  var collectionOptions = self._server._collectionOptions(self._requestPath);

  if (collectionOptions && collectionOptions.methods) {
    return _.indexOf(collectionOptions.methods, method) >= 0;
  }

  return true;
};

CollectionAPI._requestListener.prototype._beforeHandling = function(method) {
  var self = this;
  var collectionOptions = self._server._collectionOptions(self._requestPath);

  if (collectionOptions && collectionOptions.before && collectionOptions.before[method] &&  _.isFunction(collectionOptions.before[method])) {
    return collectionOptions.before[method].apply(self, _.rest(arguments));
  }

  return true;
};

CollectionAPI._requestListener.prototype._afterHandling = function(method) {
  var self = this;
  var collectionOptions = self._server._collectionOptions(self._requestPath);

  if (collectionOptions && collectionOptions.after && collectionOptions.after[method] &&  _.isFunction(collectionOptions.after[method])) {
    return collectionOptions.after[method].apply(self, _.rest(arguments));
  }

  return true;
};

CollectionAPI._requestListener.prototype._getEmptyReturnObject = function() {
  var returnObject = {
    success: false,
    statusCode : undefined,
    body: undefined
  };
  return returnObject;
};

CollectionAPI._requestListener.prototype._handleReturnObject = function(method, returnObject) {
  if (returnObject.success && returnObject.statusCode && returnObject.body) {
    var self = this;
    self._afterHandling(method);
    return self._sendResponse(returnObject.statusCode, JSON.stringify(returnObject.body));
  }
  return false;
};

CollectionAPI._requestListener.prototype._getRequest = function(fromRequest) {
  var self = this;

  self._server._fiber(function() {

    try {
      // TODO: A better way to do this?
      var collection_result = self._requestPath.collectionId !== undefined ? self._requestCollection.find(self._requestPath.collectionId) : self._requestCollection.find();

      var records = [];
      collection_result.forEach(function(record) {
        records.push(record);
      });

      var returnObject = self._getEmptyReturnObject();

      if(!self._beforeHandling('GET', records, self._requestPath, returnObject)) {
        if (fromRequest) {
          return records.length ? self._noContentResponse() : self._notFoundResponse('No Record(s) Found');
        }
        return self._rejectedResponse("Could not get that collection/object.");
      }

      if (self._handleReturnObject('GET', returnObject)) {
        return true;
      }

      records = _.compact(records);

      if (records.length === 0) {
        return self._notFoundResponse('No Record(s) Found');
      }

      self._afterHandling('GET');

      if (fromRequest === "POST") {
        return self._createdResponse(JSON.stringify(records));
      }

      return self._okResponse(JSON.stringify(records));

    } catch (e) {
      return self._internalServerErrorResponse(e);
    }
  }).run();
};

CollectionAPI._requestListener.prototype._putRequest = function() {
  var self = this;

  if (! self._requestPath.collectionId) {
    return self._notFoundResponse('Missing _id');
  }

  var requestData = '';

  self._request.on('data', function(chunk) {
    requestData += chunk.toString();
  });

  self._request.on('end', function() {
    self._server._fiber(function() {
      try {
        var obj = JSON.parse(requestData);

        var returnObject = self._getEmptyReturnObject();

        if(!self._beforeHandling('PUT', self._requestCollection.findOne(self._requestPath.collectionId), obj, self._requestPath, returnObject)) {
          return self._rejectedResponse("Could not put that object.");
        }

        if (self._handleReturnObject('PUT', returnObject)) {
          return true;
        }

        self._requestCollection.update(self._requestPath.collectionId, obj);
      } catch (e) {
        return self._internalServerErrorResponse(e);
      }

      self._afterHandling('PUT');
      if (self._requestPath.query.callback === "0") {
        return self._createdResponse(JSON.stringify({'status': 'success'}));
      } else {
        return self._getRequest('PUT');
      }
    }).run();
  });
};

CollectionAPI._requestListener.prototype._deleteRequest = function() {
  var self = this;

  if (! self._requestPath.collectionId) {
    return self._notFoundResponse('Missing _id');
  }

  self._server._fiber(function() {
    try {
      var returnObject = self._getEmptyReturnObject();

      if(!self._beforeHandling('DELETE', self._requestCollection.findOne(self._requestPath.collectionId), self._requestPath, returnObject)) {
        return self._rejectedResponse("Could not delete that object.");
      }

      if (self._handleReturnObject('DELETE', returnObject)) {
        return true;
      }

      self._requestCollection.remove(self._requestPath.collectionId);
    } catch (e) {
      return self._internalServerErrorResponse(e);
    }
    self._afterHandling('DELETE');
    return self._okResponse('');
  }).run();
};

CollectionAPI._requestListener.prototype._postRequest = function() {
  var self = this;
  var requestData = '';

  self._request.on('data', function(chunk) {
    requestData += chunk.toString();
  });

  self._request.on('end', function() {
    self._server._fiber(function() {
      try {
        var obj = JSON.parse(requestData);

        var returnObject = self._getEmptyReturnObject();

        if(!self._beforeHandling('POST', obj, self._requestPath, returnObject)) {
          return self._rejectedResponse("Could not post that object.");
        }

        if (self._handleReturnObject('POST', returnObject)) {
          return true;
        }

        self._requestPath.collectionId = self._requestCollection.insert(obj);
      } catch (e) {
        return self._internalServerErrorResponse(e);
      }
      self._afterHandling('POST');
      return self._getRequest('POST');
    }).run();
  });
};

CollectionAPI._requestListener.prototype._okResponse = function(body) {
  var self = this;
  self._sendResponse(200, body);
};

CollectionAPI._requestListener.prototype._createdResponse = function(body) {
  var self = this;
  self._sendResponse(201, body);
};

CollectionAPI._requestListener.prototype._noContentResponse = function() {
  var self = this;
  self._sendResponse(204, '');
};

CollectionAPI._requestListener.prototype._notSupportedResponse = function() {
  var self = this;
  self._sendResponse(501, '');
};

CollectionAPI._requestListener.prototype._unauthorizedResponse = function(body) {
  var self = this;
  self._sendResponse(401, JSON.stringify({message: body.toString()}));
};

CollectionAPI._requestListener.prototype._notFoundResponse = function(body) {
  var self = this;
  self._sendResponse(404, JSON.stringify({message: body.toString()}));
};

CollectionAPI._requestListener.prototype._rejectedResponse= function(body) {
  var self = this;
  self._sendResponse(409, JSON.stringify({message: body.toString()}));
};

CollectionAPI._requestListener.prototype._internalServerErrorResponse = function(body) {
  var self = this;
  self._sendResponse(500, JSON.stringify({error: body.toString()}));
};

CollectionAPI._requestListener.prototype._sendResponse = function(statusCode, body) {
  var self = this;
  self._response.statusCode = statusCode;
  self._response.setHeader('Content-Length', Buffer.byteLength(body, 'utf8'));
  self._response.setHeader('Content-Type', 'application/json');
  self._response.write(body);
  self._response.end();
  return true;
};
<commit_msg>change version string.<commit_after>CollectionAPI = function(options) {
  var self = this;

  self.version = '0.2.4';
  self._url = Npm.require('url');
  self._querystring = Npm.require('querystring');
  self._fiber = Npm.require('fibers');
  self._collections = {};
  self.options = {
    apiPath: 'collectionapi',
    standAlone: false,
    allowCORS: false,
    sslEnabled: false,
    listenPort: 3005,
    listenHost: undefined,
    authToken: undefined,
    privateKeyFile: 'privatekey.pem',
    certificateFile: 'certificate.pem'
  };
  _.extend(self.options, options || {});
};

CollectionAPI.prototype.addCollection = function(collection, path, options) {
  var self = this;

  var collectionOptions = {};
  collectionOptions[path] = {
    collection: collection,
    options: options || {}
  };
  _.extend(self._collections, collectionOptions);
};

CollectionAPI.prototype.start = function() {
  var self = this;
  var httpServer, httpOptions, scheme;

  var startupMessage = 'Collection API v' + self.version;

  if (self.options.standAlone === true) {
    if (self.options.sslEnabled === true) {
      scheme = 'https://';
      httpServer = Npm.require('https');
      var fs = Npm.require('fs');

      httpOptions = {
        key: fs.readFileSync(self.options.privateKeyFile),
        cert: fs.readFileSync(self.options.certificateFile)
      };
    } else {
      scheme = 'http://';
      httpServer = Npm.require('http');
    }

    self._httpServer = httpServer.createServer(httpOptions);
    self._httpServer.addListener('request', function(request, response) {
      new CollectionAPI._requestListener(self, request, response);
    });
    self._httpServer.listen(self.options.listenPort, self.options.listenHost);
    console.log(startupMessage + ' running as a stand-alone server on ' +  scheme + (self.options.listenHost || 'localhost') + ':' + self.options.listenPort + '/' + (self.options.apiPath || ''));
  } else {

    RoutePolicy.declare('/' + this.options.apiPath + '/', 'network');

    WebApp.connectHandlers.use(function(req, res, next) {
      if (req.url.split('/')[1] !== self.options.apiPath) {
        next();
        return;
      }
      self._fiber(function() {
        new CollectionAPI._requestListener(self, req, res);
      }).run();
    });

    console.log(startupMessage + ' running at /' + this.options.apiPath);
  }
};

CollectionAPI.prototype._collectionOptions = function(requestPath) {
  var self = this;
  return self._collections[requestPath.collectionPath] ? self._collections[requestPath.collectionPath].options : undefined;
};

CollectionAPI._requestListener = function(server, request, response) {
  var self = this;

  self._server = server;
  self._request = request;
  self._response = response;
  if (server.options.allowCORS === true) {
    response.setHeader('Access-Control-Allow-Origin', '*');
  }

  self._requestUrl = self._server._url.parse(self._request.url, true);

  // Check for the X-Auth-Token header or auth-token in the query string
  self._requestAuthToken = self._request.headers['x-auth-token'] ? self._request.headers['x-auth-token'] : self._server._querystring.parse(self._requestUrl.query)['auth-token'];

  var requestPath;
  var pathName = self._requestUrl.pathname;
  if (pathName.charAt(pathName.length - 1) === '/') {
    pathName = pathName.substring(0, pathName.length - 1);
  }

  if (self._server.options.standAlone === true && ! self._server.options.apiPath) {
    requestPath = pathName.split('/').slice(1);
  } else {
    requestPath = pathName.split('/').slice(2);
  }

  self._requestPath = {
    collectionPath: requestPath[0],
    collectionId: requestPath[1],
    fields: requestPath.slice(2),
    query: self._requestUrl.query
  };

  self._requestCollection = self._server._collections[self._requestPath.collectionPath] ? self._server._collections[self._requestPath.collectionPath].collection : undefined;

  if (!self._requestCollection) {
    return self._notFoundResponse('Collection Object Not Found');
  }

  if (!self._authenticate(self._requestAuthToken, self._request.method, self._requestPath)) {
    return self._unauthorizedResponse('Invalid/Missing Auth Token');
  }

  return self._handleRequest();
};

CollectionAPI._requestListener.prototype._authenticate = function() {
  var self = this;
  var collectionOptions = self._server._collectionOptions(self._requestPath);
  var authCount = 0;

  // Check the global auth token
  if (self._server.options.authToken) {
    authCount++;
    if (self._requestAuthToken === self._server.options.authToken) {
      return true;
    }
  }

  // Check the collection's auth token
  if (collectionOptions && collectionOptions.authToken) {
    authCount++;
    if(self._requestAuthToken === collectionOptions.authToken) {
      return true;
    }
  }

  if (!authCount && collectionOptions.authenticate && _.isFunction(collectionOptions.authenticate)) {
    authCount++;
    if (collectionOptions.authenticate.apply(self, arguments)) {
      return true;
    }
  }

  return authCount === 0;
};

CollectionAPI._requestListener.prototype._handleRequest = function() {
  var self = this;

  if (!self._requestMethodAllowed(self._request.method)) {
    return self._notSupportedResponse();
  }

  switch (self._request.method) {
  case 'GET':
    return self._getRequest();
  case 'POST':
    return self._postRequest();
  case 'PUT':
    return self._putRequest();
  case 'DELETE':
    return self._deleteRequest();
  default:
    return self._notSupportedResponse();
  }
};

CollectionAPI._requestListener.prototype._requestMethodAllowed = function(method) {
  var self = this;
  var collectionOptions = self._server._collectionOptions(self._requestPath);

  if (collectionOptions && collectionOptions.methods) {
    return _.indexOf(collectionOptions.methods, method) >= 0;
  }

  return true;
};

CollectionAPI._requestListener.prototype._beforeHandling = function(method) {
  var self = this;
  var collectionOptions = self._server._collectionOptions(self._requestPath);

  if (collectionOptions && collectionOptions.before && collectionOptions.before[method] &&  _.isFunction(collectionOptions.before[method])) {
    return collectionOptions.before[method].apply(self, _.rest(arguments));
  }

  return true;
};

CollectionAPI._requestListener.prototype._afterHandling = function(method) {
  var self = this;
  var collectionOptions = self._server._collectionOptions(self._requestPath);

  if (collectionOptions && collectionOptions.after && collectionOptions.after[method] &&  _.isFunction(collectionOptions.after[method])) {
    return collectionOptions.after[method].apply(self, _.rest(arguments));
  }

  return true;
};

CollectionAPI._requestListener.prototype._getEmptyReturnObject = function() {
  var returnObject = {
    success: false,
    statusCode : undefined,
    body: undefined
  };
  return returnObject;
};

CollectionAPI._requestListener.prototype._handleReturnObject = function(method, returnObject) {
  if (returnObject.success && returnObject.statusCode && returnObject.body) {
    var self = this;
    self._afterHandling(method);
    return self._sendResponse(returnObject.statusCode, JSON.stringify(returnObject.body));
  }
  return false;
};

CollectionAPI._requestListener.prototype._getRequest = function(fromRequest) {
  var self = this;

  self._server._fiber(function() {

    try {
      // TODO: A better way to do this?
      var collection_result = self._requestPath.collectionId !== undefined ? self._requestCollection.find(self._requestPath.collectionId) : self._requestCollection.find();

      var records = [];
      collection_result.forEach(function(record) {
        records.push(record);
      });

      var returnObject = self._getEmptyReturnObject();

      if(!self._beforeHandling('GET', records, self._requestPath, returnObject)) {
        if (fromRequest) {
          return records.length ? self._noContentResponse() : self._notFoundResponse('No Record(s) Found');
        }
        return self._rejectedResponse("Could not get that collection/object.");
      }

      if (self._handleReturnObject('GET', returnObject)) {
        return true;
      }

      records = _.compact(records);

      if (records.length === 0) {
        return self._notFoundResponse('No Record(s) Found');
      }

      self._afterHandling('GET');

      if (fromRequest === "POST") {
        return self._createdResponse(JSON.stringify(records));
      }

      return self._okResponse(JSON.stringify(records));

    } catch (e) {
      return self._internalServerErrorResponse(e);
    }
  }).run();
};

CollectionAPI._requestListener.prototype._putRequest = function() {
  var self = this;

  if (! self._requestPath.collectionId) {
    return self._notFoundResponse('Missing _id');
  }

  var requestData = '';

  self._request.on('data', function(chunk) {
    requestData += chunk.toString();
  });

  self._request.on('end', function() {
    self._server._fiber(function() {
      try {
        var obj = JSON.parse(requestData);

        var returnObject = self._getEmptyReturnObject();

        if(!self._beforeHandling('PUT', self._requestCollection.findOne(self._requestPath.collectionId), obj, self._requestPath, returnObject)) {
          return self._rejectedResponse("Could not put that object.");
        }

        if (self._handleReturnObject('PUT', returnObject)) {
          return true;
        }

        self._requestCollection.update(self._requestPath.collectionId, obj);
      } catch (e) {
        return self._internalServerErrorResponse(e);
      }

      self._afterHandling('PUT');
      if (self._requestPath.query.callback === "0") {
        return self._createdResponse(JSON.stringify({'status': 'success'}));
      } else {
        return self._getRequest('PUT');
      }
    }).run();
  });
};

CollectionAPI._requestListener.prototype._deleteRequest = function() {
  var self = this;

  if (! self._requestPath.collectionId) {
    return self._notFoundResponse('Missing _id');
  }

  self._server._fiber(function() {
    try {
      var returnObject = self._getEmptyReturnObject();

      if(!self._beforeHandling('DELETE', self._requestCollection.findOne(self._requestPath.collectionId), self._requestPath, returnObject)) {
        return self._rejectedResponse("Could not delete that object.");
      }

      if (self._handleReturnObject('DELETE', returnObject)) {
        return true;
      }

      self._requestCollection.remove(self._requestPath.collectionId);
    } catch (e) {
      return self._internalServerErrorResponse(e);
    }
    self._afterHandling('DELETE');
    return self._okResponse('');
  }).run();
};

CollectionAPI._requestListener.prototype._postRequest = function() {
  var self = this;
  var requestData = '';

  self._request.on('data', function(chunk) {
    requestData += chunk.toString();
  });

  self._request.on('end', function() {
    self._server._fiber(function() {
      try {
        var obj = JSON.parse(requestData);

        var returnObject = self._getEmptyReturnObject();

        if(!self._beforeHandling('POST', obj, self._requestPath, returnObject)) {
          return self._rejectedResponse("Could not post that object.");
        }

        if (self._handleReturnObject('POST', returnObject)) {
          return true;
        }

        self._requestPath.collectionId = self._requestCollection.insert(obj);
      } catch (e) {
        return self._internalServerErrorResponse(e);
      }
      self._afterHandling('POST');
      return self._getRequest('POST');
    }).run();
  });
};

CollectionAPI._requestListener.prototype._okResponse = function(body) {
  var self = this;
  self._sendResponse(200, body);
};

CollectionAPI._requestListener.prototype._createdResponse = function(body) {
  var self = this;
  self._sendResponse(201, body);
};

CollectionAPI._requestListener.prototype._noContentResponse = function() {
  var self = this;
  self._sendResponse(204, '');
};

CollectionAPI._requestListener.prototype._notSupportedResponse = function() {
  var self = this;
  self._sendResponse(501, '');
};

CollectionAPI._requestListener.prototype._unauthorizedResponse = function(body) {
  var self = this;
  self._sendResponse(401, JSON.stringify({message: body.toString()}));
};

CollectionAPI._requestListener.prototype._notFoundResponse = function(body) {
  var self = this;
  self._sendResponse(404, JSON.stringify({message: body.toString()}));
};

CollectionAPI._requestListener.prototype._rejectedResponse= function(body) {
  var self = this;
  self._sendResponse(409, JSON.stringify({message: body.toString()}));
};

CollectionAPI._requestListener.prototype._internalServerErrorResponse = function(body) {
  var self = this;
  self._sendResponse(500, JSON.stringify({error: body.toString()}));
};

CollectionAPI._requestListener.prototype._sendResponse = function(statusCode, body) {
  var self = this;
  self._response.statusCode = statusCode;
  self._response.setHeader('Content-Length', Buffer.byteLength(body, 'utf8'));
  self._response.setHeader('Content-Type', 'application/json');
  self._response.write(body);
  self._response.end();
  return true;
};
<|endoftext|>


<commit_before>const WebhooksApi = require('@octokit/webhooks')
const http = require('http') // core
const colors = require('irc').colors

let server
let webhook
let listener

const announce = (bot, msg) => {
  return bot.notice(bot.config.get('github.channel'), colors.wrap('dark_green', '[github] ') + msg)
}

module.exports = {
  onload: (bot) => {
    webhook = new WebhooksApi({ secret: bot.config.get('github.webhook.secret') })

    server = http.createServer(webhook.middleware)
    listener = webhook.on('*', (webhookEvent) => {
      bot.fireEvents('github', webhookEvent)
      bot.fireEvents(`github:${webhookEvent.name}`, webhookEvent)
    })

    server.listen(bot.config.get('github.webhook.port'))
  },
  onunload: (bot) => {
    webhook.removeListener(listener)
    server.close(() => console.log('gh server closed'))
  },
  events: {
    github: (bot, ghEvent) => {
      switch (ghEvent.name) {
        case 'check_run':
        case 'check_suite':
        case 'create': /* create branch */
        case 'issue_comment':
        case 'issues':
        case 'pull_request':
        case 'pull_request_review':
        case 'push':
        case 'status':
          return
      }
      announce(bot, colors.wrap('light_gray', `Unknown webhook event ${ghEvent.name}. keys: ${Object.keys(ghEvent.payload)}`))
    },
    'github:issues': (bot, ghEvent) => {
      let actionColors = {
        'opened': 'light_green',
        'edited': 'orange',
        'deleted': 'light_red',
        'transferred': 'light_gray',
        'pinned': 'white',
        'unpinned': 'white',
        'closed': 'dark_red',
        'reopened': 'dark_green',
        'assigned': 'light_cyan',
        'unassigned': 'cyan',
        'labeled': 'light_blue',
        'unlabeled': 'dark_blue',
        'locked': 'gray',
        'unlocked': 'light_gray',
        'milestoned': 'light_magenta',
        'demilestoned': 'magenta'
      }
      let coloredAction = colors.wrap(actionColors[ghEvent.payload.action], ghEvent.payload.action)
      return announce(bot, `${ghEvent.payload.sender.login} ${coloredAction} issue ${ghEvent.payload.issue.html_url}`)
    },
    'github:pull_request': (bot, ghEvent) => {
      if (ghEvent.payload.action === 'synchronize') return
      if (ghEvent.payload.action === 'ready_for_review') ghEvent.payload.action = 'undrafted'
      return announce(bot, `${ghEvent.payload.sender.login} ${ghEvent.payload.action} pull request ${ghEvent.payload.pull_request.html_url}`)
    },
    'github:delete': (bot, ghEvent) => {
      return announce(bot, `${ghEvent.payload.sender.login} deleted branch ${ghEvent.payload.ref}`)
    },
    'github:issue_comment': (bot, ghEvent) => {
      let verb = ghEvent.payload.action
      if (verb === 'created') verb = 'added'
      verb += ' comment on '
      return announce(bot, `${ghEvent.payload.sender.login} ${verb} issue comment ${ghEvent.payload.issue.html_url}`)
    },
    'github:push': (bot, ghEvent) => {
      if (ghEvent.payload.commits.length === 0) return
      return announce(bot, `${ghEvent.payload.pusher.name} pushed ${ghEvent.payload.commits.length} commits to ${ghEvent.payload.ref} ${ghEvent.payload.compare}`)
    },
    'github:pull_request_review': (bot, ghEvent) => {
      return announce(bot, `${ghEvent.payload.sender.login} ${ghEvent.payload.action} code review: ${ghEvent.payload.review.state} ${ghEvent.payload.review.html_url}`)
    }
  }
}
<commit_msg>Add assignee to issue message<commit_after>const WebhooksApi = require('@octokit/webhooks')
const http = require('http') // core
const colors = require('irc').colors

let server
let webhook
let listener

const announce = (bot, msg) => {
  return bot.notice(bot.config.get('github.channel'), colors.wrap('dark_green', '[github] ') + msg)
}

module.exports = {
  onload: (bot) => {
    webhook = new WebhooksApi({ secret: bot.config.get('github.webhook.secret') })

    server = http.createServer(webhook.middleware)
    listener = webhook.on('*', (webhookEvent) => {
      bot.fireEvents('github', webhookEvent)
      bot.fireEvents(`github:${webhookEvent.name}`, webhookEvent)
    })

    server.listen(bot.config.get('github.webhook.port'))
  },
  onunload: (bot) => {
    webhook.removeListener(listener)
    server.close(() => console.log('gh server closed'))
  },
  events: {
    github: (bot, ghEvent) => {
      switch (ghEvent.name) {
        case 'check_run':
        case 'check_suite':
        case 'create': /* create branch */
        case 'issue_comment':
        case 'issues':
        case 'pull_request':
        case 'pull_request_review':
        case 'push':
        case 'status':
          return
      }
      announce(bot, colors.wrap('light_gray', `Unknown webhook event ${ghEvent.name}. keys: ${Object.keys(ghEvent.payload)}`))
    },
    'github:issues': (bot, ghEvent) => {
      let actionColors = {
        'opened': 'light_green',
        'edited': 'orange',
        'deleted': 'light_red',
        'transferred': 'light_gray',
        'pinned': 'white',
        'unpinned': 'white',
        'closed': 'dark_red',
        'reopened': 'dark_green',
        'assigned': 'light_cyan',
        'unassigned': 'cyan',
        'labeled': 'light_blue',
        'unlabeled': 'dark_blue',
        'locked': 'gray',
        'unlocked': 'light_gray',
        'milestoned': 'light_magenta',
        'demilestoned': 'magenta'
      }
      let coloredAction = colors.wrap(actionColors[ghEvent.payload.action], ghEvent.payload.action)
      if (ghEvent.payload.action.includes('assigned')) {
        coloredAction += ' ' + ghEvent.payload.assignee.login + ' '
        coloredAction += ghEvent.payload.action === 'assigned' ? ' to' : 'from'
      }
      return announce(bot, `${ghEvent.payload.sender.login} ${coloredAction} issue ${ghEvent.payload.issue.html_url}`)
    },
    'github:pull_request': (bot, ghEvent) => {
      if (ghEvent.payload.action === 'synchronize') return
      if (ghEvent.payload.action === 'ready_for_review') ghEvent.payload.action = 'undrafted'
      return announce(bot, `${ghEvent.payload.sender.login} ${ghEvent.payload.action} pull request ${ghEvent.payload.pull_request.html_url}`)
    },
    'github:delete': (bot, ghEvent) => {
      return announce(bot, `${ghEvent.payload.sender.login} deleted branch ${ghEvent.payload.ref}`)
    },
    'github:issue_comment': (bot, ghEvent) => {
      let verb = ghEvent.payload.action
      if (verb === 'created') verb = 'added'
      verb += ' comment on '
      return announce(bot, `${ghEvent.payload.sender.login} ${verb} issue comment ${ghEvent.payload.issue.html_url}`)
    },
    'github:push': (bot, ghEvent) => {
      if (ghEvent.payload.commits.length === 0) return
      return announce(bot, `${ghEvent.payload.pusher.name} pushed ${ghEvent.payload.commits.length} commits to ${ghEvent.payload.ref} ${ghEvent.payload.compare}`)
    },
    'github:pull_request_review': (bot, ghEvent) => {
      return announce(bot, `${ghEvent.payload.sender.login} ${ghEvent.payload.action} code review: ${ghEvent.payload.review.state} ${ghEvent.payload.review.html_url}`)
    }
  }
}
<|endoftext|>


<commit_before>import mongoose from 'mongoose';
import '../db';
import { loadCategoryArray } from './utils';
import results from './results';

mongoose.Promise = global.Promise;

// FormTemplate + Form

const FIELD_TYPES = {
  area: 'lines',
  count: 'count',
  field: 'line',
  instructions: 'instructions',
  'multiple choice': 'choices',
  'multiple lines': 'lines',
  'single choice': 'choice',
  'single line': 'line',
};

function normalizeField(item, options) {
  item.oldId = item.id;
  item.type = FIELD_TYPES[item.field_type];
  item.value = item.unit_value;
  item.options = (options[item.id] || []).map((option) => {
    option.oldId = option.id;
    return option;
  });
  return item;
}

function normalizeFormTemplate(item, sections, sectionFields,
  formFields, options) {
  item.oldId = item.id;
  item.created = item.created_at;
  item.modified = item.updated_at;
  item.authenticate = item.authenticated;
  item.submitLabel = item.submit_label;
  item.sections = (sections[item.id] || []).map((section) => {
    section.oldId = section.id;
    section.fields = (sectionFields[section.id] || [])
      .map(field => normalizeField(field, options));
    return section;
  });
  if (formFields[item.id] && !sections[item.id]) {
    item.sections = [{
      fields: formFields[item.id].map(field => normalizeField(field, options)) }];
  }
  return item;
}

function normalizePayment(item, userIds) {
  item.oldId = item.id;
  item.created = item.created_at;
  item.modified = item.updated_at;
  item.amount = item.amount_cents / 100.0;
  if (item.received_notes) {
    item.notes = `${item.notes}${'\n'}${item.received_notes}`;
  }
  item.received = item.received_at;
  item.sent = item.sent_at;
  item.temporaryToken = item.verification_key;
  item.userId = userIds[item.user_id];
  return item;
}

function normalizeForm(item, fields, options, formTemplates, payments,
  userIds) {
  const template = formTemplates[item.form_id];

  // map field ids
  const templateFields = {}; // form_field.id => templateField
  template.sections.forEach((section) => {
    section.fields.forEach((field) => { templateFields[field.oldId] = field; });
  });

  item.oldId = item.id;
  item.created = item.created_at;
  item.modified = item.updated_at;

  item.fields = fields[item.id].map((field) => {
    const templateField = templateFields[field.form_field_id];
    if (!templateField) {
      console.log('!!!', field, item.oldId, template.oldId);
    }
    field.oldId = field.id;
    field.templateFieldId = templateField._id;

    if (options[field.id]) {
      // map options ids
      const templateOptions = {}; // filled_field_option.id => templateOption doc
      templateField.options.forEach((option) => {
        templateOptions[option.oldId] = option;
      });
      const logContext = () => {
        console.error('!!! item', item);
        console.error('!!! field', field);
        console.error('!!! templateField', templateField);
        console.error('!!! options', options[field.id]);
        console.error('!!! templateOptions', templateOptions);
      };

      if (templateField.type === 'choice') {
        const option = options[field.id][0];
        if (!templateOptions[option.form_field_option_id]) logContext();
        field.optionId = templateOptions[option.form_field_option_id]._id;
      } else {
        field.optionIds = options[field.id].map((option) => {
          if (!templateOptions[option.form_field_option_id]) logContext();
          return templateOptions[option.form_field_option_id]._id;
        });
      }
    }

    return field;
  });

  item.formTemplateId = template._id;
  if (item.payment_id) {
    item.paymentIds = [payments[item.payment_id]._id];
  }
  if (item.user_id) {
    item.userId = userIds[item.user_id];
  }
  return item;
}

export default function () {
  const FormTemplate = mongoose.model('FormTemplate');
  const User = mongoose.model('User');
  const Payment = mongoose.model('Payment');
  const Form = mongoose.model('Form');

  const formTemplates = {}; // oldId => doc
  const payments = {}; // oldId => doc
  const userIds = {}; // oldId => _id

  return Promise.resolve()
  .then(() => {
    const options = {}; // old field.id => [item ...]
    loadCategoryArray('form_field_options').forEach((item) => {
      if (!options[item.form_field_id]) {
        options[item.form_field_id] = [];
      }
      options[item.form_field_id].push(item);
    });

    const sectionFields = {}; // old form.id | form_section.id => [item, ...]
    const formFields = {}; // old form.id | form_section.id => [item, ...]
    loadCategoryArray('form_fields').forEach((item) => {
      if (item.form_section_id) {
        if (!sectionFields[item.form_section_id]) {
          sectionFields[item.form_section_id] = [];
        }
        sectionFields[item.form_section_id].push(item);
      } else {
        if (!formFields[item.form_id]) {
          formFields[item.form_id] = [];
        }
        formFields[item.form_id].push(item);
      }
    });

    const sections = {}; // old form.id => [item, ...]
    loadCategoryArray('form_sections').forEach((item) => {
      if (!sections[item.form_id]) {
        sections[item.form_id] = [];
      }
      sections[item.form_id].push(item);
    });

    const promises = [];
    const names = {}; // prevent duplicate names
    loadCategoryArray('forms').forEach((item) => {
      names[item.name] = item.id;
      promises.push(FormTemplate.findOne({ oldId: item.id }).exec()
      .then((formTemplate) => {
        if (formTemplate) {
          return results.skipped('FormTemplate', formTemplate);
        }
        while (names[item.name] && names[item.name] !== item.id) {
          item.name = `${item.name} 2`;
        }
        item = normalizeFormTemplate(item, sections, sectionFields,
          formFields, options);
        formTemplate = new FormTemplate(item);
        return formTemplate.save()
        .then(formTemplateSaved => results.saved('FormTemplate', formTemplateSaved))
        .catch(error => results.errored('FormTemplate', formTemplate, error));
      })
      .then((formTemplate) => { formTemplates[item.id] = formTemplate; }));
    });
    return Promise.all(promises);
  })
  .then(() => {
    // load Users so we can map ids
    return User.find({}).select('oldId').exec()
    .then((users) => {
      users.forEach((user) => {
        if (user.oldId) {
          userIds[user.oldId] = user._id;
        }
      });
    });
  })
  .then(() => {
    // User ids have been mapped, now do payments
    const promises = [];
    loadCategoryArray('payments').forEach((item) => {
      promises.push(Payment.findOne({ oldId: item.id }).exec()
      .then((payment) => {
        if (payment) {
          return results.skipped('Payment', payment);
        }
        item = normalizePayment(item, userIds);
        payment = new Payment(item);
        return payment.save()
        .then(paymentSaved => results.saved('Payment', paymentSaved))
        .catch(error => results.errored('Payment', payment, error));
      })
      .then((payment) => { payments[item.id] = payment; }));
    });
    return Promise.all(promises);
  })
  .then(() => {
    // Form templates and payments have been saved, now do forms

    const options = {}; // old filled_field.id => [item ...]
    loadCategoryArray('filled_field_options').forEach((item) => {
      if (!options[item.filled_field_id]) {
        options[item.filled_field_id] = [];
      }
      options[item.filled_field_id].push(item);
    });

    const fields = {}; // old filled_form.id => [item, ...]
    loadCategoryArray('filled_fields').forEach((item) => {
      if (!fields[item.filled_form_id]) {
        fields[item.filled_form_id] = [];
      }
      fields[item.filled_form_id].push(item);
    });

    const promises = [];
    loadCategoryArray('filled_forms').forEach((item) => {
      promises.push(Form.findOne({ oldId: item.id }).exec()
      .then((form) => {
        if (form) {
          return results.skipped('Form', form);
        }
        item = normalizeForm(item, fields, options, formTemplates, payments,
          userIds);
        form = new Form(item);
        return form.save()
        .then(formSaved => results.saved('Form', formSaved))
        .catch(error => results.errored('Form', form, error));
      }));
    });
    return Promise.all(promises);
  })
  .then(() => console.log('!!! forms done'))
  .catch(error => console.error('!!! forms catch', error, error.stack));
}
<commit_msg>Removed extraneous logging message.<commit_after>import mongoose from 'mongoose';
import '../db';
import { loadCategoryArray } from './utils';
import results from './results';

mongoose.Promise = global.Promise;

// FormTemplate + Form

const FIELD_TYPES = {
  area: 'lines',
  count: 'count',
  field: 'line',
  instructions: 'instructions',
  'multiple choice': 'choices',
  'multiple lines': 'lines',
  'single choice': 'choice',
  'single line': 'line',
};

function normalizeField(item, options) {
  item.oldId = item.id;
  item.type = FIELD_TYPES[item.field_type];
  item.value = item.unit_value;
  item.options = (options[item.id] || []).map((option) => {
    option.oldId = option.id;
    return option;
  });
  return item;
}

function normalizeFormTemplate(item, sections, sectionFields,
  formFields, options) {
  item.oldId = item.id;
  item.created = item.created_at;
  item.modified = item.updated_at;
  item.authenticate = item.authenticated;
  item.submitLabel = item.submit_label;
  item.sections = (sections[item.id] || []).map((section) => {
    section.oldId = section.id;
    section.fields = (sectionFields[section.id] || [])
      .map(field => normalizeField(field, options));
    return section;
  });
  if (formFields[item.id] && !sections[item.id]) {
    item.sections = [{
      fields: formFields[item.id].map(field => normalizeField(field, options)) }];
  }
  return item;
}

function normalizePayment(item, userIds) {
  item.oldId = item.id;
  item.created = item.created_at;
  item.modified = item.updated_at;
  item.amount = item.amount_cents / 100.0;
  if (item.received_notes) {
    item.notes = `${item.notes}${'\n'}${item.received_notes}`;
  }
  item.received = item.received_at;
  item.sent = item.sent_at;
  item.temporaryToken = item.verification_key;
  item.userId = userIds[item.user_id];
  return item;
}

function normalizeForm(item, fields, options, formTemplates, payments,
  userIds) {
  const template = formTemplates[item.form_id];

  // map field ids
  const templateFields = {}; // form_field.id => templateField
  template.sections.forEach((section) => {
    section.fields.forEach((field) => { templateFields[field.oldId] = field; });
  });

  item.oldId = item.id;
  item.created = item.created_at;
  item.modified = item.updated_at;

  item.fields = fields[item.id].map((field) => {
    const templateField = templateFields[field.form_field_id];
    field.oldId = field.id;
    field.templateFieldId = templateField._id;

    if (options[field.id]) {
      // map options ids
      const templateOptions = {}; // filled_field_option.id => templateOption doc
      templateField.options.forEach((option) => {
        templateOptions[option.oldId] = option;
      });
      const logContext = () => {
        console.error('!!! item', item);
        console.error('!!! field', field);
        console.error('!!! templateField', templateField);
        console.error('!!! options', options[field.id]);
        console.error('!!! templateOptions', templateOptions);
      };

      if (templateField.type === 'choice') {
        const option = options[field.id][0];
        if (!templateOptions[option.form_field_option_id]) logContext();
        field.optionId = templateOptions[option.form_field_option_id]._id;
      } else {
        field.optionIds = options[field.id].map((option) => {
          if (!templateOptions[option.form_field_option_id]) logContext();
          return templateOptions[option.form_field_option_id]._id;
        });
      }
    }

    return field;
  });

  item.formTemplateId = template._id;
  if (item.payment_id) {
    item.paymentIds = [payments[item.payment_id]._id];
  }
  if (item.user_id) {
    item.userId = userIds[item.user_id];
  }
  return item;
}

export default function () {
  const FormTemplate = mongoose.model('FormTemplate');
  const User = mongoose.model('User');
  const Payment = mongoose.model('Payment');
  const Form = mongoose.model('Form');

  const formTemplates = {}; // oldId => doc
  const payments = {}; // oldId => doc
  const userIds = {}; // oldId => _id

  return Promise.resolve()
  .then(() => {
    const options = {}; // old field.id => [item ...]
    loadCategoryArray('form_field_options').forEach((item) => {
      if (!options[item.form_field_id]) {
        options[item.form_field_id] = [];
      }
      options[item.form_field_id].push(item);
    });

    const sectionFields = {}; // old form.id | form_section.id => [item, ...]
    const formFields = {}; // old form.id | form_section.id => [item, ...]
    loadCategoryArray('form_fields').forEach((item) => {
      if (item.form_section_id) {
        if (!sectionFields[item.form_section_id]) {
          sectionFields[item.form_section_id] = [];
        }
        sectionFields[item.form_section_id].push(item);
      } else {
        if (!formFields[item.form_id]) {
          formFields[item.form_id] = [];
        }
        formFields[item.form_id].push(item);
      }
    });

    const sections = {}; // old form.id => [item, ...]
    loadCategoryArray('form_sections').forEach((item) => {
      if (!sections[item.form_id]) {
        sections[item.form_id] = [];
      }
      sections[item.form_id].push(item);
    });

    const promises = [];
    const names = {}; // prevent duplicate names
    loadCategoryArray('forms').forEach((item) => {
      names[item.name] = item.id;
      promises.push(FormTemplate.findOne({ oldId: item.id }).exec()
      .then((formTemplate) => {
        if (formTemplate) {
          return results.skipped('FormTemplate', formTemplate);
        }
        while (names[item.name] && names[item.name] !== item.id) {
          item.name = `${item.name} 2`;
        }
        item = normalizeFormTemplate(item, sections, sectionFields,
          formFields, options);
        formTemplate = new FormTemplate(item);
        return formTemplate.save()
        .then(formTemplateSaved => results.saved('FormTemplate', formTemplateSaved))
        .catch(error => results.errored('FormTemplate', formTemplate, error));
      })
      .then((formTemplate) => { formTemplates[item.id] = formTemplate; }));
    });
    return Promise.all(promises);
  })
  .then(() => {
    // load Users so we can map ids
    return User.find({}).select('oldId').exec()
    .then((users) => {
      users.forEach((user) => {
        if (user.oldId) {
          userIds[user.oldId] = user._id;
        }
      });
    });
  })
  .then(() => {
    // User ids have been mapped, now do payments
    const promises = [];
    loadCategoryArray('payments').forEach((item) => {
      promises.push(Payment.findOne({ oldId: item.id }).exec()
      .then((payment) => {
        if (payment) {
          return results.skipped('Payment', payment);
        }
        item = normalizePayment(item, userIds);
        payment = new Payment(item);
        return payment.save()
        .then(paymentSaved => results.saved('Payment', paymentSaved))
        .catch(error => results.errored('Payment', payment, error));
      })
      .then((payment) => { payments[item.id] = payment; }));
    });
    return Promise.all(promises);
  })
  .then(() => {
    // Form templates and payments have been saved, now do forms

    const options = {}; // old filled_field.id => [item ...]
    loadCategoryArray('filled_field_options').forEach((item) => {
      if (!options[item.filled_field_id]) {
        options[item.filled_field_id] = [];
      }
      options[item.filled_field_id].push(item);
    });

    const fields = {}; // old filled_form.id => [item, ...]
    loadCategoryArray('filled_fields').forEach((item) => {
      if (!fields[item.filled_form_id]) {
        fields[item.filled_form_id] = [];
      }
      fields[item.filled_form_id].push(item);
    });

    const promises = [];
    loadCategoryArray('filled_forms').forEach((item) => {
      promises.push(Form.findOne({ oldId: item.id }).exec()
      .then((form) => {
        if (form) {
          return results.skipped('Form', form);
        }
        item = normalizeForm(item, fields, options, formTemplates, payments,
          userIds);
        form = new Form(item);
        return form.save()
        .then(formSaved => results.saved('Form', formSaved))
        .catch(error => results.errored('Form', form, error));
      }));
    });
    return Promise.all(promises);
  })
  .then(() => console.log('!!! forms done'))
  .catch(error => console.error('!!! forms catch', error, error.stack));
}
<|endoftext|>