//function joo$prepareWindow(window) { with(window) {
if (typeof document.getElementsByTagNameNS!="function") {
  document.getElementsByTagNameNS = function(namespaceURI, localName) {
    var elements = this.getElementsByTagName(localName);
    var i=0;
    while (i<elements.length) {
      if (elements[i].scopeName=="HTML") { // TODO: mapping from namespaceURI to scopeName!
        elements.splice(i,1);
      } else {
        ++i;
      }
    }
    return elements;
  }
}

if (typeof Node=="undefined") {
  window.Node = {
    ELEMENT_NODE: 1,
    ATTRIBUTE_NODE: 2,
    TEXT_NODE: 3
    // TODO
  };
}

Function.prototype.bind = function(object) {
  var fn = this;
  return function() {
    return fn.apply(object,arguments);
  };
}

RegExp.compile = typeof RegExp.prototype.compile=="function" ?
 (function(regExpStr, options) {
    var r = new RegExp();
    if (!regExpStr) {
      return this;
    }
    r.compile(regExpStr, options);
    return r;
  }) :
 (function(regExpStr, options) {
   return new RegExp(regExpStr, options);
 });
if (typeof Array.prototype.forEach!="function") {
  Array.prototype.forEach = function(fn, bind){
    for (var i = 0, j = this.length; i < j; i++) {
      if (i in this) {
        fn.call(bind, this[i], i, this);
      }
    }
  };
}

if (typeof Array.prototype.map!="function") {
  Array.prototype.map = function(fn, bind){
    var results = [];
    for (var i = 0, j = this.length; i < j; i++) results[i] = fn.call(bind, this[i], i, this);
    return results;
  };
}

if (typeof Array.prototype.filter!="function") {
  Array.prototype.filter = function(fn, bind) {
    var len = this.length;
    var res = [];
    for (var i = 0; i < len; i++) {
      if (i in this) {
        var val = this[i];
        if (fn.call(bind, this[i], i, this)) {
          res.push(val);
        }
      }
    }

    return res;
  };
}

if (typeof window.addEventListener!="function") {
  // we are in IE:
  window.addEventListener = function(eventName, listener, capture) {
    var attachee = this;
    //noinspection FallthroughInSwitchStatementJS
    if (eventName=="focus" || eventName=="blur") {
      eventName = eventName=="focus" ? "focusin" : "focusout";
      attachee = this.document;
    }
    attachee.attachEvent("on"+eventName, function() {
      window.event.preventDefault = function() { this.returnValue = false; };
      return listener(window.event);
    });
  };
}

Array.prototype.broadcast = function(methodName, parameter1, parameter2) {
  for (var i=0; i < this.length; ++i) {
    this[i][methodName](parameter1, parameter2);
  }
}

Array.prototype.remove=function(s){
  for(var i=0; i < this.length; i++){
    if (s==this[i]) {
      this.splice(i, 1);
      return true;
    }
  }
  return false;
}

if (typeof Array.prototype.indexOf!="function") {
  Array.prototype.indexOf = function(item, from){
    var len = this.length;
    var useEquals = typeof item.equals == "function" && item.equals!==joo.lang.JOObject.prototype.equals;
    for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
      if (item === this[i] || useEquals && item.equals(this[i]))
        return i;
    }
    return -1;
  }

}

Array.prototype.contains = function(element) {
  return this.indexOf(element)!=-1;
}

Array.prototype.indexOfEquals = function(item, from){
  var len = this.length;
  var useEquals = typeof item.equals == "function";
  for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
    if (item === this[i] || useEquals && item.equals(this[i]))
      return i;
  }
  return -1;
}

Array.prototype.containsEquals = function(element) {
  return this.indexOfEquals(element)!=-1;
}

Array.prototype.binarySearch = function(element) {
  var left = -1,
      right = this.length;
  while (right - left > 1) {
    var mid = (left + right) >>> 1;
    var comp = this[mid].compareTo(element);
    if (comp==0) {
      return mid;
    } else if(comp < 0) {
      left = mid;
    } else {
      right = mid;
    }
  }
  return -right-1;
}

Math.sgn = function(number) {
  return number<0 ? -1 : number>0 ? 1 : 0;
}

Number.prototype.toString = (function() {
  var oldToString = Number.prototype.toString;
  var ZEROS = "0000000000";
  return function(radix, digits) {
    var result = oldToString.call(this, radix || 10);
    var zeros = digits-result.length;
    if (zeros<=0)
      return result;
    return ZEROS.substring(0,zeros)+result;
  }
})();


if (typeof MouseEvent!="undefined") {
    HTMLTableCellElement.prototype.super$setAttribute = HTMLTableCellElement.prototype.setAttribute;
    HTMLTableCellElement.prototype.setAttribute = function(name, value) {
      return this.super$setAttribute(name.toLowerCase(), value);
    };
    window.attachEvent = Element.prototype.attachEvent = function(eventName, handler) {
	  var self = this;
	  this.addEventListener(eventName.substring(2), function(event) {
	    self.ownerDocument.defaultView.event = event;
		handler();
	  }, false);
	};
  Event.prototype.__defineSetter__("returnValue", function(val) { if (val==false) this.preventDefault(); });
	Event.prototype.__defineGetter__("srcElement", function() { return this.target; });
	MouseEvent.prototype.__defineGetter__("fromElement", function() {
	  return this.type=="mouseover" ? this.relatedTarget : this.target;
	});
	MouseEvent.prototype.__defineGetter__("toElement", function() {
	  return this.type=="mouseover" ? this.target : this.relatedTarget;
	});
}

if (typeof window.KeyEvent=="undefined") {
  window.KeyEvent = {
    DOM_VK_CANCEL: 3,
    DOM_VK_HELP: 6,
    DOM_VK_BACK_SPACE: 8,
    DOM_VK_TAB: 9,
    DOM_VK_CLEAR: 12,
    DOM_VK_RETURN: 13,
    DOM_VK_ENTER: 14,
    DOM_VK_SHIFT: 16,
    DOM_VK_CONTROL: 17,
    DOM_VK_ALT: 18,
    DOM_VK_PAUSE: 19,
    DOM_VK_CAPS_LOCK: 20,
    DOM_VK_ESCAPE: 27,
    DOM_VK_SPACE: 32,
    DOM_VK_PAGE_UP: 33,
    DOM_VK_PAGE_DOWN: 34,
    DOM_VK_END: 35,
    DOM_VK_HOME: 36,
    DOM_VK_LEFT: 37,
    DOM_VK_UP: 38,
    DOM_VK_RIGHT: 39,
    DOM_VK_DOWN: 40,
    DOM_VK_PRINTSCREEN: 44,
    DOM_VK_INSERT: 45,
    DOM_VK_DELETE: 46,
    DOM_VK_0: 48,
    DOM_VK_1: 49,
    DOM_VK_2: 50,
    DOM_VK_3: 51,
    DOM_VK_4: 52,
    DOM_VK_5: 53,
    DOM_VK_6: 54,
    DOM_VK_7: 55,
    DOM_VK_8: 56,
    DOM_VK_9: 57,
    DOM_VK_SEMICOLON: 59,
    DOM_VK_EQUALS: 61,
    DOM_VK_A: 65,
    DOM_VK_B: 66,
    DOM_VK_C: 67,
    DOM_VK_D: 68,
    DOM_VK_E: 69,
    DOM_VK_F: 70,
    DOM_VK_G: 71,
    DOM_VK_H: 72,
    DOM_VK_I: 73,
    DOM_VK_J: 74,
    DOM_VK_K: 75,
    DOM_VK_L: 76,
    DOM_VK_M: 77,
    DOM_VK_N: 78,
    DOM_VK_O: 79,
    DOM_VK_P: 80,
    DOM_VK_Q: 81,
    DOM_VK_R: 82,
    DOM_VK_S: 83,
    DOM_VK_T: 84,
    DOM_VK_U: 85,
    DOM_VK_V: 86,
    DOM_VK_W: 87,
    DOM_VK_X: 88,
    DOM_VK_Y: 89,
    DOM_VK_Z: 90,
    DOM_VK_CONTEXT_MENU: 93,
    DOM_VK_NUMPAD0: 96,
    DOM_VK_NUMPAD1: 97,
    DOM_VK_NUMPAD2: 98,
    DOM_VK_NUMPAD3: 99,
    DOM_VK_NUMPAD4: 100,
    DOM_VK_NUMPAD5: 101,
    DOM_VK_NUMPAD6: 102,
    DOM_VK_NUMPAD7: 103,
    DOM_VK_NUMPAD8: 104,
    DOM_VK_NUMPAD9: 105,
    DOM_VK_MULTIPLY: 106,
    DOM_VK_ADD: 107,
    DOM_VK_SEPARATOR: 108,
    DOM_VK_SUBTRACT: 109,
    DOM_VK_DECIMAL: 110,
    DOM_VK_DIVIDE: 111,
    DOM_VK_F1: 112,
    DOM_VK_F2: 113,
    DOM_VK_F3: 114,
    DOM_VK_F4: 115,
    DOM_VK_F5: 116,
    DOM_VK_F6: 117,
    DOM_VK_F7: 118,
    DOM_VK_F8: 119,
    DOM_VK_F9: 120,
    DOM_VK_F10: 121,
    DOM_VK_F11: 122,
    DOM_VK_F12: 123,
    DOM_VK_F13: 124,
    DOM_VK_F14: 125,
    DOM_VK_F15: 126,
    DOM_VK_F16: 127,
    DOM_VK_F17: 128,
    DOM_VK_F18: 129,
    DOM_VK_F19: 130,
    DOM_VK_F20: 131,
    DOM_VK_F21: 132,
    DOM_VK_F22: 133,
    DOM_VK_F23: 134,
    DOM_VK_F24: 135,
    DOM_VK_NUM_LOCK: 144,
    DOM_VK_SCROLL_LOCK: 145,
    DOM_VK_COMMA: 188,
    DOM_VK_PERIOD: 190,
    DOM_VK_SLASH: 191,
    DOM_VK_BACK_QUOTE: 192,
    DOM_VK_OPEN_BRACKET: 219,
    DOM_VK_BACK_SLASH: 220,
    DOM_VK_CLOSE_BRACKET: 221,
    DOM_VK_QUOTE: 222,
    DOM_VK_META: 224
  };
}
//}}

//joo$prepareWindow(window);
Function.prototype.getName = typeof Function.prototype.name=="string"
? (function getName() { return this.name; })
: (function() {
  var nameRE = /function +([a-zA-Z\$_][a-zA-Z\$_0-9]*) *\(/;
  return (function getName() {
    if (!("name" in this)) {
      var matches = nameRE.exec(this.toString());
      var name = matches ? matches[1] : "";
      if (name=="anonymous")
        name = "";
      this.name = name;
    }
    return this.name;
  });
}());

(function() {
  function initFields(privateBean, publicBean, fieldNames) {
    for (var i=0; i<fieldNames.length; ++i) {
      var fieldName = fieldNames[i];
      //alert("init field: "+fieldName);
      var bean = publicBean[fieldName] ? publicBean : privateBean;
      bean[fieldName] = bean[fieldName]();
    }
  }
  function createPackage(packageName) {
    var $package = window;
    if (packageName) {
      var packageParts = packageName.split(".");
      for (var i=0; i<packageParts.length; ++i) {
        var subpackage = $package[packageParts[i]];
        if (!subpackage) {
          subpackage = new Package();
          $package[packageParts[i]] = subpackage;
        }
        $package = subpackage;
      }
    }
    return $package;
  }
  function isFunction(object) {
    return typeof object=="function" && object.constructor!==RegExp;
  }
  function createMethod(object) {
    for (var name in object) {
      return setFunctionName(object[name], name);
    }
  }
  function createEmptyConstructor($prototype) {
    var $constructor = new Function();
    $constructor.prototype =  $prototype;
    return $constructor;
  };
  function createDefaultConstructor(superName) {
    return (function $DefaultConstructor() {
      this[superName].apply(this,arguments);
    });
  }
  function setFunctionName(theFunction, name) {
    theFunction.getName = function() { return name; };
    return theFunction;
  }
  function registerPrivateMember(privateStatic, classPrefix, memberName) {
    var privateMemberName = classPrefix+memberName;
    privateStatic["_"+memberName] = privateMemberName;
    return privateMemberName;
  }
  function createGetClass($constructor) {
    return (function Object$getClass() { return $constructor; });
  }
  var ClassDescription = (function() {
    var ClassDescription$static = {
      // static members:
      PENDING: 0,
      PREPARING: 1,
      PREPARED: 2,
      INITIALIZING: 3,
      INITIALIZED: 4,
      classDescriptions: {},
      pendingClassDescriptions: {},
      getClassDescription: function(fullClassName) {
          return this.classDescriptions[fullClassName];
      },
      waitForSuper: function(classDef) {
        var pendingCDs = this.pendingClassDescriptions[classDef.$extends];
        if (!pendingCDs) {
          pendingCDS = this.pendingClassDescriptions[classDef.$extends] = [];
        }
        pendingCDS.push(classDef);
      },
      prepareSubclasses: function(classDef) {
        var pendingCDS = this.pendingClassDescriptions[classDef.fullClassName];
        if (pendingCDS) {
          delete this.pendingClassDescriptions[classDef.fullClassName];
          for (var c=0; c<pendingCDS.length; ++c) {
            pendingCDS[c].prepare();
          }
        }
      }
    };
    // constructor:
    function ClassDescription(classDef) {
      for (var m in classDef) {
        this[m] = classDef[m];
      }
      this.fullClassName = this.$package + "." + this.$class;
      ClassDescription$static.classDescriptions[this.fullClassName] = this;
      this.prepare();
    }
    with(ClassDescription$static) {
      // instance members:
      ClassDescription.prototype = {
        fullClassName: undefined,
        $extends: "joo.lang.JOObject",
        level: undefined,
        state: PENDING,
        superClassDescription: undefined,
        $constructor: undefined,
        Public: undefined,
        Static: undefined,
        getStatic: undefined,
        /**
         * Prepares this class to be used by constructor, by accessing a static member, or as a super class.
         * The actual class loading is done when any of this three methods is called.
         */
        prepare: function() {
          if (this.state===PREPARING)
            throw new Error("cyclic usages between classes "+this.fullClassName+" and "+this.superClassDescription.fullClassName+".");
          if (this.state!==PENDING)
            return;
          if (this.fullClassName=="joo.lang.JOObject") {
            this.$extends = null;
            this.superClassDescription = null;
          } else {
            this.superClassDescription = getClassDescription(this.$extends);
            if (!this.superClassDescription || this.superClassDescription.state==PENDING) {
              // super class not yet loaded, stay pending and wait for super class:
              waitForSuper(this);
              return;
            }
          }
          this.state = PREPARING;
          // Only do the minimal setup to allow a preliminary, initializing public constructor and static getter,
          // and to allow subclasses to plug their constructor into this class.
          // create preliminary constructor and static getter that initialize before delegating to the real ones:
          this.level = this.superClassDescription ? this.superClassDescription.level + 1 : 0;
          var classDescription = this;
          this.$constructor = function() {
            classDescription.initialize();
            classDescription.$constructor.apply(this,arguments);
          };
          setFunctionName(this.$constructor, this.fullClassName);
          if (this.superClassDescription) {
            this.$constructor.prototype = new (this.superClassDescription.Public)();
          }
          // TODO: only if not final:
          this.Public = createEmptyConstructor(this.$constructor.prototype);
          // static part:
          this.Static = this.superClassDescription
            ? createEmptyConstructor(new (this.superClassDescription.Static)())
            : new Function();
          this.getStatic = function() {
            classDescription.initialize();
            return classDescription.getStatic();
          }
          // TODO: only if public:
          this.$package = createPackage(this.$package);
          this.$package[this.$class] = this.$constructor;
          this.$package[this.$class+"_"] = this.getStatic;

          this.state = PREPARED;
          prepareSubclasses(this);
        },
        /**
         * Initializes this class by finishing the class setup and then invoking all static initializers.
         */
        initialize: function() {
          if (this.state!==PREPARED)
            return;
          this.state = INITIALIZING;
          // finish object structure setup of this class:
          // public part: avoid recursion!
          this.$package[this.$class+"_"] = this.getStatic = undefined;
          this.$package[this.$class] = this.$constructor = undefined;

          // private part of the object structure:
          var classPrefix = this.level; // + "$";
          var fieldsWithInitializer = [];
          var classDescription = this;
          if (this.superClassDescription) {
            var superName = classPrefix+"super";
            this.Public.prototype[superName] = function $super() {
              delete this[superName]; // only allow to call $super once!
              classDescription.superClassDescription.$constructor.apply(this,arguments);
              initFields(null, this, fieldsWithInitializer);
            };
          }
          // static part:
          this.$package[this.$class+"_"] = this.getStatic = function() {
            // overwrite, this time without initializing:
            return classDescription.Static.prototype;
          };
          var privateStatic = new (this.Static)();
          privateStatic._super = superName;

          if (this.superClassDescription) {
            // init super class:
            this.superClassDescription.initialize();
          }

          // evaluate $members, transfer members into the prepared objects:

          // Define a mapping to efficiently find the right prototype object to store a member,
          // depending on its modifiers.
          // Note: As long as "protected" is not implemented, treat it like "public".
          var targetMap = {
            $this: {
              fieldsWithInitializer: fieldsWithInitializer,
              $public: this.Public.prototype,
              $protected: this.Public.prototype,
              $private: this.Public.prototype
            },
            $static: {
              fieldsWithInitializer: [],
              $public: this.Static.prototype,
              $protected: this.Static.prototype,
              $private: privateStatic
            }
          };
          if (isFunction(this.$members)) {
            var memberDeclarations = this.$members(privateStatic);
            var i=0;
            while (i<memberDeclarations.length) {
              var memberKey = "$this"; // default: not static
              var visibility = "$public"; // default: public visibility
              var members = memberDeclarations[i++];
              if (members===undefined) {
                continue;
              }
              var memberType = "function";
              var modifiers;
              if (typeof members=="string") {
                modifiers = members.split(" ");
                for (var j=0; j<modifiers.length; ++j) {
                  var modifier = modifiers[j];
                  if (modifier=="static") {
                    memberKey = "$static";
                  } else if (modifier=="private" || modifier=="public" || modifier=="protected") {
                    visibility = "$"+modifier;
                  } else if (modifier=="var" || modifier=="const") {
                    memberType = modifier;
                  } else if (modifier=="override") {
                    // so far: igrnoe. TODO: enable super-call!
                  } else {
                    throw new Error("Unknown modifier '"+modifier+"'.");
                  }
                }
                if (i>=memberDeclarations.length) {
                  throw new Error("Member expected after modifiers "+modifiers.join(" "));
                }
                members = memberDeclarations[i++];
              } else {
                modifiers = [];
              }
              var target = targetMap[memberKey][visibility];
              //document.writeln("defining "+modifiers.join(" ")+" member(s):");
	      var memberName;
	      if (memberType=="function") {
                if (typeof members=="object") {
                  members = createMethod(members);
                }
                memberName = members.getName();
                if (memberName==this.$class) {
                  this.$constructor = members;
                } else if (memberKey=="$this") {
                  if (visibility=="$private") {
                    memberName = registerPrivateMember(privateStatic, classPrefix, memberName);
                    setFunctionName(members, memberName);
                  } else if (isFunction(target[memberName])) {
                    // Found overriding! Store super method as private method delegate for super access:
                    this.Public.prototype[registerPrivateMember(privateStatic, classPrefix, memberName)] = target[memberName];
                  }
                }
                target[memberName] = members;
              } else {
                var targetFieldsWithInitializer = targetMap[memberKey].fieldsWithInitializer;
                for (memberName in members) {
                  var member = members[memberName];
                  if (memberKey=="$this" && visibility=="$private") {
                    memberName = registerPrivateMember(privateStatic, classPrefix, memberName);
                  }
                  target[memberName] = member;
                  if (isFunction(member)) {
                    var initFunctionName =  member.getName();
                    if (initFunctionName=="" || initFunctionName.indexOf('$')!=-1) {
                      targetFieldsWithInitializer.push(memberName);
                    }
                  }
                }
              }
            }
          }
          if (!this.$constructor) {
            this.$constructor = createDefaultConstructor(superName);
          }
          setFunctionName(this.$constructor, this.fullClassName);
          this.$constructor.prototype = this.Public.prototype;
          this.Public.prototype.getClass = createGetClass(this.$constructor);
          // TODO: constructor visibility!
          this.$package[this.$class] = this.$constructor;
          // init static fields with initializer:
          initFields(privateStatic, this.Static.prototype, targetMap.$static.fieldsWithInitializer);
        }
      };
    }
    ClassDescription.$static = ClassDescription$static;
    return ClassDescription;
  })();
  function Package() { }
  window.joo = new Package();
  window.joo.Class = {};
  var loadedClasses = {};
  window.joo.Class.load = function(fullClassName) {
    if (!loadedClasses[fullClassName]) {
      loadedClasses[fullClassName] = true;
      var uri = document.location.href;
      uri = uri.substring(0, uri.lastIndexOf("/")+1);
      uri += fullClassName.replace(/\./g,"/")+".js";
      var script = document.createElement("script");
      script.src = uri;
      document.body.appendChild(script);
    }
  };
  window.joo.Class.run = function(fullClassName, args) {
    window.joo.Class.load(fullClassName);
    window.onload = function() {
      eval(fullClassName+"_()").main(args);
    }
  }
  window.joo.Class.prepare = function(packageDef /* import*, classDef, members */) {
    var classDef = arguments[arguments.length-2];
    var members = arguments[arguments.length-1];
    var classDesc = { $members: members };
    if (typeof packageDef!="string")
      throw new Error("package declaration must be a string.");
    var packageParts = packageDef.split(/\s+/);
    if (packageParts[0]!="package")
      throw new Error("package declaration must start with 'package'.");
    if (packageParts.length!=2) {
      throw new Error("package declaration must be followed by a package name.");
    }
    classDesc.$package = packageParts[1];

    if (typeof classDef!="string")
      throw new Error("class declaration must be a string.");
    var classParts = classDef.split(/\s+/);
    var i=0;
    if (classParts[i]=="public") {
      classDesc.visibility = classParts[i++];
    }
    if (classParts[i]=="abstract") {
      classDesc.$abstract = true;
      ++i;
    }
    if (classParts[i++]!="class")
      throw new Error("expected 'class' after class modifiers.");
    if (i==classParts.length) {
      throw new Error("expected class name after keyword 'class'.");
    }
    classDesc.$class = classParts[i++];
    if (i<classParts.length) {
      if (classParts[i++]!="extends")
        throw new Error("expected EOL or 'extends' after class name.");
      if (i==classParts.length)
        throw new Error("expected class name after 'extends'.");
      classDesc.$extends = classParts[i++];
    }
    if (i<classParts.length)
      throw new Error("unexpected token '"+classParts[i]+" after class declaration.");
    new ClassDescription(classDesc);
  };
})();
//  alert("runtime loaded!");
joo.typeOf = function typeOf(obj){
  if (obj==undefined) return false;
  var type = typeof obj;
  if (type == 'object' || type == 'function'){
    switch(obj.constructor){
      case Array: return 'array';
      case RegExp: return 'regexp';
    }
    if (typeof obj.length == 'number' && obj.callee) {
      return 'arguments';
    }
  }
  return type;
};
/*	SWFObject v2.0 <http://code.google.com/p/swfobject/>
	Copyright (c) 2007 Geoff Stearns, Michael Williams, and Bobby van der Sluis
	This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
*/
var swfobject=function(){var Z="undefined",P="object",B="Shockwave Flash",h="ShockwaveFlash.ShockwaveFlash",W="application/x-shockwave-flash",K="SWFObjectExprInst",G=window,g=document,N=navigator,f=[],H=[],Q=null,L=null,T=null,S=false,C=false;var a=function(){var l=typeof g.getElementById!=Z&&typeof g.getElementsByTagName!=Z&&typeof g.createElement!=Z&&typeof g.appendChild!=Z&&typeof g.replaceChild!=Z&&typeof g.removeChild!=Z&&typeof g.cloneNode!=Z,t=[0,0,0],n=null;if(typeof N.plugins!=Z&&typeof N.plugins[B]==P){n=N.plugins[B].description;if(n){n=n.replace(/^.*\s+(\S+\s+\S+$)/,"$1");t[0]=parseInt(n.replace(/^(.*)\..*$/,"$1"),10);t[1]=parseInt(n.replace(/^.*\.(.*)\s.*$/,"$1"),10);t[2]=/r/.test(n)?parseInt(n.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof G.ActiveXObject!=Z){var o=null,s=false;try{o=new ActiveXObject(h+".7")}catch(k){try{o=new ActiveXObject(h+".6");t=[6,0,21];o.AllowScriptAccess="always"}catch(k){if(t[0]==6){s=true}}if(!s){try{o=new ActiveXObject(h)}catch(k){}}}if(!s&&o){try{n=o.GetVariable("$version");if(n){n=n.split(" ")[1].split(",");t=[parseInt(n[0],10),parseInt(n[1],10),parseInt(n[2],10)]}}catch(k){}}}}var v=N.userAgent.toLowerCase(),j=N.platform.toLowerCase(),r=/webkit/.test(v)?parseFloat(v.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,i=false,q=j?/win/.test(j):/win/.test(v),m=j?/mac/.test(j):/mac/.test(v);/*@cc_on i=true;@if(@_win32)q=true;@elif(@_mac)m=true;@end@*/return{w3cdom:l,pv:t,webkit:r,ie:i,win:q,mac:m}}();var e=function(){if(!a.w3cdom){return }J(I);if(a.ie&&a.win){try{g.write("<script id=__ie_ondomload defer=true src=//:><\/script>");var i=c("__ie_ondomload");if(i){i.onreadystatechange=function(){if(this.readyState=="complete"){this.parentNode.removeChild(this);V()}}}}catch(j){}}if(a.webkit&&typeof g.readyState!=Z){Q=setInterval(function(){if(/loaded|complete/.test(g.readyState)){V()}},10)}if(typeof g.addEventListener!=Z){g.addEventListener("DOMContentLoaded",V,null)}M(V)}();function V(){if(S){return }if(a.ie&&a.win){var m=Y("span");try{var l=g.getElementsByTagName("body")[0].appendChild(m);l.parentNode.removeChild(l)}catch(n){return }}S=true;if(Q){clearInterval(Q);Q=null}var j=f.length;for(var k=0;k<j;k++){f[k]()}}function J(i){if(S){i()}else{f[f.length]=i}}function M(j){if(typeof G.addEventListener!=Z){G.addEventListener("load",j,false)}else{if(typeof g.addEventListener!=Z){g.addEventListener("load",j,false)}else{if(typeof G.attachEvent!=Z){G.attachEvent("onload",j)}else{if(typeof G.onload=="function"){var i=G.onload;G.onload=function(){i();j()}}else{G.onload=j}}}}}function I(){var l=H.length;for(var j=0;j<l;j++){var m=H[j].id;if(a.pv[0]>0){var k=c(m);if(k){H[j].width=k.getAttribute("width")?k.getAttribute("width"):"0";H[j].height=k.getAttribute("height")?k.getAttribute("height"):"0";if(O(H[j].swfVersion)){if(a.webkit&&a.webkit<312){U(k)}X(m,true)}else{if(H[j].expressInstall&&!C&&O("6.0.65")&&(a.win||a.mac)){D(H[j])}else{d(k)}}}}else{X(m,true)}}}function U(m){var k=m.getElementsByTagName(P)[0];if(k){var p=Y("embed"),r=k.attributes;if(r){var o=r.length;for(var n=0;n<o;n++){if(r[n].nodeName.toLowerCase()=="data"){p.setAttribute("src",r[n].nodeValue)}else{p.setAttribute(r[n].nodeName,r[n].nodeValue)}}}var q=k.childNodes;if(q){var s=q.length;for(var l=0;l<s;l++){if(q[l].nodeType==1&&q[l].nodeName.toLowerCase()=="param"){p.setAttribute(q[l].getAttribute("name"),q[l].getAttribute("value"))}}}m.parentNode.replaceChild(p,m)}}function F(i){if(a.ie&&a.win&&O("8.0.0")){G.attachEvent("onunload",function(){var k=c(i);if(k){for(var j in k){if(typeof k[j]=="function"){k[j]=function(){}}}k.parentNode.removeChild(k)}})}}function D(j){C=true;var o=c(j.id);if(o){if(j.altContentId){var l=c(j.altContentId);if(l){L=l;T=j.altContentId}}else{L=b(o)}if(!(/%$/.test(j.width))&&parseInt(j.width,10)<310){j.width="310"}if(!(/%$/.test(j.height))&&parseInt(j.height,10)<137){j.height="137"}g.title=g.title.slice(0,47)+" - Flash Player Installation";var n=a.ie&&a.win?"ActiveX":"PlugIn",k=g.title,m="MMredirectURL="+G.location+"&MMplayerType="+n+"&MMdoctitle="+k,p=j.id;if(a.ie&&a.win&&o.readyState!=4){var i=Y("div");p+="SWFObjectNew";i.setAttribute("id",p);o.parentNode.insertBefore(i,o);o.style.display="none";G.attachEvent("onload",function(){o.parentNode.removeChild(o)})}R({data:j.expressInstall,id:K,width:j.width,height:j.height},{flashvars:m},p)}}function d(j){if(a.ie&&a.win&&j.readyState!=4){var i=Y("div");j.parentNode.insertBefore(i,j);i.parentNode.replaceChild(b(j),i);j.style.display="none";G.attachEvent("onload",function(){j.parentNode.removeChild(j)})}else{j.parentNode.replaceChild(b(j),j)}}function b(n){var m=Y("div");if(a.win&&a.ie){m.innerHTML=n.innerHTML}else{var k=n.getElementsByTagName(P)[0];if(k){var o=k.childNodes;if(o){var j=o.length;for(var l=0;l<j;l++){if(!(o[l].nodeType==1&&o[l].nodeName.toLowerCase()=="param")&&!(o[l].nodeType==8)){m.appendChild(o[l].cloneNode(true))}}}}}return m}function R(AE,AC,q){var p,t=c(q);if(typeof AE.id==Z){AE.id=q}if(a.ie&&a.win){var AD="";for(var z in AE){if(AE[z]!=Object.prototype[z]){if(z=="data"){AC.movie=AE[z]}else{if(z.toLowerCase()=="styleclass"){AD+=' class="'+AE[z]+'"'}else{if(z!="classid"){AD+=" "+z+'="'+AE[z]+'"'}}}}}var AB="";for(var y in AC){if(AC[y]!=Object.prototype[y]){AB+='<param name="'+y+'" value="'+AC[y]+'" />'}}t.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+AD+">"+AB+"</object>";F(AE.id);p=c(AE.id)}else{if(a.webkit&&a.webkit<312){var AA=Y("embed");AA.setAttribute("type",W);for(var x in AE){if(AE[x]!=Object.prototype[x]){if(x=="data"){AA.setAttribute("src",AE[x])}else{if(x.toLowerCase()=="styleclass"){AA.setAttribute("class",AE[x])}else{if(x!="classid"){AA.setAttribute(x,AE[x])}}}}}for(var w in AC){if(AC[w]!=Object.prototype[w]){if(w!="movie"){AA.setAttribute(w,AC[w])}}}t.parentNode.replaceChild(AA,t);p=AA}else{var s=Y(P);s.setAttribute("type",W);for(var v in AE){if(AE[v]!=Object.prototype[v]){if(v.toLowerCase()=="styleclass"){s.setAttribute("class",AE[v])}else{if(v!="classid"){s.setAttribute(v,AE[v])}}}}for(var u in AC){if(AC[u]!=Object.prototype[u]&&u!="movie"){E(s,u,AC[u])}}t.parentNode.replaceChild(s,t);p=s}}return p}function E(k,i,j){var l=Y("param");l.setAttribute("name",i);l.setAttribute("value",j);k.appendChild(l)}function c(i){return g.getElementById(i)}function Y(i){return g.createElement(i)}function O(k){var j=a.pv,i=k.split(".");i[0]=parseInt(i[0],10);i[1]=parseInt(i[1],10);i[2]=parseInt(i[2],10);return(j[0]>i[0]||(j[0]==i[0]&&j[1]>i[1])||(j[0]==i[0]&&j[1]==i[1]&&j[2]>=i[2]))?true:false}function A(m,j){if(a.ie&&a.mac){return }var l=g.getElementsByTagName("head")[0],k=Y("style");k.setAttribute("type","text/css");k.setAttribute("media","screen");if(!(a.ie&&a.win)&&typeof g.createTextNode!=Z){k.appendChild(g.createTextNode(m+" {"+j+"}"))}l.appendChild(k);if(a.ie&&a.win&&typeof g.styleSheets!=Z&&g.styleSheets.length>0){var i=g.styleSheets[g.styleSheets.length-1];if(typeof i.addRule==P){i.addRule(m,j)}}}function X(k,i){var j=i?"visible":"hidden";if(S){c(k).style.visibility=j}else{A("#"+k,"visibility:"+j)}}return{registerObject:function(l,i,k){if(!a.w3cdom||!l||!i){return }var j={};j.id=l;j.swfVersion=i;j.expressInstall=k?k:false;H[H.length]=j;X(l,false)},getObjectById:function(l){var i=null;if(a.w3cdom&&S){var j=c(l);if(j){var k=j.getElementsByTagName(P)[0];if(!k||(k&&typeof j.SetVariable!=Z)){i=j}else{if(typeof k.SetVariable!=Z){i=k}}}}return i},embedSWF:function(n,u,r,t,j,m,k,p,s){if(!a.w3cdom||!n||!u||!r||!t||!j){return }r+="";t+="";if(O(j)){X(u,false);var q=(typeof s==P)?s:{};q.data=n;q.width=r;q.height=t;var o=(typeof p==P)?p:{};if(typeof k==P){for(var l in k){if(k[l]!=Object.prototype[l]){if(typeof o.flashvars!=Z){o.flashvars+="&"+l+"="+k[l]}else{o.flashvars=l+"="+k[l]}}}}J(function(){R(q,o,u);if(q.id==u){X(u,true)}})}else{if(m&&!C&&O("6.0.65")&&(a.win||a.mac)){X(u,false);J(function(){var i={};i.id=i.altContentId=u;i.width=r;i.height=t;i.expressInstall=m;D(i)})}}},getFlashPlayerVersion:function(){return{major:a.pv[0],minor:a.pv[1],release:a.pv[2]}},hasFlashPlayerVersion:O,createSWF:function(k,j,i){if(a.w3cdom&&S){return R(k,j,i)}else{return undefined}},createCSS:function(j,i){if(a.w3cdom){A(j,i)}},addDomLoadEvent:J,addLoadEvent:M,getQueryParamValue:function(m){var l=g.location.search||g.location.hash;if(m==null){return l}if(l){var k=l.substring(1).split("&");for(var j=0;j<k.length;j++){if(k[j].substring(0,k[j].indexOf("="))==m){return k[j].substring((k[j].indexOf("=")+1))}}}return""},expressInstallCallback:function(){if(C&&L){var i=c(K);if(i){i.parentNode.replaceChild(L,i);if(T){X(T,true);if(a.ie&&a.win){L.style.display="block"}}L=null;T=null;C=false}}}}}();joo.Class.prepare("package joo.css",

"public class Color extends joo.lang.JOObject",function($jscContext){with(joo.css)with($jscContext)return[

"public static const",{TRANSPARENT:function(){return new Color(-1,-1,-1,0);}},
"public static const",{WHITE:function(){return new Color(255,255,255);}},
"public static const",{BLACK:function(){return new Color(0,0,0);}},
"public static const",{GRAY:function(){return new Color(128,128,128);}},
"public static const",{RED:function(){return new Color(255,0,0);}},
"public static const",{GREEN:function(){return new Color(0,255,0);}},
"public static const",{BLUE:function(){return new Color(0,0,255);}},
"public static const",{DARK_BLUE:function(){return new Color(0,0,128);}},

"private static const",{FACTOR:0.7},

"public",function Color(red,green,blue){
this[_super]();
this[_red]=red;
this[_green]=green;
this[_blue]=blue;
this[_updateAsString]();
},

"private",function updateAsString(){
this[_asString]=this[_red]<0
?"transparent"
:["rgb(",Math.round(this[_red]),",",Math.round(this[_green]),",",Math.round(this[_blue]),")"].join("");
},

"public",function clone(){
return new Color(this[_red],this[_green],this[_blue]);
},

"public",function darker(factor){
if(!factor)
factor=FACTOR;
if(factor==FACTOR&&this[_darkerColor]){
return this[_darkerColor];
}
var dc=new Color(
this[_red]*factor,
this[_green]*factor,
this[_blue]*factor
);
if(factor==FACTOR)
this[_darkerColor]=dc;
return dc;
},

"public",function brighter(factor){
if(!factor)
factor=FACTOR;
if(factor==FACTOR&&this[_brighterColor]){
return this[_brighterColor];
}
var bc;
var r=this[_red];
var g=this[_green];
var b=this[_blue];

var i=1/(1-factor);
if(r==0&&g==0&&b==0){
bc=new Color(i,i,i);
}else{
if(r>0&&r<i)r=i;
if(g>0&&g<i)g=i;
if(b>0&&b<i)b=i;

bc=new Color(Math.min(r/factor,255),
Math.min(g/factor,255),
Math.min(b/factor,255));
}
if(factor==FACTOR)
this[_brighterColor]=bc;
return bc;
},

"override public",function hashCode(){
return this[_asString];
},

"override public",function equals(color){
return color&&this[_asString]==color.toString();
},

"private static const",{JSON_PROPERTIES:function(){return [_red,_green,_blue];}},

"override protected",function isJsonProperty(property){
return JSON_PROPERTIES.contains(property);
},

"override protected",function addPropertiesFromJson(json,jsonBuilder){
this[_addPropertiesFromJson](json,jsonBuilder);
this[_updateAsString]();
},

"override public",function toString(){
return this[_asString];
},

"private var",{red: undefined},
"private var",{green: undefined},
"private var",{blue: undefined},
"private var",{asString: undefined},
"private var",{brighterColor: undefined},
"private var",{darkerColor: undefined},
]}
);joo.Class.prepare("package joo.html",
"public class Browser",function($jscContext){with(joo.html)with($jscContext)return[

"public static const",{WINDOW:function(){return eval("window");}},
"public static const",{DOCUMENT:function(){return WINDOW.document;}},
"public static const",{USER_AGENT:function(){return WINDOW.navigator["userAgent"];}},
"public static const",{ENGINE_IE6:"ie6"},
"public static const",{ENGINE_IE7:"ie7"},
"public static const",{ENGINE_GECKO:"gecko"},
"public static const",{ENGINE_OPERA:"opera"},
"public static const",{ENGINE_WEBKIT419:"webkit419"},
"public static const",{ENGINE_WEBKIT420:"webkit420"},
"public static const",{ENGINE_UNKNOWN:"unknown"},
"public static const",{ENGINE:function(){

if("ActiveXObject"in WINDOW){
return"XMLHttpRequest"in WINDOW?ENGINE_IE7:ENGINE_IE6;
}
if("childNodes"in DOCUMENT&&!DOCUMENT["all"]&&!("taintEnabled"in WINDOW.navigator))
return"xpath"in WINDOW?ENGINE_WEBKIT420:ENGINE_WEBKIT419;
if(DOCUMENT["getBoxObjectFor"]!=null)
return ENGINE_GECKO;
if("opera"in WINDOW)
return ENGINE_OPERA;
return ENGINE_UNKNOWN;
}},
"private static const",{BODY:function(){return DOCUMENT.getElementsByTagName("body")[0];}},
"public static const",{SUPPORTS_CSS_TEXT:function(){return typeof BODY.style.cssText=="string";}},
"public static const",{SUPPORTS_FILTERS:function(){return typeof BODY.style.filter=="string";}},
]}
);joo.Class.prepare("package joo.html",
"public class Dimensions",function($jscContext){with(joo.html)with($jscContext)return[

"public",function Dimensions(width,height){
this.width=width;
this.height=height;
},

"public var",{width: undefined},
"public var",{height: undefined},
]}
);joo.Class.prepare("package joo.html",

"public class Document",function($jscContext){with(joo.html)with($jscContext)return[

"private static const",{Browser:function(){return Browser_();}},
"public static const",{INSTANCE:function(){return new Document();}},

"public",function Document(ownerWindow){
this[_super]();
this.ownerWindow=ownerWindow?ownerWindow:Browser.WINDOW;
this[_peer]=this.ownerWindow.document;
},

"public",function getPeer(){
return this[_peer];
},

"public",function getWindow(){
return this.ownerWindow;
},

"public",function createElement(elementName){
return new Element(this,this[_peer].createElement(elementName));
},

"public",function createTextNode(text){

return this[_peer].createTextNode(text);
},

"public",function getElement(peerOrId){
var thePeer=typeof peerOrId=="string"?this[_peer].getElementById(peerOrId):peerOrId;
if(!thePeer){
throw"Undefined Element "+peerOrId;
}
return new Element(this,thePeer);
},

"public",function getDocumentElement(){
return this.getElement(this[_peer].documentElement);
},

"public",function getBody(){
if(!this[_body]){
this[_body]=this.getElement(this[_peer].getElementsByTagName("body")[0]);
}
return this[_body];
},

"public",function write(text){
this[_peer].write(text);
},

"public",function close(){
this[_peer].close();
},

"public",function toString(){
return"Document "+this[_peer];
},

"public var",{ownerWindow: undefined},
"private var",{peer: undefined},
"private var",{body: undefined},
]}
);joo.Class.prepare("package joo.html",

"public class Element extends joo.lang.JOObject",function($jscContext){with(joo.html)with($jscContext)return[

"public",function Element(ownerDocument,peer){
this[_super]();
this.ownerDocument=ownerDocument;
this[_peer]=peer;
},

"public",function getPeer(){
return this[_peer];
},

"private static const",{PREVENT_DEFAULT:function preventDefault(){
this["returnValue"]=false;
}},

"private static const",{STOP_PROPAGATION:function stopPropagation(){
this["cancelBubble"]=true;
}},

"private",function createIEEventHandler(listener){
return function(){
var window=this;
var event=window.event;
event.preventDefault=PREVENT_DEFAULT;
event.stopPropagation=STOP_PROPAGATION;

var body=window.document.getElementsByTagName("BODY");
event.pageX=event.clientX+body.scrollLeft;
event.pageY=event.clientY+body.scrollTop;
return listener(event);
};
},

"public",function addEventListener(eventType,listener,capture){
var thisPeer=this[_peer];
if(typeof thisPeer.addEventListener=="function"){
thisPeer.addEventListener(eventType,listener,capture);
}else{

thisPeer.attachEvent("on"+eventType,this[_createIEEventHandler](listener));
}
},

"public",function setId(id){
this[_peer].id=id;
return this;
},

"public",function setClassName(className){
this[_peer].className=className;
return this;
},

"public",function setAttributes(attributes){
var className=attributes["className"];
if(className){
this.setClassName(className);
delete attributes["className"];
}
var style=attributes["style"];
if(style){
this.setStyle(style);
delete attributes["style"];
}
for(var a in attributes){
var value=attributes[a];
if(typeof value=="number"){
value=String(Math.round(value));
}
this[_peer].setAttribute(a,value);
}
return this;
},

"private static",function convertToString(value){
switch(typeof value){
case"string":
return value;
case"number":
return Math.round(value)+"px";
case"object":
if(value!=null&&value.constructor==Array){
var result=[];
var i;
for(i=0;i<value.length;++i){
result.push(convertToString(value[i]));
}
return result.join(" ");
}
}
return String(value);
},

"public static",function setCssText(element,cssText){
if(typeof element["getPeer"]=="function"){
element=element["getPeer"]();
}
if(Browser.SUPPORTS_CSS_TEXT){
element.style.cssText=cssText;
}else{
element.setAttribute("style",cssText);
}
},

"public",function setStyle(styleAttributes){
if(typeof styleAttributes=="string"){
setCssText(this[_peer],styleAttributes);
return this;
}
var style=this[_peer].style;
if(styleAttributes["opacity"]!==undefined&&typeof style.filter=="string"){
var opacity=Math.round(styleAttributes["opacity"]*100);

try{

this[_peer].filters.item("DXImageTransform.Microsoft.Alpha")["Opacity"]=opacity;
}catch(ex){
style.filter="progid:DXImageTransform.Microsoft.Alpha(opacity="+opacity+")";
}
delete styleAttributes["opacity"];
}
for(var s in styleAttributes){
style[s]=convertToString(styleAttributes[s]);
}
return this;
},

"public",function remove(){
this[_peer].parentNode.removeChild(this[_peer]);
return this;
},

"public",function appendChild(element){
var thisPeer;
if(typeof element.getPeer=="function"){
thisPeer=element.getPeer();
}else{
thisPeer=element;
element=this.ownerDocument.getElement(thisPeer);
}
this[_peer].appendChild(thisPeer);
return element;
},

"public",function getParentElement(){
return this.ownerDocument.getElement(this[_peer].parentNode);
},

"public",function getOffset(){
return new Offset(this[_peer].offsetLeft,this[_peer].offsetTop);
},

"public",function setOffset(offset,top){
var left;
if(top===undefined){
left=offset.left;top=offset.top;
}else{
left=offset;
}
this.setStyle({left:offset.left,top:offset.top});
return this;
},

"public",function getAbsoluteOffset(){
var thisPeer=this[_peer];
var offset=new Offset(0,0);
do{
offset.left+=thisPeer.offsetLeft;
offset.top+=thisPeer.offsetTop;
thisPeer=thisPeer.offsetParent;
}while(thisPeer);
return offset;
},

"public",function getDimensions(){
var thisPeer=this[_peer];
return new Dimensions(thisPeer.offsetWidth,thisPeer.offsetHeight);
},

"override public",function toString(){
return this[_peer].id||this[_peer].nodeName;
},

"public var",{ownerDocument: undefined},
"private var",{peer: undefined},
]}
);joo.Class.prepare("package joo.html",
"public class Offset",function($jscContext){with(joo.html)with($jscContext)return[

"public static var",{HOME:function(){return new Offset(0,0);}},

"public",function Offset(left,top){
this.left=left;
this.top=top;
},

"public static",function getOffset(offsetOrLeft,top){
if(top!==undefined){
return new Offset(offsetOrLeft,top);
}
return offsetOrLeft;
},

"public",function clone(){
return new Offset(this.left,this.top);
},

"public",function plus(offsetOrLeft,top){
var offset=getOffset(offsetOrLeft,top);
return new Offset(this.left+offset.left,this.top+offset.top);
},

"public",function minus(offsetOrLeft,top){
var offset=getOffset(offsetOrLeft,top);
return new Offset(this.left-offset.left,this.top-offset.top);
},

"public",function getDistance(){
return Math.sqrt(this.left*this.left+this.top*this.top);
},

"public",function scale(factor){
return new Offset(this.left*factor,this.top*factor);
},

"public",function isHome(){
return this.left==0&&this.top==0;
},

"public var",{left: undefined},
"public var",{top: undefined},
]}
);joo.Class.prepare("package joo.html.slant",

"import joo.html.Document",
"import joo.html.Element",

"public class SlantCanvas extends joo.html.Element",function($jscContext){with(joo.html.slant)with($jscContext)return[

"private static const",{Browser:function(){return joo.html.Browser_();}},

"public",function SlantCanvas(document,canvas){
this[_super](document,canvas);
this.setAttributes({className:"canvas"});
},

"override public",function appendChild(child){
++this[_divIndex];
return this[_appendChild](child);
},

"private static",function rectCssText(color,
x0,y0,x1,y1,
borderColor,borderWidth){
var width=x1-x0;
var height=y1-y0;
if(borderWidth){
if(borderWidth<0){

var doubleBW=-2*borderWidth;
if(width>=doubleBW&&height>=doubleBW){
borderWidth=-borderWidth;
width-=doubleBW;
height-=doubleBW;
}else{

color=borderColor;
borderWidth=0;
}
}else{

x0-=borderWidth;
y0-=borderWidth;
}
}

var rect=["background-color:",color,
";left:",x0,"px;top:",y0,"px;width:",width,"px;height:",height,"px;"];
if(borderWidth){
rect.push("border-color:",borderColor,";border-width:",borderWidth,"px;");
}
return rect;
},

"private",function add(cssText,zIndex,opacity){
if(zIndex!==undefined){
cssText.push("z-index:",zIndex,";");
}
if(opacity<1){
if(Browser.SUPPORTS_FILTERS){
cssText.push("filter:progid:DXImageTransform.Microsoft.Alpha(opacity=",Math.round(opacity*100),");");
}else{
cssText.push("opacity:",opacity,";");
}
}
cssText=cssText.join("");
var div=this.getPeer().childNodes[this[_divIndex]++];
if(!div){
div=this.ownerDocument.createElement("div").setClassName("slant").getPeer();
this[_appendChild](div);
}
if(Browser.SUPPORTS_CSS_TEXT){
div.style.cssText=cssText;
}else{
div.setAttribute("style",cssText);
}
return div;
},














"public",function addRect(color,
x0,y0,x1,y1,
zIndex,opacity,
borderColor,borderWidth){
return this[_add](rectCssText(color,Math.round(x0),Math.round(y0),Math.round(x1),Math.round(y1),borderColor,borderWidth),zIndex,opacity);
},



























"public",function addSlant(color,
x00,y00,x01,y01,
x10,y10,x11,y11,
zIndex,opacity,
borderColor,borderWidth){
x00=Math.round(x00);
y00=Math.round(y00);
x10=Math.round(x10);
y10=Math.round(y10);
x01=Math.round(x01);
y01=Math.round(y01);
x11=Math.round(x11);
y11=Math.round(y11);
var cssText;
if(x00==x01&&x10==x11){
if(y00==y10&&y01==y11){

cssText=rectCssText(color,x00,y00,x11,y11,borderColor,borderWidth);
}else if(y00>=y10&&y01<=y11){

cssText=["left:",x00,"px;top:",y10,"px;border-right-color:",color,
";border-width:",y00-y10,"px ",x11-x00,"px ",y11-y01,"px 0;height:",y01-y00,"px;"];
}else if(y00<=y10&&y01>=y11){

cssText=["left:",x00,"px;top:",y00,"px;border-left-color:",color,
";border-width:",y10-y00,"px 0 ",y01-y11,"px ",x11-x00,"px;height:",y11-y10,"px;"];
}
}else if(x00<=x01&&x10>=x11){

cssText=["left:",x00,"px;top:",y00,"px;border-top-color:",color,
";border-width:",y11-y00,"px ",x10-x11,"px 0 ",x01-x00,"px;width:",x11-x01,"px;"];
}else if(x00>=x01&&x10<=x11){

cssText=["left:",x01,"px;top:",y00,"px;border-bottom-color:",color,
";border-width:0 ",x11-x10,"px ",y11-y00,"px ",x00-x01,"px;width:",x10-x00,"px;"];
}
if(cssText===undefined){
throw new Error(["Unsupported Slant coordinates ",x00,"|",y00," ",x10,"|",y10," ",x01,"|",y01," ",x11,"|",y11,"."].join(""));
}
return this[_add](cssText,zIndex,opacity);
},

"public",function rewind(offset){
if(offset===undefined){
offset=0;
}
this[_divIndex]=offset;
},

"public",function clearRest(){
var div=this.getPeer();
var i;
for(i=this[_divIndex];i<this[_lastDivIndex];++i){
var child=div.childNodes[i];
child.style.display="none";
}
this[_lastDivIndex]=this[_divIndex];
},

"public",function getItemCount(){
return this[_divIndex];
},

"public",function getItem(index){
return this.getPeer().childNodes[index];
},

"private var",{divIndex:0},
"private var",{lastDivIndex:0},
]}
);joo.Class.prepare("package joo.lang",
"public class JOObject",function($jscContext){with(joo.lang)with($jscContext)return[

"private static var",{idCnt:0},

"private static const",{INIT:function(){

Array.prototype["hashCode"]=joo.lang.JOObject.prototype.hashCode;
}},

"public static",function getHashCode(obj){
return obj&&typeof obj.hashCode=="function"?obj.hashCode():"_"+obj;
















},

"public static",function equal(o1,o2){
return o1===o2||o1&&typeof o1.equals=="function"&&o1.equals(o2);
},

"public static",function toJsonString(json){
switch(typeof json){
case"string":
return'"'+json.replace(/(["\\])/g,"\\$1")+'"';
case"object":
if(json===null){
return"null";
}
if(json.constructor==Array){
return'['+json.map(toJsonString).join(',')+']';
}
var string=[];
for(var property in json){
string.push(toJsonString(property)+':'+toJsonString(json[property]));
}
return'{'+string.join(',')+'}';
case"undefined":
return"undefined";
case"number":
if(!isFinite(json))
return"null";
}
return String(json);
},

"private static const",{JSON_REG_EXP:/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/},













"public static",function fromJsonString(str,secure){
return((typeof str!="string")||(secure&&!JSON_REG_EXP.test(str)))?null:eval('('+str+')');
},

"public static",function toJsonObject(obj){
return new joo.lang.JsonBuilder().toJsonObject(obj);
},

"public static",function fromJsonObject(json){
return new joo.lang.JsonBuilder().fromJsonObject(json);
},

"public",function JOObject(){
},

"public",function getClass(){
return this["constructor"];
},

"public",function hashCode(){
return this["0id"]||(this["0id"]="_"+(idCnt++));
},

"public",function equals(joobject){
return this===joobject;
},

"public",function toJson(){
return new joo.lang.JsonBuilder().toJsonObject(this);
},

"protected",function addPropertiesToJson(result,jsonBuilder){
var noPredicate=typeof this.isJsonProperty!="function";
for(var property in this){
if(property!="_pcl"&&(noPredicate||this.isJsonProperty(property))){
result[property]=jsonBuilder.toJsonObject(this[property]);
}
}
},

"protected",function isJsonProperty(property){
var value=this[property];
return typeof value!="function"&&value!==this.getClass().prototype[property];
},

"public",function fromJson(json){
this.addPropertiesFromJson(json,new joo.lang.JsonBuilder());
},

"protected",function addPropertiesFromJson(json,jsonBuilder){

for(var property in json){
if(property.charAt(0)!='$'){
this[property]=jsonBuilder.fromJsonObject(json[property]);
}
}
},

"public",function initFrom(props){
joo.util.PropertyAware_().setProperties(this,props);
},

"override public",function toString(){
return this.getClass()["getName"]()+"@"+this.hashCode();
},

]}
);joo.Class.prepare("package joo.lang",
"class JsonBuilder",function($jscContext){with(joo.lang)with($jscContext)return[

function toJsonObject(obj){
if(typeof obj!="object"||obj==null)
return obj;
if(obj.constructor==Array){

var jsonArray=[];
for(var i=0;i<obj.length;++i){
jsonArray[i]=this.toJsonObject(obj[i]);
}
return jsonArray;
}
var json;
if(typeof obj.addPropertiesToJson=="function"){
var hashCode=obj.hashCode();
var ref=this[_visited][hashCode];
if(ref){
var idref=ref["$id"];
if(!idref){
idref=ref["$id"]=String(this[_idCnt]++);
}
return{"$idref":idref};
}
json=this[_visited][hashCode]={"$class":obj.getClass()["getName"]()};
obj.addPropertiesToJson(json,this);
return json;
}

json={};
joo.lang.JOObject.prototype.addPropertiesToJson.call(obj,json,this);
return json;
},

function fromJsonObject(json){
if(typeof json!="object"||json==null)
return json;
if(json.constructor==Array){

var array=[];
for(var i=0;i<json.length;++i){
array[i]=this.fromJsonObject(json[i]);
}
return array;
}
var refId=json["$idref"];
if(refId){
return this[_visited][refId];
}
var fullClassName=json["$class"];
if(!fullClassName){
var obj={};
joo.lang.JOObject.prototype.addPropertiesFromJson.call(obj,json,this);
return obj;
}
var clazz=eval(fullClassName);
var joobject=new clazz();
var id=json["$id"];
if(id){
this[_visited][id]=joobject;
}
joobject.addPropertiesFromJson(json,this);
return joobject;
},

"private const",{visited:function(){return {};}},
"private var",{idCnt:1},
]}
);joo.Class.prepare(


















"package joo.sound",

"public class Sound",function($jscContext){with(joo.sound)with($jscContext)return[

"private static const",{Document:function(){return joo.html.Document_();}},

"private static const",{DEBUG:false},
"private static const",{FLASH_CONTAINER:function(){return (window.navigator.appName.indexOf("Microsoft")!=-1||window.navigator.appName.indexOf("Opera")!=-1
?window:window.document);}},
"private static const",{SWF_LOCATION:"jssoundkit/SoundBridge2.swf"},
"private static const",{SWF_ID:"__SoundBridge__"},
"private static var",{INSTANCES:function(){return [];}},
"private static var",{soundBridge: undefined},
"private static var",{soundAvailable: undefined},

"public static",function init(onInit){
if(soundAvailable!==undefined){
onInit(soundAvailable);
return;
}
var soundElement=Document.INSTANCE.createElement("div");
soundElement.setId(SWF_ID);
Document.INSTANCE.getBody().appendChild(soundElement);
swfobject.embedSWF(SWF_LOCATION,SWF_ID,"0","0","8.0.0","",{id:SWF_ID},{allowScriptAccess:"always"});

new joo.util.TimedExecutor(function(){
trace("Waiting for SoundBridge...");
soundBridge=FLASH_CONTAINER[SWF_ID];
if(!soundBridge||"nodeName"in soundBridge&&soundBridge.nodeName.toLowerCase()=="div"){
trace("SoundBridge not found!");
soundAvailable=false;
onInit(false);
return false;
}
if(typeof soundBridge.proxyMethods!="function")
return undefined;
soundAvailable=true;
if(DEBUG)
console.debug("SoundBridge initialized, calling onLoad handler!");
if(onInit)
onInit(true);
return false;
},100).start();
},

"public static",function isAvailable(){
return soundAvailable;
},

"public",function Sound(url,startImmediately){
this[_super]();
this[_index]=soundBridge.newSound();
INSTANCES[this[_index]]=this;
if(url){
this.loadSound(url,false);
if(startImmediately){
this.start();
}
}
},

"private",function call(name,arguments){
if(soundBridge){
if(DEBUG)
console.debug("Sound#call "+name+" on sound #"+this[_index]);
return soundBridge.proxyMethods(this[_index],name,arguments);
}
return undefined;
},

"public",function loadSound(url,streaming){
this[_call]("loadSound",[url,streaming]);
},

"public",function start(secondOffset,loops){
if(this[_loaded]){
this[_call]("start",secondOffset===undefined?[]:[secondOffset,loops]);
}else{
this[_startOnLoad]=function(){
this.start(secondOffset,loops);
};
}
},

"public",function stop(){
this[_call]("stop",[]);
},

"public",function fade(duration,targetVolume){
var startVolume=this.getVolume();
var volumeDelta=targetVolume-startVolume;

var sound=this;
var startTime=new Date().getTime();
this[_fader]=new joo.util.TimedExecutor(function(){
var timeOffset=new Date().getTime()-startTime;
var volume=startVolume+volumeDelta*timeOffset/duration;

var result=undefined;
if(volumeDelta<0?volume<=targetVolume:volume>=targetVolume){
if(targetVolume==0){
sound.stop();
volume=startVolume;
}else{
volume=targetVolume;
}
result=false;
}
sound.setVolume(volume);
return result;
},100);
this[_fader].start();
},

"public",function getId3(){
return this[_call]("id3",[]);
},

"public",function getPan(){
return this[_call]("getPan",[]);
},

"public",function getTransform(){
return this[_call]("getTransform",[]);
},

"public",function getVolume(){
return this[_call]("getVolume",[]);
},

"public",function setPan(value){
this[_call]("setPan",[value]);
return this;
},

"public",function setTransform(transformObject){
this[_call]("setTransform",[transformObject]);
return this;
},

"public",function setVolume(value){
this[_call]("setVolume",[value]);
return this;
},

"public",function getDuration(){
return this[_call]("getDuration",[]);
},

"public",function getPosition(){
return this[_call]("getPosition",[]);
},

"public",function getBytesLoaded(){
return this[_call]("getBytesLoaded",[]);
},

"public",function getBytesTotal(){
return this[_call]("getBytesTotal",[]);
},

"public",function onLoad(success){
},

"public",function internalOnLoad(success){
this[_loaded]=true;
if(this[_startOnLoad]){
this[_startOnLoad]();
}
this.onLoad(success);
},

"private static",function getInstance(index){
return INSTANCES[index];
},

"public static",function callbackOnLoad(index,success){
trace("Sound.onLoad("+success+") index="+index);
getInstance(index).internalOnLoad(success);
},

"public",function onSoundComplete(){
},

"public static",function callbackOnSoundComplete(index){
trace("Sound:onSoundComplete() event triggered");
getInstance(index).onSoundComplete();
},

"public",function onID3(){
},

"public static",function callbackOnID3(index){
trace("Sound:onID3() event triggered");
getInstance(index).onID3();
},

"private static",function trace(value){
if(DEBUG){
console.debug(value);
}
},

"private var",{index: undefined},
"private var",{loaded:false},
"private var",{startOnLoad: undefined},
"private var",{fader: undefined},
]}
);joo.Class.prepare(
"package joo.util",

"class GapArrayIterator",function($jscContext){with(joo.util)with($jscContext)return[

"public",function GapArrayIterator(elements){
this[_super]();
this[_elements]=elements;
this[_findNext]();
},
"public",function hasNext(){
return this[_index]<this[_elements].length;
},
"public",function next(){
var next=this[_elements][this[_index]];
this[_findNext]();
return next;
},
"private",function findNext(){
var thisElements=this[_elements];
for(var i=this[_index]+1;i<=thisElements.length;++i){
if(thisElements[i]!==undefined){
this[_index]=i;
return;
}
}
this[_index]=thisElements.length;
},
"private var",{elements: undefined},
"private var",{index:-1},
]}
);joo.Class.prepare(
"package joo.util",

"public class HashSet extends joo.lang.JOObject",function($jscContext){with(joo.util)with($jscContext)return[

"public",function HashSet(element){
this[_super]();
this[_reset]();
if(element){
if(!this.addAll(element)){
this.add(element);
}
}
},
"public",function getSize(){
return this[_size];
},
"public",function isEmpty(){
return this[_size]==0;
},
"public",function iterator(){
return new GapArrayIterator(this[_elements]);
},
"public",function add(element){
if(element===undefined){
throw"IllegalArgument: may not add undefined to HashSet.";
}
var hashCode=getHashCode(element);
var thisIndexByHashCode=this[_indexByHashCode];
var index=thisIndexByHashCode[hashCode];
var thisElements=this[_elements];
if(index!==undefined){
return false;
}
thisIndexByHashCode[hashCode]=thisElements.length;
thisElements.push(element);
++this[_size];
return true;
},
"public",function addAll(array){
var result=false;
if(array&&array.constructor===Array){
for(var i=0;i<array.length;++i){
if(array[i]!==undefined){
result|=this.add(array[i]);
}
}
}
return result;
},
"public",function pop(){
var thisElements=this[_elements];
for(var i=0;i<thisElements.length;++i){
if(thisElements[i]!==undefined){
var result=thisElements[i];
thisElements[i]=undefined;
--this[_size];
delete this[_indexByHashCode][getHashCode(result)];
return result;
}
}
return undefined;
},
"public",function remove(element){
var hashCode=getHashCode(element);
var index=this[_indexByHashCode][hashCode];
if(index===undefined){
return false;
}
this[_elements][index]=undefined;
--this[_size];
delete this[_indexByHashCode][hashCode];


return true;
},
"private",function reset(){
this[_indexByHashCode]={};
this[_elements]=[];
this[_size]=0;
},
"public",function clear(){
this[_reset]();
},
"public",function contains(element){
return this[_indexByHashCode][getHashCode(element)]!==undefined;
},
"private var",{indexByHashCode: undefined},
"private var",{elements: undefined},
"private var",{size: undefined},
"override public",function toString(){
var definedElements;
if(this[_size]==this[_elements].length){
definedElements=this[_elements];
}else{
definedElements=[];
for(var i=this.iterator();i.hasNext();){
definedElements.push(i.next());
}
}
return"{"+definedElements.join(", ")+"}";
},
]}
);joo.Class.prepare("package joo.util",

"public class Interval",function($jscContext){with(joo.util)with($jscContext)return[

"public static",function create(numberOrArrayOrInterval){
switch(numberOrArrayOrInterval){
case"number":return new Interval(numberOrArrayOrInterval,numberOrArrayOrInterval);
case"array":return new Interval(numberOrArrayOrInterval[0],numberOrArrayOrInterval[1]);
case"object":return numberOrArrayOrInterval;
}
throw"Cannot create Interval from '"+numberOrArrayOrInterval+"'.";
},

"public",function Interval(a,b){
this.a=a;
this.b=b;
if(a>b){
throw"Interval: IllegalArguments "+this;
}
},

"public",function contains(n){
return this.a<=n&&n<=this.b;
},

"public",function includes(interval){
return this.a<=interval.a&&this.b>=interval.b;
},

"public",function intersection(interval){
var a1=Math.max(this.a,interval.a);
var b1=Math.min(this.b,interval.b);
return a1<=b1?new Interval(a1,b1):null;
},

"public",function compareTo(c){
return this.a>c?1:this.b<c?-1:0;
},

"public",function toString(){
return["[",this.a,",",this.b,"]"].join("");
},

"public var",{a: undefined},
"public var",{b: undefined},
]}
);joo.Class.prepare("package joo.util",

"public class TimedExecutor",function($jscContext){with(joo.util)with($jscContext)return[

"private static const",{Browser:function(){return joo.html.Browser_();}},

"public",function TimedExecutor(handler,timeout){
this[_handler]=handler;
this[_timeout]=timeout;
this[_trigger]=this[_trigger].bind(this);
},

"private",function setTimeout(delay){
this[_timer]=Browser.WINDOW.setTimeout(this[_trigger],Math.max(this[_timeout]-delay,0));
},

"private",function trigger(){
this[_triggerStartTime]=new Date().getTime();
var realTimeout=this[_triggerStartTime]-this[_lastTriggerStartTime];

var result=this[_handler](realTimeout,this);
this[_lastTriggerStartTime]=this[_triggerStartTime];
if(typeof result=="number"){
this[_timeout]=result;
}
if(result===false||result<0){
this[_timer]=undefined;
}else{
var duration=new Date().getTime()-this[_triggerStartTime];

this[_setTimeout](duration);
}
},

"public",function getTriggerStartTime(){
return this[_triggerStartTime];
},

"public",function getLastTriggerStartTime(){
return this[_lastTriggerStartTime];
},

"public",function isRunning(){
return! !this[_timer];
},

"public",function start(){
if(!this[_timer]){
this[_lastTriggerStartTime]=new Date().getTime();
this[_setTimeout](0);
return true;
}
return false;
},

"public",function stop(){
if(this[_timer]){
Browser.WINDOW.clearTimeout(this[_timer]);
this[_timer]=undefined;
return true;
}
return false;
},

"public",function restart(){
var result=this.stop();
this.start();
return result;
},

"private var",{handler: undefined},
"private var",{timeout:0},
"private var",{timer: undefined},
"private var",{triggerStartTime: undefined},
"private var",{lastTriggerStartTime: undefined},
]}
);joo.Class.prepare("package net.jangaron",

"public class Direction",function($jscContext){with(net.jangaron)with($jscContext)return[
"public static const",{DIRS:function(){return [];}},
"public static const",{NORTH:function(){return new Direction("N",0,1,String.fromCharCode(parseInt("25B2",16)));}},
"public static const",{EAST:function(){return new Direction("E",1,0,String.fromCharCode(parseInt("25C4",16)));}},
"public static const",{SOUTH:function(){return new Direction("S",0,-1,String.fromCharCode(parseInt("25BC",16)));}},
"public static const",{WEST:function(){return new Direction("W",-1,0,String.fromCharCode(parseInt("25BA",16)));}},
"public static var",{DIRS_COUNT:0},

"private static const",{init:function(){

var getDir=function(relative){
return DIRS[(d+relative)%DIRS_COUNT];
};
for(var d=0;d<DIRS_COUNT;++d){
var dir=DIRS[d];
dir.opposite=getDir(DIRS_COUNT/2);
dir.turnRight=getDir(1);
dir.turnLeft=getDir(DIRS_COUNT-1);
}
}},

"public",function Direction(name,dx,dy,compassArrow){
DIRS.push(this);++DIRS_COUNT;
this[_name]=name;
this.dx=dx;
this.dy=dy;
this[_compassArrow]=compassArrow;
},

"public",function getCompassArrow(){
return this[_compassArrow];
},

"override public",function toString(){
return this[_name];
},

"private var",{name: undefined},
"private var",{compassArrow: undefined},
"public var",{dx: undefined},
"public var",{dy: undefined},
"public var",{opposite: undefined},
"public var",{turnLeft: undefined},
"public var",{turnRight: undefined},
]}
);joo.Class.prepare("package net.jangaron",

"import net.jangaron.ViewPort",

"public class Grid extends joo.lang.JOObject",function($jscContext){with(net.jangaron)with($jscContext)return[

"private static const",{Direction:function(){return Direction_();}},
"private static const",{Document:function(){return joo.html.Document_();}},
"private static const",{ViewPort:function(){return ViewPort_();}},
"private static const",{Sound:function(){return joo.sound.Sound_();}},
"private static const",{Color:function(){return joo.css.Color_();}},
"private static const",{Browser:function(){return joo.html.Browser_();}},

"public static const",{MIN_INTERVAL_MS:40},

"private static const",{SOUND_AMBIENT:"ambient"},
"private static const",{SOUND_WON:"won"},
"private static const",{SOUND_LOST:"lost"},
"private static const",{SOUND_START:"start"},
"private static const",{SOUND_BEEP:"beep"},

"public static",function main(width,height,highRim,
startOpacity,obstacleCnt,
musicVolume,soundVolume,
viewPortDefs){
var STYLES=
[[{height:"95%",top:"5%",width:"100%",left:"0%"}],
[{height:"47%",top:"4.5%",width:"100%",left:"0%"},
{height:"47%",top:"52.5%",width:"100%",left:"0%"}],
[{height:"47%",top:"4.5%",width:"100%",left:"0%"},
{height:"47%",top:"52.5%",width:"49%",left:"0%"},
{height:"49%",top:"52.5%",width:"49%",left:"50.5%"}],
[{height:"47%",top:"4.5%",width:"49%",left:"0%"},
{height:"47%",top:"4.5%",width:"49%",left:"50.5%"},
{height:"47%",top:"52.5%",width:"49%",left:"0%"},
{height:"47%",top:"52.5%",width:"49%",left:"50.5%"}]
];
var startPositions=
[new Position(width/2,10,Direction.NORTH),
new Position(width/2,height-10,Direction.SOUTH),
new Position(width/2-10,10,Direction.NORTH),
new Position(width/2+10,height-10,Direction.SOUTH),
new Position(width/2+10,10,Direction.NORTH),
new Position(width/2-10,height-10,Direction.SOUTH)];
var viewPortCnt=0;
var viewPortDef;
for(var i=0;i<viewPortDefs.length;++i){
viewPortDef=viewPortDefs[i];
if(viewPortDef.user||viewPortDef.visible){
++viewPortCnt;
}
}
var styles=STYLES[viewPortCnt-1];
var gameDocument=Document.INSTANCE;
if(Browser.ENGINE!=Browser.ENGINE_GECKO){
gameDocument.getDocumentElement().setStyle({overflow:"hidden"});
}
var lightcycles=[];
var viewports=[];
for(i=0;i<viewPortDefs.length;++i){
viewPortDef=viewPortDefs[i];
var lightCycle=new LightCycle(viewPortDef.teamColor.getTeam(),viewPortDef.name,viewPortDef.teamColor.getColor(),viewPortDef.startPosition||startPositions[i],
viewPortDef.user?viewPortDef.keyMap:null,
viewPortDef.minSpeed,viewPortDef.maxSpeed);
lightcycles.push(lightCycle);
if(viewPortDef.user||viewPortDef.visible){
var style=viewPortDef.style?viewPortDef.style:styles[viewports.length];
var viewPort=ViewPort.create(gameDocument,style);
viewPort.setLightCycle(lightCycle);
viewports.push(viewPort);
}
}
Sound.init(function(hasSound){
if(!hasSound){
musicVolume=soundVolume=0;
}
Browser.WINDOW["grid"]=new Grid(width,height,highRim,startOpacity,obstacleCnt,lightcycles,viewports,musicVolume,soundVolume);
});
},

"public",function Grid(width,height,highRim,
startOpacity,obstacleCnt,
lightCycles,viewPorts,
musicVolume,soundVolume){
this[_super]();
this[_lightCycles]=lightCycles;
this[_lightCycles].broadcast("setGrid",this);
this[_viewPorts]=viewPorts;
this[_viewPorts].broadcast("setGrid",this);
this[_stepExecutor]=new joo.util.TimedExecutor(this[_doStep].bind(this),MIN_INTERVAL_MS);
this.width=width;
this.height=height;
this.highRim=highRim;
this.startOpacity=startOpacity;
this.obstacleCnt=obstacleCnt;

var document=Document.INSTANCE;
this[_createStatusLine](document);
var htmlElement=document.getDocumentElement();
this[_gameOver]=this[_gameOver].bind(this);
this[_terminalAnimationExecutor]=new joo.util.TimedExecutor(this[_animateTerminal].bind(this),40);
this[_terminal]=document.createElement("div").setClassName("terminal").setStyle({opacity:"0.8"});
document.getBody().appendChild(this[_terminal]);
htmlElement.addEventListener("keydown",this[_onkeydown].bind(this),true);
htmlElement.addEventListener("keyup",this[_onkeyup].bind(this),true);
Browser.WINDOW.addEventListener("blur",this[_onblur].bind(this),true);
Browser.WINDOW.addEventListener("focus",this[_onfocus].bind(this),true);
this.soundVolume=soundVolume;
this.musicVolume=musicVolume;
if(musicVolume||soundVolume){
this[_sounds]={};
if(musicVolume>0){
var ambient=new joo.sound.Sound();
ambient.loadSound("sound/Recognizer.mp3",true);
ambient.stop();
ambient.setVolume(musicVolume);

ambient.onSoundComplete=function(){
ambient.start();
};
this[_sounds][SOUND_AMBIENT]=ambient;
this[_sounds][SOUND_WON]=new joo.sound.Sound("sound/won.mp3",false).setVolume(musicVolume);
this[_sounds][SOUND_LOST]=new joo.sound.Sound("sound/lost.mp3",false).setVolume(musicVolume);
}
if(soundVolume>0){
this[_sounds][SOUND_START]=new joo.sound.Sound("sound/transform-and-start.mp3",false).setVolume(soundVolume);
this[_sounds][SOUND_BEEP]=new joo.sound.Sound("sound/beep.mp3",false).setVolume(soundVolume);
}
}

for(var vp=0;vp<this[_viewPorts].length;++vp){
var viewPort=this[_viewPorts][vp];
if(viewPort.getLightCycle().isUser()){
this[_primaryViewPort]=viewPort;
break;
}
}
if(!this[_primaryViewPort]){
this[_primaryViewPort]=this[_viewPorts][0];
}
this[_init]();
},

"private",function getSound(name){
return this[_sounds][name];
},

"private",function createStatusLine(document){
this[_statusLine]=document.createElement("div").setClassName("status");
document.getBody().appendChild(this[_statusLine]);
this[_statusLines]={};
this[_lightCycles].forEach(this[_addToStatusLine],this);
this[_updateStatusLine]=this[_updateStatusLine].bind(this);
},

"private static",function cssPercent(n){
return Math.floor(n*100)/100+"%";
},

"private",function addToStatusLine(lightCycle,index){
var document=Document.INSTANCE;
var lightCycleStatus=this[_statusLines][lightCycle]=
document.createElement("div").setStyle({
color:Color.WHITE,backgroundColor:lightCycle.getColor(),
left:cssPercent(index*100/this[_lightCycles].length),
width:cssPercent(100/this[_lightCycles].length)
});
lightCycleStatus.appendChild(document.createTextNode(lightCycle.getName()));
this[_statusLine].appendChild(lightCycleStatus);
},

"public",function getLightCycles(){
return this[_lightCycles];
},

"public",function getPrimaryViewPort(){
return this[_primaryViewPort];
},

"private",function init(){
if(this.musicVolume){
this[_getSound](SOUND_WON).stop();
this[_getSound](SOUND_LOST).stop();
this[_getSound](SOUND_AMBIENT).start();
}
this[_terminal].setStyle({display:"none"});
this[_terminalAnimationExecutor].stop();
this[_inGame]=true;
this[_keyQueue]=[];
this.walls=[];
var GRAY=Color.GRAY;
([new Wall(GRAY,0,[0,this.height]),
new Wall(GRAY,this.width,[0,this.height]),
new Wall(GRAY,[0,this.width],0),
new Wall(GRAY,[0,this.width],this.height)]).forEach(this.addWall,this);
this[_createRandomWalls](this.obstacleCnt);
this[_livingCount]=this[_lightCycles].length;
this[_livingCountByTeam]={};
this[_livingTeams]=0;
this[_livingUserCount]=0;
this[_userLightCycles]=[];
for(var lc=0;lc<this[_livingCount];++lc){
var lightCycle=this[_lightCycles][lc];
if(lightCycle.isUser()){
this[_userLightCycles].push(this[_lightCycles][lc]);
}
var team=lightCycle.getTeam();
if(lightCycle.isUser()||team!==lightCycle.getName()){
if(!this[_livingCountByTeam][team]){
this[_livingCountByTeam][team]=0;
++this[_livingTeams];
}
++this[_livingCountByTeam][team];
}
}
this[_livingUserCount]=this[_userLightCycles].length;
this[_lightCycles].broadcast("init");
if(Browser.WINDOW.parent==Browser.WINDOW){

if(!this[_stepExecutor].start()){

}
}else{
this[_viewPorts].broadcast("update");
}
},

"private",function createRandomWalls(number){
var GRAY=new joo.css.Color(120,120,140);
for(var i=0;i<number;++i){
var wall;
do{
var x1=Math.round(20+Math.random()*(this.width-40));
var x2=Math.round(20+Math.random()*(this.width-40));
var y1=Math.round(20+Math.random()*(this.height-40));
var y2=Math.round(20+Math.random()*(this.height-40));
wall=Math.random()>0.5
?new Wall(GRAY,[Math.min(x1,x2),Math.max(x1,x2)],y1)
:new Wall(GRAY,x1,[Math.min(y1,y2),Math.max(y1,y2)]);
}while(this[_hasIntersectingWall](wall));

if(wall.x1==wall.x2){
this.addWall(new Wall(GRAY,wall.x1-.5,[wall.y1,wall.y2]));
this.addWall(new Wall(GRAY,wall.x1+.5,[wall.y1,wall.y2]));
this.addWall(new Wall(GRAY,[wall.x1-.5,wall.x1+.5],y1));
this.addWall(new Wall(GRAY,[wall.x1-.5,wall.x1+.5],y2));
}else{
this.addWall(new Wall(GRAY,[wall.x1,wall.x2],wall.y1-.5));
this.addWall(new Wall(GRAY,[wall.x1,wall.x2],wall.y1+.5));
this.addWall(new Wall(GRAY,x1,[wall.y1-.5,wall.y1+.5]));
this.addWall(new Wall(GRAY,x2,[wall.y1-.5,wall.y1+.5]));
}
}
},

"private",function hasIntersectingWall(wall){
for(var i=0;i<this.walls.length;++i){
var w=this.walls[i];
if(w.intersects(wall)){
return true;
}
}
return false;
},

"public",function addWall(wall){
this.walls.push(wall);
},

"public",function removeWall(wall){
return this.walls.remove(wall);
},

"private",function doStep(passedMillis,tie){
if(!this[_inGame])
return undefined;
this[_updateFrameRate](passedMillis);
var oldLivingCount=this[_livingCount];
var lastStartTime=tie.getLastTriggerStartTime();
var startTime=tie.getTriggerStartTime();

do{
var nextTurnTime=this[_getNextTurnTime]();

this[_lightCycles].broadcast("move",(nextTurnTime||startTime)-lastStartTime);
this[_lightCycles].broadcast("update");
this[_lightCycles].broadcast("checkCrashed");
lastStartTime=nextTurnTime;
this[_lightCycles].broadcast("turn",nextTurnTime);
}while(nextTurnTime);
this[_viewPorts].broadcast("update");
this[_lightCycles].broadcast("update");
this[_lightCycles].broadcast("checkCrashed");
this[_lightCycles].forEach(this[_updateStatusLine]);
if(oldLivingCount!=this[_livingCount]&&this[_isGameOver]()){
this[_viewPorts].broadcast("update");

this[_inGame]=false;
Browser.WINDOW.setTimeout(this[_gameOver],0);
return false;
}
return undefined;
},

"private",function getNextTurnTime(){
for(var ulc=0;ulc<this[_userLightCycles].length;++ulc){
var lightCycle=this[_userLightCycles][ulc];
var nextTurnTime=lightCycle.nextTurnTime();
if(nextTurnTime){
return nextTurnTime;
}
}
return undefined;
},


function crashed(lightCycle){
if(lightCycle.isUser()){

var exchangeLC=this[_findExchangeLightCycle](lightCycle);
if(exchangeLC){

for(var vp=0;vp<this[_viewPorts].length;++vp){
var viewPort=this[_viewPorts][vp];
if(viewPort.getLightCycle()===lightCycle){

this[_userLightCycles].remove(lightCycle);
this[_userLightCycles].push(exchangeLC);
exchangeLC["1keyMap"]=lightCycle["1keyMap"];
lightCycle["1keyMap"]=undefined;
viewPort.setLightCycle(exchangeLC);
return;
}
}
throw new Error("View port of user-controlled lightcycle "+lightCycle.getName()+" not found!");
}
}
},

"private",function findExchangeLightCycle(lightCycle){
var team=lightCycle.getTeam();
for(var i=0;i<this[_lightCycles].length;++i){
var lc=this[_lightCycles][i];
if(lc!==lightCycle&&!lc.isDead()&&!lc.isUser()&&lc.getTeam()==team){
return lc;
}
}
},

"private",function isGameOver(){
if(this[_livingCount]<=1
||this[_userLightCycles].length>0&&this[_livingUserCount]==0){
return true;
}
for(var team in this[_livingCountByTeam]){
if(this[_livingCountByTeam][team]==0){
delete this[_livingCountByTeam][team];
--this[_livingTeams];
if(this[_livingTeams]<=1){
return true;
}
}
}
return false;
},
"private",function updateStatusLine(lightCycle){
var sl=this[_statusLines][lightCycle];

sl.setStyle({opacity:String(lightCycle.getOpacity()*.75)});

sl.getPeer().firstChild.data=[lightCycle.getName(),
" | w",lightCycle.wins.toString(10,2),
" | d",lightCycle.deaths.toString(10,2)].join("");
},

"private",function updateFrameRate(passedMillis){
this[_passedMillisSum]+=passedMillis;
++this[_renderedFrames];
if(this[_passedMillisSum]>=1000){
Browser.WINDOW.status=Math.round(this[_renderedFrames]*100000/this[_passedMillisSum])/100;
this[_passedMillisSum]=0;
this[_renderedFrames]=0;
}
},

"public",function removeLightCycle(lightCycle){
for(var i=0;i<this.walls.length;){
var w=this.walls[i];
if(w.lightCycle===lightCycle){
this.walls.splice(i,1);
}else{
++i;
}
}
--this[_livingCount];
if(lightCycle.isUser()){
--this[_livingUserCount];
}
--this[_livingCountByTeam][lightCycle.getTeam()];
},

"private",function onkeydown(event){
event.time=new Date().getTime();
if(!this[_inGame]){
if(event.keyCode==13){
this[_init]();
event.preventDefault();
return false;
}
return true;
}
switch(event.keyCode){
case 32:
if(this[_stepExecutor].isRunning()){
this[_stepExecutor].stop();
}else{
this[_stepExecutor].start();
}
event.preventDefault();
return false;
}
for(var lc=this[_userLightCycles].length-1;lc>=0;--lc){
var lightCycle=this[_userLightCycles][lc];
if(!lightCycle.onkeydown(event)){
event.preventDefault();
return false;
}
}
return true;
},

"private",function onkeyup(event){
event.time=new Date().getTime();
if(!this[_inGame]){
return true;
}
for(var lc=this[_userLightCycles].length-1;lc>=0;--lc){
var lightCycle=this[_userLightCycles][lc];
if(!lightCycle.onkeyup(event)){
event.preventDefault();
return false;
}
}
return true;
},

"private",function onblur(){
if(this[_userLightCycles].length>0){
this[_stepExecutor].stop();
}
},

"private",function onfocus(){
if(this[_inGame]){
this[_stepExecutor].start();
}
},

"private static",function displayName(lc){
var output=[lc.isUser()?"USER":"PROGRAM"," ",lc.getName().toUpperCase()];
if(lc.getTeam()!=lc.getName()){
output.push(" [",lc.getTeam().toUpperCase()," TEAM]");
}
return output.join("");
},

"private",function gameOver(){









var survivingPrograms=[];
var survivingUser;
var survivingTeams=new joo.util.HashSet();
var survivor;
for(var s=0;s<this[_lightCycles].length;++s){
var lc=this[_lightCycles][s];
if(!lc.isDead()){
if(lc.isUser()){
survivor=survivingUser=lc;
}else{
survivingPrograms.push(lc);
}
if(lc.isUser()||lc.getTeam()!==lc.getName()){
survivingTeams.add(lc.getTeam());
}
}
}
if(!survivor&&survivingPrograms.length>0){

survivor=survivingPrograms[Math.floor(Math.random()*survivingPrograms.length)];
survivingPrograms.forEach(function(s){if(s!==survivor)++s.deaths;});
}
var survivorName;
if(survivor){
survivorName=displayName(survivor);
++survivor.wins;
survivorName=displayName(survivor);
}else{
survivorName="NOBODY";
}
var msg;

switch(this[_userLightCycles].length){
case 0:
msg=["GAME OVER"];
break;
case 1:
if(survivingUser){
if(this.musicVolume){
this[_getSound](SOUND_AMBIENT).stop();
this[_getSound](SOUND_WON).start();
}
var manyPrograms=this[_lightCycles].length-this[_userLightCycles].length>1;
msg=["NO! THIS IS IMPOSSIBLE!",
survivorName+" HAS BEATEN MY BEST PROGRAM"+(manyPrograms?"S":""),
"WAIT UNTIL I'VE GOTTEN 2,415 TIMES SMARTER..."];
break;
}

default:
if(this.musicVolume){
this[_getSound](SOUND_AMBIENT).stop();
this[_getSound](SOUND_LOST).start();
}
msg=["ILLEGAL CODE"];
for(var u=0;u<this[_userLightCycles].length;++u){
var ulc=this[_userLightCycles][u];
if(ulc.isDead()){
msg.push(displayName(ulc)+" DETACHED FROM SYSTEM");
}
}
}
msg.push(survivorName+" HAS WON THE GAME");
msg.push("END OF LINE");
msg.push("<HIT RETURN TO PLAY AGAIN>");
this[_terminal].getPeer().innerHTML="<p><span class='cursor'>&nbsp;</span></p>";
var docWidth=Document.INSTANCE.getDocumentElement().getDimensions().width;
this[_terminal].setStyle({display:"block",fontSize:docWidth/30});
this[_message]=msg;
this[_messageLineIndex]=0;
this[_terminalAnimationExecutor].start();
},

"private",function animateTerminal(passedMillis){

var line=this[_message][0];
var p=this[_terminal].getPeer().lastChild;
if(!line){

var cursorStyle=p.lastChild["style"];
cursorStyle.display=cursorStyle.display!="none"?"none":"inline";
return 500;
}
if(this[_messageLineIndex]>=line.length){
this[_message].shift();
if(this[_message].length==0){
return 500;
}
p.removeChild(p.lastChild);
this[_messageLineIndex]=0;
p=p.ownerDocument.createElement("p");
p.innerHTML="<span class='cursor'>&nbsp;</span>";
this[_terminal].appendChild(p);
return 200;
}
if(this[_messageLineIndex]==0){
if(this.soundVolume){
this[_getSound](SOUND_BEEP).start();
}
p.insertBefore(p.ownerDocument.createTextNode(""),p.firstChild);
this[_messageLineIndex]=1;
}else{
this[_messageLineIndex]+=Math.round(passedMillis/20);
}
p.firstChild.data=line.substring(0,this[_messageLineIndex]);
return 40;
},

"public var",{width: undefined},
"public var",{height: undefined},
"public var",{highRim: undefined},
"public var",{obstacleCnt: undefined},
"public var",{startOpacity:1},
"public var",{musicVolume:100},
"public var",{soundVolume:100},
"private var",{lightCycles: undefined},
"private var",{primaryViewPort: undefined},
"private var",{userLightCycles: undefined},
"private var",{livingCount: undefined},
"private var",{livingCountByTeam: undefined},
"private var",{livingUserCount: undefined},
"private var",{livingTeams: undefined},
"private var",{viewPorts: undefined},
"private var",{stepExecutor: undefined},
"private var",{keyQueue: undefined},
"public var",{walls: undefined},
"private var",{passedMillisSum:0},
"private var",{renderedFrames:0},
"private var",{statusLine: undefined},
"private var",{statusLines: undefined},
"private var",{sounds: undefined},
"private var",{terminalAnimationExecutor: undefined},
"private var",{inGame:false},
"private var",{terminal: undefined},
"private var",{messageLineIndex: undefined},
"private var",{message: undefined},
"private var",{insideStep: undefined},
]}
);joo.Class.prepare("package net.jangaron",
"public class KeyMap extends joo.util.PropertyAware",function($jscContext){with(net.jangaron)with($jscContext)return[

"public",function KeyMap(props){
this[_super](props);
},

"public var",{left: undefined},
"public var",{right: undefined},
"public var",{lookLeft: undefined},
"public var",{lookRight: undefined},
"public var",{lookBackwards: undefined},
"public var",{faster: undefined},
"public var",{slower: undefined},

]}
);joo.Class.prepare("package net.jangaron",

"public class LightCycle",function($jscContext){with(net.jangaron)with($jscContext)return[

"private static const",{Direction:function(){return Direction_();}},

"private static const",{DEFAULT_MIN_SPEED:25},
"private static const",{DEFAULT_MAX_SPEED:80},
"private static const",{DEBUG:false},

"public",function LightCycle(team,name,color,
position,keyMap,
minSpeed,maxSpeed){
this[_super]();
this[_team]=team||name;
this[_name]=name;
this[_color]=color;
this[_initialPosition]=position;
this[_position]=new Position();
this[_keyMap]=keyMap;
this.minSpeed=minSpeed?minSpeed:DEFAULT_MIN_SPEED;
this.maxSpeed=maxSpeed?maxSpeed:DEFAULT_MAX_SPEED;
},

"public",function setGrid(grid){
this[_grid]=grid;
},

"public",function setTeam(team){
this[_team]=team;
},

"public",function getTeam(){
return this[_team];
},

"public",function setName(name){
this[_name]=name;
},

"public",function getName(){
return this[_name];
},

"public",function isUser(){
return! !this[_keyMap];
},

"public",function setColor(color){
this[_color]=color;
},

"public",function getColor(){
return this[_color];
},

"public",function getOpacity(){
return this[_opacity];
},

"public",function getPosition(){
return this[_position];
},

"public",function getViewPosition(){
var viewPosition=this.getPosition();
if(!this.isDead()){
viewPosition=this.getPosition().clone();
if(this[_viewTurn]){
viewPosition.dir=viewPosition.dir[this[_viewTurn]];
}
viewPosition.move(0.51);
}
return viewPosition;
},

"public",function init(){
if(this[_grid].soundVolume>0){
if(!this[_sound]){
this[_sound]={

derezz:new joo.sound.Sound(this.isUser()?"sound/derezz.mp3":"sound/derezz2.mp3",false),
turnLeft:new joo.sound.Sound("sound/turn1.mp3",false),
turnRight:new joo.sound.Sound("sound/turn2.mp3",false)
};


}
}
this[_opacity]=this[_grid].startOpacity;
this.speed=1;
this[_position].setPosition(this[_initialPosition]);
this[_turnQueue]=[];
this[_prevCycleWall]=this[_cycleWall]=undefined;
this[_lastWall]=new Wall(this[_color],this[_position].x,this[_position].y,this);
this[_prevCycleWall]=this[_findCrashWall](this[_lastWall],new joo.util.HashSet());
this[_cycleWall]=this[_createCycleWall]();
this[_cycleHeadWall]=this[_createCycleWall](true);
this[_updateCycleHeadWall]();
},

"private",function createCycleWall(isHeadWall){
var newCycleWall=new Wall(this[_color],this[_position].x,this[_position].y,isHeadWall?undefined:this);
newCycleWall.lightCycle=this;
this[_grid].addWall(newCycleWall);
return newCycleWall;
},

"private",function updateCycleHeadWall(){
switch(this[_position].dir){
case Direction.NORTH:
case Direction.SOUTH:
this[_cycleHeadWall].x1=this[_position].x-0.5;
this[_cycleHeadWall].x2=this[_position].x+0.5;
this[_cycleHeadWall].y1=this[_cycleHeadWall].y2=this[_position].y;
break;
default:
this[_cycleHeadWall].y1=this[_position].y-0.5;
this[_cycleHeadWall].y2=this[_position].y+0.5;
this[_cycleHeadWall].x1=this[_cycleHeadWall].x2=this[_position].x;
}
},

"public",function getCycleWall(){
return this[_cycleWall];
},

"private",function getLinePos(){
return Math.round(1/10*(this[_position].dir.dx!=0?this[_position].x:this[_position].y));

},

"private static const",{ANGLE_TO_PAN:function(){return 100/(Math.PI/2);}},

"private",function playSound(soundName){
if(!this[_sound])
return;
var primaryViewPort=this[_grid].getPrimaryViewPort();
var volume;
var pan;
if(primaryViewPort.getLightCycle()===this){
volume=1;
pan=0;
}else{
var microPosition=primaryViewPort.getPosition();
var thisPosition=this.getPosition();
var dx=thisPosition.x-microPosition.x;
var dy=thisPosition.y-microPosition.y;
var distance=Math.sqrt(dx*dx+dy*dy);
volume=1-distance/300;

var gradient=microPosition.dir.dx==0
?microPosition.dir.dy*dx/Math.abs(dy)
:-microPosition.dir.dx*dy/Math.abs(dx);

var alpha=Math.atan(gradient);
pan=Math.round(alpha*ANGLE_TO_PAN);
if(DEBUG){
console.debug("dx "+dx+" dy "+dy+" dir.dx "+microPosition.dir.dx+" dir.dy "+microPosition.dir.dy+" distance "+distance+" gradient "+gradient+" sound "+soundName+": v "+volume+" p "+pan);
}
}
if(volume>0){
var theSound=this[_sound][soundName];
theSound.setVolume(this[_grid].soundVolume*volume);
theSound.setPan(pan);
theSound.start();
}
},

"public",function move(passedMillis){
if(this[_opacity]==this[_grid].startOpacity){
this[_updateSpeed](new Date().getTime());
if(this.speed<this.minSpeed){

this.speed=Math.min(this.minSpeed,this.speed+passedMillis*15/1000);
}

this[_position].move(this.speed*passedMillis/1000);






}else if(this[_opacity]>0){
this[_opacity]-=passedMillis/2000;
if(this[_opacity]<0.1){
this[_opacity]=0;
this[_grid].removeLightCycle(this);

}
}
},

"private",function updateSpeed(now){
if(this[_fasterDown]){
if(this.speed<this.maxSpeed){
this.speed=Math.min(this.maxSpeed,this.speed+(now-this[_fasterDown])*0.005);
}
this[_fasterDown]=now;
}else if(this[_slowerDown]){
if(this.speed>this.minSpeed){
this.speed=Math.max(this.minSpeed,this.speed-(now-this[_slowerDown])*0.015);
}
this[_slowerDown]=now;
}
},

"public",function update(){
if(!this.isDead()){
switch(this[_position].dir){
case Direction.NORTH:
this[_lastWall].y1=this[_cycleWall].y2;
this[_cycleHeadWall].y1=this[_cycleHeadWall].y2=
this[_lastWall].y2=this[_cycleWall].y2=this[_position].y;
break;
case Direction.EAST:
this[_lastWall].x1=this[_cycleWall].x2;
this[_cycleHeadWall].x1=this[_cycleHeadWall].x2=
this[_lastWall].x2=this[_cycleWall].x2=this[_position].x;
break;
case Direction.SOUTH:
this[_lastWall].y2=this[_cycleWall].y1;
this[_cycleHeadWall].y1=this[_cycleHeadWall].y2=
this[_lastWall].y1=this[_cycleWall].y1=this[_position].y;
break;
default:
this[_lastWall].x2=this[_cycleWall].x1;
this[_cycleHeadWall].x1=this[_cycleHeadWall].x2=
this[_lastWall].x1=this[_cycleWall].x1=this[_position].x;
}
if(DEBUG){
this[_cycleWall].check();
this[_cycleHeadWall].check();
}
}
},

"private",function moveWall(distance,turn){
var startPosition=this[_position];
var endPosition=startPosition.clone();
if(turn){
endPosition[turn]();
}
endPosition.move(distance);
return new Wall(this[_color],
[Math.min(startPosition.x,endPosition.x),Math.max(startPosition.x,endPosition.x)],
[Math.min(startPosition.y,endPosition.y),Math.max(startPosition.y,endPosition.y)]);
},

"protected",function computeTurn(){
var theTurn;
var excludedWalls=new joo.util.HashSet([this[_cycleHeadWall],this[_cycleWall],this[_prevCycleWall]]);
if(this[_findCrashWall](this[_moveWall](this.speed/3,undefined),excludedWalls)){
theTurn=Math.random()<0.5?"turnLeft":"turnRight";
if(this[_findCrashWall](this[_moveWall](this.speed/10,theTurn),excludedWalls)){
theTurn=theTurn=="turnLeft"?"turnRight":"turnLeft";
if(this[_findCrashWall](this[_moveWall](this.speed/10,theTurn),excludedWalls)){
theTurn=undefined;
}
}
}
return theTurn;
},

"private",function mayTurn(){
return!this.isDead()&&
(this[_cycleWall].x2-this[_cycleWall].x1>=1||
this[_cycleWall].y2-this[_cycleWall].y1>=1);
},

"public",function nextTurnTime(){
return this[_turnQueue].length>0&&this[_mayTurn]()?this[_turnQueue][0]["time"]:undefined;
},

"public",function turn(eventTime){
if(!this[_mayTurn]()){

return;
}
var theTurn;
if(this[_keyMap]){
if(eventTime&&this.nextTurnTime()==eventTime){
theTurn=this[_turnQueue].shift()["dir"];
}
}else{
theTurn=this.computeTurn();
}
if(theTurn){
this[_playSound](theTurn);
this[_position].x=Math.round(this[_position].x);
this[_position].y=Math.round(this[_position].y);
this.update();
this[_position].dir=this[_position].dir[theTurn];
this[_lastWall].x1=this[_lastWall].x2=this[_position].x;
this[_lastWall].y1=this[_lastWall].y2=this[_position].y;
this[_prevCycleWall]=this[_cycleWall];
this[_cycleWall]=this[_createCycleWall]();
this[_position].move(0.1);
this.update();
this[_updateCycleHeadWall]();
}
},

"public",function checkCrashed(){
if(this.isDead())
return;
var excludedWalls=new joo.util.HashSet([this[_cycleHeadWall],this[_cycleWall],this[_prevCycleWall]]);
var crashWall=this[_findCrashWall](this[_lastWall],excludedWalls);
if(crashWall){

switch(this[_position].dir){
case Direction.NORTH:
this[_position].y=crashWall.y1-0.1;
break;
case Direction.EAST:
this[_position].x=crashWall.x1-0.1;
break;
case Direction.SOUTH:
this[_position].y=crashWall.y2+0.1;
break;
default:
this[_position].x=crashWall.x2+0.1;
}
++this.deaths;
this.update();
this[_grid].removeWall(this[_cycleHeadWall]);
this[_opacity]-=0.1;

this[_playSound]("derezz");
this[_grid].crashed(this);
}
},

"private",function findCrashWall(lastWall,excludedWalls){

var walls=this[_grid].walls;
for(var i=0;i<walls.length;++i){
var wall=walls[i];
if(!excludedWalls.contains(wall)&&lastWall.intersects(wall)){
return walls[i];
}
}
return undefined;
},

"public",function isDead(){
return this[_opacity]<this[_grid].startOpacity;
},

"public",function onkeydown(event){
var keys=this[_keyMap];
if(keys){
switch(event.keyCode){
case keys.left:this[_turnQueue].push({"time":event.time,"dir":"turnLeft"});break;
case keys.right:this[_turnQueue].push({"time":event.time,"dir":"turnRight"});break;
case keys.lookLeft:this[_viewTurn]="turnLeft";break;
case keys.lookRight:this[_viewTurn]="turnRight";break;
case keys.lookBackwards:this[_viewTurn]="opposite";break;
case keys.faster:
if(!this[_fasterDown]){
this[_fasterDown]=event.time;
}
break;
case keys.slower:
if(!this[_slowerDown]){
this[_slowerDown]=event.time;
}
break;
default:return true;
}
return false;
}
return true;
},

"public",function onkeyup(event){
var keys=this[_keyMap];
if(keys){
switch(event.keyCode){
case keys.lookLeft:
case keys.lookRight:
case keys.lookBackwards:
this[_viewTurn]=undefined;
break;
case keys.faster:
this[_updateSpeed](new Date().getTime());
this[_fasterDown]=undefined;
break;
case keys.slower:
this[_updateSpeed](new Date().getTime());
this[_slowerDown]=undefined;
break;
default:return true;
}
return false;
}
return true;
},

"private var",{grid: undefined},
"private var",{team: undefined},
"private var",{name: undefined},
"private var",{color: undefined},
"private var",{opacity: undefined},
"public var",{minSpeed: undefined},
"public var",{maxSpeed: undefined},
"private var",{initialPosition: undefined},
"private var",{position: undefined},
"private var",{turnQueue: undefined},
"private var",{viewTurn: undefined},
"private var",{keyMap: undefined},
"private var",{lastWall: undefined},
"private var",{cycleWall: undefined},
"private var",{prevCycleWall: undefined},
"private var",{cycleHeadWall: undefined},
"private var",{sound: undefined},
"private var",{fasterDown: undefined},
"private var",{slowerDown: undefined},
"public var",{speed: undefined},
"public var",{deaths:0},
"public var",{wins:0},
]}
);joo.Class.prepare("package net.jangaron",

"public class Line",function($jscContext){with(net.jangaron)with($jscContext)return[

"private static const",{Color:function(){return joo.css.Color_();}},

"public",function Line(viewPort,y){
this.viewPort=viewPort;
this[_y]=y;
this.HALF_LINE_WIDTH=viewPort.GRID_LINE_WIDTH/2;
},

"public",function update(offset){
var y0=this[_y]-offset;
var y1=this.viewPort.getY(y0+this.HALF_LINE_WIDTH);
var y2=this.viewPort.getY(y0-this.HALF_LINE_WIDTH)+1;
if(!this[_div]){
this[_div]=this.viewPort.lineLayer.addRect(Color.WHITE,
0,this.viewPort.HORIZON+y1,
this.viewPort.WIDTH,this.viewPort.HORIZON+y2);
}else{
this[_div].style.top=Math.round(this.viewPort.HORIZON+y1)+"px";
this[_div].style.height=Math.round(y2-y1)+"px";
this[_div].style.width=this.viewPort.WIDTH+"px";
}
},

"public var",{HALF_LINE_WIDTH: undefined},
"public var",{viewPort: undefined},
"private var",{y: undefined},
"private var",{div: undefined},
]}
);joo.Class.prepare("package net.jangaron",

"public class Position",function($jscContext){with(net.jangaron)with($jscContext)return[

"private static const",{Direction:function(){return Direction_();}},

"public",function Position(x,y,dir){
this.x=x;
this.y=y;
this.dir=dir;
},

"public",function clone(){
return new Position(this.x,this.y,this.dir);
},

"public",function setPosition(position){
this.x=position.x;
this.y=position.y;
this.dir=position.dir;
},

"public",function getPosition(distance){
var thisDir=this.dir;
return new Position(this.x+thisDir.dx*distance,this.y+thisDir.dy*distance,thisDir);
},

"public",function getOffset(steps){
return this[_offset](this.dir,steps);
},

"public",function getLeftOffset(steps){
return this[_offset](this.dir.turnRight,steps);
},

"private",function offset(dir,steps){
switch(dir){
case Direction.NORTH:return this.y%steps;
case Direction.EAST:return this.x%steps;
case Direction.SOUTH:return(steps-this.y%steps)%steps;
default:return(steps-this.x%steps)%steps;
}
},

"public",function move(distance){
var thisDir=this.dir;
this.x+=thisDir.dx*distance;
this.y+=thisDir.dy*distance;
},

"public",function turnLeft(){
this.dir=this.dir.turnLeft;
},

"public",function turnRight(){
this.dir=this.dir.turnRight;
},

"public var",{x: undefined},
"public var",{y: undefined},
"public var",{dir: undefined},
]}
);joo.Class.prepare("package net.jangaron",












"public class RelativeWall extends joo.lang.JOObject",function($jscContext){with(net.jangaron)with($jscContext)return[

"private static const",{Direction:function(){return Direction_();}},

"private static const",{DEBUG:false},

"public",function RelativeWall(wall){
this[_super]();
this.wall=wall;
this.wallProjection=new Trapez();
},

"public",function update(pos){
this[_maybeHides]=[];
this.hiddenByCnt=0;
this.zIndex=10000;
var thisWall=this.wall;
var rx1=thisWall.x1-pos.x;
var ry1=thisWall.y1-pos.y;
var rx2=thisWall.x2-pos.x;
var ry2=thisWall.y2-pos.y;
switch(pos.dir){
case Direction.NORTH:
return this.setValues(rx1,ry1,rx2,ry2);
case Direction.SOUTH:
return this.setValues(-rx2,-ry2,-rx1,-ry1);
case Direction.EAST:
if(ry1===ry2)
return this.setValues(-ry1,rx1,-ry2,rx2);
return this.setValues(-ry2,rx2,-ry1,rx1);
case Direction.WEST:
if(rx1===rx2)
return this.setValues(ry1,-rx1,ry2,-rx2);
return this.setValues(ry2,-rx2,ry1,-rx1);
}
throw"Unknown direction "+pos.dir;
},

"public",function setValues(x1,y1,x2,y2){
this.x1=x1;
this.y1=y1;
this.x2=x2;
this.y2=y2;
if(DEBUG&&!(x1<=x2&&y1<=y2)){
throw"IllegalArgument:"+this.toString1();
}
this.mayHidePoint=

this.x1==0&&this.x2==0?this[_mayHidePointNever]


:this.x1<0&&this.x2>0?this[_mayHidePointMiddle]


:this.x2<=0?this[_mayHidePointLeft]

:this[_mayHidePointRight];
return this;
},






function mayHidePoint(x,y){

},

"private",function mayHidePointNever(x,y){
return false;
},

"private",function mayHidePointMiddle(x,y){
return y>this.y1||y==this.y1&&this.x1<=x&&x<=this.x2;
},

"private",function mayHidePointLeft(x,y){

return x<this.x2&&(y>this.y1);
},

"private",function mayHidePointRight(x,y){

return x>this.x1&&(y>this.y1);
},





"public",function updateMaybeHides(other,unhiddenElements){
if(this.mayHidePoint(other.x1,other.y1)||this.mayHidePoint(other.x2,other.y2)){
this[_maybeHides].push(other);
if(other.hiddenByCnt++ ==0){
unhiddenElements.remove(other);
}
return true;
}
return false;
},

"public",function removedFromUnhidden(unhiddenElements){
this[_maybeHides].forEach(function(other){
if(--other.hiddenByCnt==0){
unhiddenElements.add(other);
}
});
},

"public",function toString1(){
return"["+[this.wall.color,this.wall.getOpacity(),this.x1,this.y1,this.x2,this.y2].join(",")+"]";
},

"public var",{wall: undefined},
"public var",{wallProjection: undefined},
"public var",{x1: undefined},
"public var",{y1: undefined},
"public var",{x2: undefined},
"public var",{y2: undefined},
"private var",{maybeHides:function(){return [];}},
"public var",{hiddenByCnt:0},
"public var",{zIndex:10000},
]}
);joo.Class.prepare("package net.jangaron",

"public class SlantLine",function($jscContext){with(net.jangaron)with($jscContext)return[

"private static const",{Color:function(){return joo.css.Color_();}},

"public",function SlantLine(viewPort,gx){
this.viewPort=viewPort;
this.gx=gx;
},

"private",function clippedPoint(x){
var vp=this.viewPort;
x=Math.abs(x);
if(x>vp.SIDE){
return{x:vp.SIDE,y:Math.round(vp.HORIZON*(1+vp.SIDE/x))};
}else{
return{x:x,y:vp.HEIGHT};
}
},

"public",function update(index){
var vp=this.viewPort;
var HALF_LINE_WIDTH=vp.HALF_SLANT_LINE_WIDTH;
var gxRel=(this.gx+index/vp.GRID_LINE_DISTANCE)*vp.SIDE;
if(Math.abs(gxRel)<=HALF_LINE_WIDTH){
vp.slantLineLayer.addSlant(Color.WHITE,
vp.SIDE,vp.HORIZON,vp.SIDE+gxRel-HALF_LINE_WIDTH,vp.HEIGHT,
vp.SIDE,vp.HORIZON,vp.SIDE+gxRel+HALF_LINE_WIDTH,vp.HEIGHT);
}else{
var left=this[_clippedPoint](gxRel-HALF_LINE_WIDTH);
var right=this[_clippedPoint](gxRel+HALF_LINE_WIDTH);

var off;
if(gxRel<0){
vp.slantLineLayer.addSlant(Color.WHITE,
0,vp.HORIZON,0,right.y,
vp.SIDE,vp.HORIZON,vp.SIDE-right.x,right.y);
off=left.y<vp.HEIGHT?1:0;
vp.slantLineLayer.addSlant(Color.BLACK,
0,vp.HORIZON-off,0,left.y-off,
vp.SIDE,vp.HORIZON-off,vp.SIDE-left.x,left.y-off);
}else{
vp.slantLineLayer.addSlant(Color.WHITE,
vp.SIDE,vp.HORIZON,vp.SIDE+left.x,left.y,
vp.WIDTH,vp.HORIZON,vp.WIDTH,left.y);
off=right.y<vp.HEIGHT?1:0;
vp.slantLineLayer.addSlant(Color.BLACK,
vp.SIDE,vp.HORIZON-off,vp.SIDE+right.x,right.y-off,
vp.WIDTH,vp.HORIZON-off,vp.WIDTH,right.y-off);
}
}
},

"public var",{viewPort: undefined},
"public var",{gx: undefined},
]}
);joo.Class.prepare("package net.jangaron",

"public class TeamColor extends joo.lang.JOObject",function($jscContext){with(net.jangaron)with($jscContext)return[

"public static const",{TEAM_GOLD:"Gold"},
"public static const",{TEAM_BLUE:"Blue"},
"public static const",{TEAM_GREEN:"Green"},
"public static const",{TEAM_EARTH:"Earth"},
"public static const",{TEAM_WATER:"Water"},
"public static const",{TEAM_PINK:"Pink"},

"public static const",{COLOR_ORANGE:"Orange"},
"public static const",{COLOR_RED:"Red"},
"public static const",{COLOR_YELLOW:"Yellow"},
"public static const",{COLOR_VIOLET:"Violet"},
"public static const",{COLOR_BLUE:"Blue"},
"public static const",{COLOR_CYAN:"Cyan"},
"public static const",{COLOR_GREEN:"Green"},
"public static const",{COLOR_SILICON:"Silicon"},
"public static const",{COLOR_BROWN:"Brown"},
"public static const",{COLOR_AQUA:"Aqua"},
"public static const",{COLOR_PINK:"Pink"},

"public static const",{UNDEFINED:function(){return new net.jangaron.TeamColor("",null);}},
"public static const",{GOLD_ORANGE:function(){return new net.jangaron.TeamColor(TEAM_GOLD,COLOR_ORANGE);}},
"public static const",{GOLD_RED:function(){return new net.jangaron.TeamColor(TEAM_GOLD,COLOR_RED);}},
"public static const",{GOLD_YELLOW:function(){return new net.jangaron.TeamColor(TEAM_GOLD,COLOR_YELLOW);}},
"public static const",{BLUE_VIOLET:function(){return new net.jangaron.TeamColor(TEAM_BLUE,COLOR_VIOLET);}},
"public static const",{BLUE_BLUE:function(){return new net.jangaron.TeamColor(TEAM_BLUE,COLOR_BLUE);}},
"public static const",{GREEN_CYAN:function(){return new net.jangaron.TeamColor(TEAM_GREEN,COLOR_CYAN);}},
"public static const",{GREEN_GREEN:function(){return new net.jangaron.TeamColor(TEAM_GREEN,COLOR_GREEN);}},
"public static const",{EARTH_SILICON:function(){return new net.jangaron.TeamColor(TEAM_EARTH,COLOR_SILICON);}},
"public static const",{EARTH_BROWN:function(){return new net.jangaron.TeamColor(TEAM_EARTH,COLOR_BROWN);}},
"public static const",{WATER_AQUA:function(){return new net.jangaron.TeamColor(TEAM_WATER,COLOR_AQUA);}},
"public static const",{PINK_PINK:function(){return new net.jangaron.TeamColor(TEAM_PINK,COLOR_PINK);}},

"public static const",{TEAMS_AND_COLORS:function(){return [
GOLD_ORANGE,
GOLD_RED,
GOLD_YELLOW,
BLUE_VIOLET,
BLUE_BLUE,
GREEN_CYAN,
GREEN_GREEN,
EARTH_SILICON,
EARTH_BROWN,
WATER_AQUA,
PINK_PINK
];}},

"public",function TeamColor(team,colorName){
this[_super]();
this[_team]=team;
this[_colorName]=colorName;
},

"public",function getTeam(){
return this[_team];
},

"public",function getColorName(){
return this[_colorName];
},

"private static const",{COLOR_BY_NAME:function(){return {
"Orange":new joo.css.Color(228,108,10),
"Red":new joo.css.Color(228,75,10),
"Yellow":new joo.css.Color(245,169,10),
"Violet":new joo.css.Color(125,0,150),
"Blue":new joo.css.Color(64,0,192),
"Cyan":new joo.css.Color(23,211,145),
"Green":new joo.css.Color(10,228,108),
"Silicon":new joo.css.Color(186,177,149),
"Brown":new joo.css.Color(166,149,103),
"Aqua":new joo.css.Color(115,209,193),
"Pink":new joo.css.Color(227,166,193)
};}},

"public",function getColor(){
return COLOR_BY_NAME[this[_colorName]];
},

"override public",function hashCode(){
return this.toString();
},

"override public",function equals(teamColor){
return this[_team]==teamColor.getTeam()&&this[_colorName]==teamColor.getColorName();
},

"override public",function toString(){
return[this[_team]," (",this[_colorName],")"].join("");
},

"private var",{team: undefined},
"private var",{colorName: undefined},
]}
);joo.Class.prepare("package net.jangaron",

"public class Trapez",function($jscContext){with(net.jangaron)with($jscContext)return[

"public",function setValues(color,x1,y1,x2,y2){
this.color=color;
if(x2<x1){

this.x1=x2;
this.y1=y2;
this.x2=x1;
this.y2=y1;
}else{
this.x1=x1;
this.y1=y1;
this.x2=x2;
this.y2=y2;
}
},

"public",function intersects(trapez){
return Math.max(this.x1,trapez.x1)<=Math.min(this.x2,trapez.x2);
},

"override public",function toString(){
return"["+[this.color,this.x1,this.y1,this.x2,this.y2].join(",")+"]";
},

"public var",{color: undefined},
"public var",{x1: undefined},
"public var",{y1: undefined},
"public var",{x2: undefined},
"public var",{y2: undefined},
]}
);joo.Class.prepare("package net.jangaron",

"public class ViewPort extends joo.html.Element",function($jscContext){with(net.jangaron)with($jscContext)return[

"private static const",{COLOR_BY_DIR:function(){return {N:"brighter",S:"darker"};}},
"private static const",{NUMBER_OF_GRID_LINES:20},
"private static const",{DEBUG:false},
"private static const",{Browser:function(){return joo.html.Browser_();}},
"private static const",{Color:function(){return joo.css.Color_();}},






"public static",function create(document,style){
if(!document){
var gameWindow=Browser.WINDOW.open();
document=new joo.html.Document(gameWindow);
document.write("<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>"
+"<html xmlns='http://www.w3.org/1999/xhtml'>"

+"<head><title>Jangaron</title><style>"
+"html { height: 100%; overflow: hidden; }"
+"body { overflow: hidden; padding: 0; margin: 0; border: 0; width: 100%; height: 100%; background-color: black; }"
+".canvas { display: block; overflow: hidden; margin: 0; padding: 0; left: 0; background-color: black; position: absolute; width: 100%; height: 100%; }"
+".slant { position: absolute; padding: 0; margin: 0; line-height: 0; width: 0; height: 0; border-style: solid; border-color: transparent; border-width: 0; }"
+"</style>"
+"<script>"
+"window.opener.joo$prepareWindow(window);"
+"</script>"
+"</head>"
+"<body></body>"
+"</html>");
document.close();
}
var div=document.createElement("div").setStyle(style);
document.getBody().appendChild(div);
return new ViewPort(document,div.getPeer());
},

"public",function ViewPort(document,viewPortId){
this[_super](document,viewPortId);
this.setClassName("viewport");
this.GRID_LINE_DISTANCE=10;
this.GRID_LINE_WIDTH=1;
this.VIEW_DEPTH=1e10;
this[_initDimensions]();
this.slantLineLayer=this[_createLayer]();
this.lineLayer=this[_createLayer]();
this[_wallLayer]=this[_createLayer]();
this[_hudLayer]=this[_createHUD]();
this[_createGridLines]();
document.getWindow().addEventListener("resize",function(){
this[_sizeDirty]=true;
}.bind(this),false);
},

"private",function createLayer(){
var div=this.ownerDocument.createElement("div");
this.appendChild(div);
return new joo.html.slant.SlantCanvas(this.ownerDocument,div.getPeer());
},

"private",function initDimensions(){
this[_sizeDirty]=false;
var dim=this.getDimensions();
this.WIDTH=dim.width;
this.HEIGHT=Math.min(dim.height,Math.round(this.WIDTH/2));
this.HORIZON=Math.round(this.HEIGHT/2);
this.SIDE=Math.round(this.WIDTH/2);
this.X_FACTOR=this.SIDE/this.HORIZON/this.GRID_LINE_DISTANCE;
this.Y_FACTOR=this.HORIZON*this.GRID_LINE_DISTANCE;
this.HALF_SLANT_LINE_WIDTH=this.GRID_LINE_WIDTH/2*this.SIDE/this.GRID_LINE_DISTANCE;
this[_leftOffset]=undefined;
this[_offset]=undefined;
},

"public",function setLightCycle(lightCycle){
this[_lightCycle]=lightCycle;
this[_initHUD](lightCycle);
},

"public",function getLightCycle(){
return this[_lightCycle];
},

"public",function setGrid(grid){
this.grid=grid;
},

"public",function getPosition(){
return this[_lightCycle].getViewPosition();
},

"public",function getY(yIndex){
return yIndex<0?this.HORIZON:this.Y_FACTOR/(this.GRID_LINE_DISTANCE+yIndex);
},

"public",function project(rw){
var y1=this.getY(Math.max(rw.y1,0));
var y2;
var x1;
var x2;
var xFactor=this.X_FACTOR;
var dir=this.getPosition().dir;
var isXWall=rw.y1==rw.y2;
if(isXWall||rw.x1==0&&rw.x2==0){
y2=y1;
if(isXWall){
xFactor*=y1;
x1=rw.x1*xFactor;
x2=rw.x2*xFactor;
if(x1>this.SIDE||x2<-this.SIDE){
return false;
}

x1=Math.max(x1,-this.SIDE-1);
x2=Math.min(x2,this.SIDE+1);
}else{
x1=0;
x2=1;
}
}else{
dir=rw.x1>0?dir.turnRight:dir.turnLeft;
y2=this.getY(rw.y2);
xFactor*=rw.x1;
x2=xFactor*y2;
if(Math.abs(x2)>this.SIDE){
return false;
}
x1=xFactor*y1;
var x1abs=Math.abs(x1);
if(x1abs>this.SIDE||rw.y1<=0&&rw.y2>0&&x1abs<this.SIDE){

var side=rw.x1<0?-this.SIDE-1:this.SIDE+1;
y1=side*y1/x1;
x1=side;
}
}
var color=rw.wall.color;
var colorChange=COLOR_BY_DIR[dir];
if(colorChange){
color=color[colorChange]();
}
rw.wallProjection.setValues(color,x1,y1,x2,y2);
return true;
},

"private",function insertRelativeWall(relativeWalls,newRelativeWall,
unhiddenRelativeWalls){


var isUnhidden=true;
for(var ws=0;ws<relativeWalls.length;++ws){
var relativeWall=relativeWalls[ws];
if(newRelativeWall.wallProjection.intersects(relativeWall.wallProjection)){
if(!newRelativeWall.updateMaybeHides(relativeWall,unhiddenRelativeWalls)){
if(relativeWall.updateMaybeHides(newRelativeWall,unhiddenRelativeWalls)){
isUnhidden=false;
}
}
}
}
relativeWalls.push(newRelativeWall);
if(isUnhidden){
unhiddenRelativeWalls.add(newRelativeWall);
}
},

"public",function update(){
if(this[_sizeDirty]){
this[_initDimensions]();
}
this[_updateHUD]();
var position=this.getPosition();
this[_updateSlantLines](position);
this[_updateLines](position);
var relativeWalls=[];
var unhiddenRelativeWalls=new joo.util.HashSet();
var walls=this.grid.walls;
var relativeWall;
var viewPortKey="_"+this.hashCode();
for(var w=0;w<walls.length;++w){
var wall=walls[w];
var relativeWallsByViewPort=wall.relativeWalls;
relativeWall=relativeWallsByViewPort[viewPortKey];
if(!relativeWall){
relativeWallsByViewPort[viewPortKey]=relativeWall=new RelativeWall(walls[w]);
}
relativeWall.update(position);
if((relativeWall.y1>=0||relativeWall.y2>=0)&&(relativeWall.y1<this.VIEW_DEPTH||relativeWall.y2<this.VIEW_DEPTH)){

if(this.project(relativeWall)){
this[_insertRelativeWall](relativeWalls,relativeWall,unhiddenRelativeWalls);
}
}
}
var zIndex=10000;
var zBuffer=new ZBuffer();
var slant;
var WHITE=new joo.css.Color(245,245,245);
this[_wallLayer].rewind();
while(relativeWall=unhiddenRelativeWalls.pop()){
relativeWall.removedFromUnhidden(unhiddenRelativeWalls);
if(DEBUG&&!relativeWalls.remove(relativeWall)){
throw"Element not present: "+relativeWall+" in ["+relativeWalls.join(",")+"]";
}
var wallProjection=relativeWall.wallProjection;
var x1=this.SIDE+wallProjection.x1;
var x2=this.SIDE+wallProjection.x2;

var opacity=relativeWall.wall.getOpacity();
var isHighRim=this.grid.highRim&&relativeWall.wall.color===Color.GRAY;

var isVisible=isHighRim
||(opacity==1?zBuffer.addInterval(x1,x2):zBuffer.isIntervalVisible(x1,x2));
if(isVisible){
var y1=wallProjection.y1;
var y2=wallProjection.y2;
var opaque=opacity==1?1:0;
var y1top=isHighRim?-opaque:this.HORIZON-y1;
if(y1==y2){
slant=this[_wallLayer].addRect(wallProjection.color,
x1,y1top,x2,this.HORIZON+y1,
zIndex--,opacity,WHITE,-opaque);
}else{
var y2top=isHighRim?-opaque:this.HORIZON-y2;
var x1border=x1+opaque;
var x2border=x2-opaque;
if(y1>this.HORIZON){



x1=x2+(x2-x1)*(1/(y2-y1))*(this.HORIZON-y2);
y1=this.HORIZON+opaque;y1top=-opaque;
this[_wallLayer].addRect(wallProjection.color,
0,0,x1,this.HEIGHT,
zIndex,opacity);
x1border=x1;
}else if(y2>this.HORIZON){


x2=x1+(x2-x1)*(1/(y2-y1))*(this.HORIZON-y1);
y2=this.HORIZON+opaque;y2top=-opaque;
this[_wallLayer].addRect(wallProjection.color,
x2,0,this.WIDTH,this.HEIGHT,
zIndex,opacity);
x2border=x2;
}
if(x1border<=x2border){
slant=this[_wallLayer].addSlant(wallProjection.color,
x1border,y1top+opaque,x1border,this.HORIZON+y1-opaque,
x2border,y2top+opaque,x2border,this.HORIZON+y2-opaque,
zIndex--,opacity);
}
if(opaque){
slant=this[_wallLayer].addSlant(WHITE,
x1,y1top,x1,this.HORIZON+y1,
x2,y2top,x2,this.HORIZON+y2,
zIndex--,opacity);
}
}
if(DEBUG){
slant["id"]="rw"+relativeWall.hashCode();slant["rw"]=relativeWall;
}
}else if(DEBUG){
console.debug("hidden wall: "+relativeWall.toString1());
}
}
if(DEBUG&&relativeWalls.length!=0){
throw"Some walls not rendered: ["+relativeWalls.join(",")+"]";
}
this[_wallLayer].clearRest();
if(Browser.ENGINE===Browser.ENGINE_OPERA){
this[_operaClassToggle]=!this[_operaClassToggle];
this.setClassName("viewport"+(this[_operaClassToggle]?" foo":""));
}
},

"private",function createGridLines(){
this[_slantLines]=[];
for(var i=0;i<NUMBER_OF_GRID_LINES/2;++i){
this[_slantLines].push(new SlantLine(this,-i));
this[_slantLines].push(new SlantLine(this,i+1));
}
this[_lines]=[];
for(i=1;i<=NUMBER_OF_GRID_LINES;++i){
this[_lines].push(new Line(this,i*this.GRID_LINE_DISTANCE));
}
},

"private",function updateSlantLines(position){
var newLeftOffset=position.getLeftOffset(this.GRID_LINE_DISTANCE);
if(newLeftOffset!=this[_leftOffset]){
this[_leftOffset]=newLeftOffset;
this.slantLineLayer.rewind();
this[_slantLines].broadcast("update",this.GRID_LINE_DISTANCE-newLeftOffset);
}
},

"private",function updateLines(position){
var newOffset=position.getOffset(this.GRID_LINE_DISTANCE);
if(newOffset!=this[_offset]){
this[_offset]=newOffset;
this[_lines].broadcast("update",newOffset);
var furthestLine=this.lineLayer.getItem(this.lineLayer.getItemCount()-1).style;
furthestLine.height=(parseInt(furthestLine.top)+parseInt(furthestLine.height)-this.HORIZON)+"px";
furthestLine.top=this.HORIZON+"px";

}
},

"private",function createHUD(){
var newHudLayer=this[_createLayer]();
var document=this.ownerDocument;

var hud=document.createElement("div").setAttributes({className:"hud",style:{
color:Color.WHITE,
zIndex:"20000",opacity:".75"
}});
hud.appendChild(document.createTextNode(""));
newHudLayer.appendChild(hud);

var speedContainer=document.createElement("div").setAttributes({className:"speed",style:{
zIndex:"20000",opacity:".75"
}});
var speedIndicator=document.createElement("div");
speedIndicator.appendChild(document.createTextNode(String.fromCharCode(160)));
speedContainer.appendChild(speedIndicator);
var speed=document.createElement("div").setStyle({
color:Color.WHITE,position:"absolute"
});
speed.appendChild(document.createTextNode("0"));
speedContainer.appendChild(speed);
newHudLayer.appendChild(speedContainer);
this[_renderedSpeed]=0;
return newHudLayer;
},

"private",function initHUD(lightCycle){
var hud=this[_hudLayer].getItem(0);
var speedContainer=hud.nextSibling;
speedContainer.style["backgroundColor"]=hud.style["backgroundColor"]=lightCycle.getColor().toString();
speedContainer.firstChild.style["backgroundColor"]=lightCycle.getColor().darker().toString();
},

"private",function updateHUD(){
var position=this.getPosition();
this[_hudLayer].getItem(0).firstChild.data=[this[_lightCycle].getName(),
"| x",Math.round(position.x).toString(10,3),"y",Math.round(position.y).toString(10,3),position.dir.getCompassArrow()].join(" ");

var newRenderedSpeed=Math.round(this[_lightCycle].speed);
if(newRenderedSpeed!=this[_renderedSpeed]){
var speedContainer=this[_hudLayer].getItem(1);
var speedIndicator=speedContainer.firstChild;
var maxSpeed=this[_lightCycle].maxSpeed;
var widthPercent=Math.round(100*newRenderedSpeed/maxSpeed);
speedIndicator.style.width=widthPercent+"%";
speedContainer.lastChild.firstChild.data=String(newRenderedSpeed);
this[_renderedSpeed]=newRenderedSpeed;
}
},

"public var",{GRID_LINE_DISTANCE: undefined},
"public var",{GRID_LINE_WIDTH: undefined},
"public var",{HALF_SLANT_LINE_WIDTH: undefined},
"public var",{VIEW_DEPTH: undefined},
"public var",{WIDTH: undefined},
"public var",{HEIGHT: undefined},
"public var",{HORIZON: undefined},
"public var",{SIDE: undefined},
"public var",{X_FACTOR: undefined},
"public var",{Y_FACTOR: undefined},
"public var",{grid: undefined},
"private var",{lightCycle: undefined},
"private var",{sizeDirty: undefined},
"private var",{leftOffset: undefined},
"private var",{slantLines: undefined},
"private var",{offset: undefined},
"private var",{lines: undefined},
"public var",{lineLayer: undefined},
"public var",{slantLineLayer: undefined},
"private var",{wallLayer: undefined},
"private var",{hudLayer: undefined},
"private var",{renderedSpeed: undefined},
"private var",{operaClassToggle:false},
]}
);joo.Class.prepare("package net.jangaron",

"public class Wall",function($jscContext){with(net.jangaron)with($jscContext)return[

"private static const",{DEBUG:false},

"public",function Wall(color,p1,p2,opacityHolder){
this[_super]();
this.color=color;
if(typeof p1=="number"){
this.x1=this.x2=p1;
}else{
this.x1=p1[0];
this.x2=p1[1];
}
if(typeof p2=="number"){
this.y1=this.y2=p2;
}else{
this.y1=p2[0];
this.y2=p2[1];
}
this[_opacityHolder]=opacityHolder;
if(DEBUG){
this.check();
}
},

"public",function getOpacity(){
return this[_opacityHolder]?this[_opacityHolder].getOpacity():1;
},

"public",function check(){
if(!(this.x1<=this.x2&&this.y1<=this.y2)){
throw new Error("Wall: IllegalArgument: "+this);
}
},

"public",function intersects(wall){
return Math.max(this.x1,wall.x1)<=Math.min(this.x2,wall.x2)
&&Math.max(this.y1,wall.y1)<=Math.min(this.y2,wall.y2);
},

"override public",function toString(){
return["[",this.x1,",",this.y1,"|",this.x2,",",this.y2,"]"].join("");
},

"public var",{color: undefined},
"public var",{brightColor: undefined},
"public var",{darkColor: undefined},
"private var",{opacityHolder: undefined},
"public var",{x1: undefined},
"public var",{y1: undefined},
"public var",{x2: undefined},
"public var",{y2: undefined},
"public var",{relativeWalls:function(){return {};}},
"public var",{lightCycle: undefined},
]}
);joo.Class.prepare("package net.jangaron",

"public class ZBuffer",function($jscContext){with(net.jangaron)with($jscContext)return[

"public",function ZBuffer(){
this[_intervals]=[];
},

"public",function isIntervalVisible(a,b){
var thisIntervals=this[_intervals];
var aIndex=thisIntervals.binarySearch(a);

return aIndex<0||b>thisIntervals[aIndex]["b"];
},

"public",function addInterval(a,b){
var thisIntervals=this[_intervals];
var aIndex=thisIntervals.binarySearch(a);
if(aIndex>=0){
var aInterval=thisIntervals[aIndex];

if(b<=aInterval.b){
return false;
}
a=aInterval.a;
}else{
aIndex=-aIndex-1;
}
var bIndex=thisIntervals.binarySearch(b);
if(bIndex>=0){
b=thisIntervals[bIndex]["b"];
}else{
bIndex=-bIndex-2;
}
var newInterval=new joo.util.Interval(a,b);

thisIntervals.splice(aIndex,bIndex-aIndex+1,newInterval);
return true;
},

"override public",function toString(){
return this[_intervals].join(" ");
},

"private var",{intervals:function(){return [];}},
]}
);