if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(elt /*, from*/)
  {
    var len = this.length >>> 0;

    var from = Number(arguments[1]) || 0;
    from = (from < 0)
         ? Math.ceil(from)
         : Math.floor(from);
    if (from < 0)
      from += len;

    for (; from < len; from++)
    {
      if (from in this &&
          this[from] === elt)
        return from;
    }
    return -1;
  };
}

if (!Array.prototype.lastIndexOf)
{
  Array.prototype.lastIndexOf = function(elt /*, from*/)
  {
    var len = this.length;

    var from = Number(arguments[1]);
    if (isNaN(from))
    {
      from = len - 1;
    }
    else
    {
      from = (from < 0)
           ? Math.ceil(from)
           : Math.floor(from);
      if (from < 0)
        from += len;
      else if (from >= len)
        from = len - 1;
    }

    for (; from > -1; from--)
    {
      if (from in this &&
          this[from] === elt)
        return from;
    }
    return -1;
  };
}

if (!Array.prototype.every)
{
  Array.prototype.every = function(fun /*, thisp*/)
  {
    var len = this.length >>> 0;
    if (typeof fun != "function")
      throw new TypeError();

    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this &&
          !fun.call(thisp, this[i], i, this))
        return false;
    }

    return true;
  };
}

if (!Array.prototype.filter)
{
  Array.prototype.filter = function(fun /*, thisp*/)
  {
    var len = this.length >>> 0;
    if (typeof fun != "function")
      throw new TypeError();

    var res = new Array();
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this)
      {
        var val = this[i]; // in case fun mutates this
        if (fun.call(thisp, val, i, this))
          res.push(val);
      }
    }

    return res;
  };
}

if (!Array.prototype.forEach)
{
  Array.prototype.forEach = function(fun /*, thisp*/)
  {
    var len = this.length >>> 0;
    if (typeof fun != "function")
      throw new TypeError();

    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this)
        fun.call(thisp, this[i], i, this);
    }
  };
}


if (!Array.prototype.map)
{
  Array.prototype.map = function(fun /*, thisp*/)
  {
    var len = this.length >>> 0;
    if (typeof fun != "function")
      throw new TypeError();

    var res = new Array(len);
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this)
        res[i] = fun.call(thisp, this[i], i, this);
    }

    return res;
  };
}

if (!Array.prototype.some)
{
  Array.prototype.some = function(fun /*, thisp*/)
  {
    var i = 0,
        len = this.length >>> 0;

    if (typeof fun != "function")
      throw new TypeError();

    var thisp = arguments[1];
    for (; i < len; i++)
    {
      if (i in this &&
          fun.call(thisp, this[i], i, this))
        return true;
    }

    return false;
  };
}

if (!Array.prototype.reduce)
{
  Array.prototype.reduce = function(fun /*, initial*/)
  {
    var len = this.length >>> 0;
    if (typeof fun != "function")
      throw new TypeError();

    // no value to return if no initial value and an empty array
    if (len == 0 && arguments.length == 1)
      throw new TypeError();

    var i = 0;
    if (arguments.length >= 2)
    {
      var rv = arguments[1];
    }
    else
    {
      do
      {
        if (i in this)
        {
          rv = this[i++];
          break;
        }

        // if array contains no values, no initial value to return
        if (++i >= len)
          throw new TypeError();
      }
      while (true);
    }

    for (; i < len; i++)
    {
      if (i in this)
        rv = fun.call(null, rv, this[i], i, this);
    }

    return rv;
  };
}

if (!Array.prototype.reduceRight)
{
  Array.prototype.reduceRight = function(fun /*, initial*/)
  {
    var len = this.length >>> 0;
    if (typeof fun != "function")
      throw new TypeError();

    // no value to return if no initial value, empty array
    if (len == 0 && arguments.length == 1)
      throw new TypeError();

    var i = len - 1;
    if (arguments.length >= 2)
    {
      var rv = arguments[1];
    }
    else
    {
      do
      {
        if (i in this)
        {
          rv = this[i--];
          break;
        }

        // if array contains no values, no initial value to return
        if (--i < 0)
          throw new TypeError();
      }
      while (true);
    }

    for (; i >= 0; i--)
    {
      if (i in this)
        rv = fun.call(null, rv, this[i], i, this);
    }

    return rv;
  };
}


Array.prototype.extend = function (arr)
{
    for (var i=0; i<arr.length; i++)
    {
        this.push(arr[i])
    }
}

Array.create = function (obj)
{
    return Array.prototype.slice.call(obj, 0)
}


Array.zip = function ()
{
    var zipped = []
    
    for (var i = 0; i < arguments[0].length; i++)
    {
        var r = []
        for (var j = 0; j < arguments.length; j++)
        {
            r.push(arguments[j][i])
        }
        zipped.push(r)
    }
    
    return zipped
}


Array.generate = function (size, fn)
{
    var a = []
    
    for (var i=0; i<size; i++)
    {
        a.push(fn(i))
    }
    
    return a
}


Function.prototype.bind = function ()
{
    var slice = Array.prototype.slice
    var args = slice.call(arguments, 0)
    var fn = this
    var obj = args.shift()
    
    return function ()
    {
        var args1 = slice.call(args, 0)
        var args2 = slice.call(arguments, 0)
        var l1 = args1.length, l2 = args2.length
        while (l2--)
        {
            args1[l1 + l2] = args2[l2]
        }
        return fn.apply(obj, args1)
    }
}

Function.prototype.loop = function (times)
{
    for (var i=0; i<times; i++)
    {
        this(i)
    }
}


String.prototype.truncate = function (maxlen)
{
    if (this.length <= maxlen)
    {
        return this
    }
    
    return this.substr(0,maxlen-3)+'...'
}


function E()
{
    var e = $(document.createElement(arguments[0]))
    
    if (arguments.length > 1)
    {
        var args = Array.prototype.slice.call(arguments, 0)
        args.shift()
        
        if (typeof args[0] == 'string')
        {
            e.addClass(args.shift())
        }
        
        for (var i=0; i<args.length; i++)
        {
            if (args[i])
            {
                if (!args[i].jquery && typeof args[i].length != "undefined")
                {
                    args[i].forEach(function (_e)
                    {
                        e.append(_e)
                    })
                }
                else
                {
                    e.append(args[i])
                }
            }
        }
    }
    
    return e
}


function T(s)
{
    return $(document.createTextNode(s))
}


$.fn.appendlist = function (elms)
{
    if (elms.length > 0)
    {
        var frag = document.createDocumentFragment()
        elms.forEach(function (e)
        {
            if (e)
            {
                if (e.jquery)
                {
                    e = e.get(0)
                }
                frag.appendChild(e)
            }
        })
        this.get(0).appendChild(frag)
    }
    return this
}


var Event = function ()
{
    this.listeners = [];
}
Event.prototype = {
    bind: function(l)
    {
        if (this.listeners.indexOf(l) < 0)
        {
            this.listeners.push(l)
        }
    },
    fire: function ()
    {
        var args = Array.prototype.slice.call(arguments, 0)
        $.each(this.listeners, function ()
        {
            this.apply(null, args)
        })
    }
}