//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
  };
}

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);
// Copyright 2008 CoreMedia AG
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an "AS
// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language
// governing permissions and limitations under the License.

// JangarooScript runtime support. Author: Frank Wienberg

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.prototype.bind = function(object) {
  var fn = this;
  return function() {
    return fn.apply(object,arguments);
  };
};

(function(theGlobalObject) {
  function initFields(privateBean, publicBean, fieldNamesAndInitializers) {
    for (var i=0; i<fieldNamesAndInitializers.length; ++i) {
      var fieldNameOrInitializer = fieldNamesAndInitializers[i];
      if (typeof fieldNameOrInitializer == "function") {
        fieldNameOrInitializer();
      } else {
        //alert("init field: "+fieldNameOrInitializer);
        var bean = publicBean[fieldNameOrInitializer] ? publicBean : privateBean;
        bean[fieldNameOrInitializer] = bean[fieldNameOrInitializer]();
      }
    }
  }
  function createPackage(packageName) {
    var $package = theGlobalObject;
    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 createEmptyConstructor($prototype) {
    var emptyConstructor = function(){};
    emptyConstructor.prototype =  $prototype;
    return emptyConstructor;
  };
  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; });
  }
  function emptySuper() {}
  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: "Object",
        level: undefined,
        state: PENDING,
        superClassDescription: undefined,
        $constructor: undefined,
        Public: undefined,
        publicConstructor: undefined,
        createInitializingPublicStaticMethod: function(methodName) {
          var classDescription = this;
          this.publicConstructor[methodName] = function() {
            classDescription.initialize();
            return classDescription.publicConstructor[methodName].apply(null, arguments);
          };
        },
        /**
         * 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.$extends=="Object") {
            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);
          };
          // TODO: only if public:
          this.$package = createPackage(this.$package);
          var className = this.$class;
          this.$package[className] = this.publicConstructor = setFunctionName(function() {
            classDescription.$constructor.apply(this,arguments);
          }, this.fullClassName);
          // to initialize when calling the first public static method, wrap those methods:
          for (var i=0; i<this.$publicStaticMethods.length; ++i) {
            this.createInitializingPublicStaticMethod(this.$publicStaticMethods[i]);
          }
          if (this.superClassDescription) {
            this.publicConstructor.prototype = new (this.superClassDescription.Public)();
          }
          // TODO: only if not final:
          this.Public = createEmptyConstructor(this.publicConstructor.prototype);
          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.publicConstructor;
          this.state = INITIALIZING;
          // finish object structure setup of this class:
          // public part: avoid recursion!
          this.$constructor = undefined;

          // private part of the object structure:
          if (false && this.$extends!="Object" && this.superClassDescription == null) {
            throw new Error("Super class "+this.$extends+" of class "+this.fullClassName+" is not prepared.");
          }
          var classPrefix = this.level; // + "$";
          var fieldsWithInitializer = [];
          var classDescription = this;
          var superName = classPrefix+"super";
          // static part:
          var publicConstructor = this.publicConstructor;
          var 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: publicConstructor,
              $protected: publicConstructor,
              $private: privateStatic
            }
          };
          if (isFunction(this.$members)) {
            var memberDeclarations = this.$members(publicConstructor, 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 memberName = undefined;
              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: ignore. TODO: enable super-call!
                  } else if (j==modifiers.length-1) {
                    // last "modifier" may be the member name:
                    memberName = modifier;
                  } 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):");
	      if (memberType=="function") {
                if (!memberName) {
                  // found static code block; execute on initialization
                  targetMap.$static.fieldsWithInitializer.push(members);
                } else {
                  if (memberName=="_"+this.$class) {
                    this.$constructor = members;
                    memberName = this.$class;
                  } 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];
                    }
                  }
                  setFunctionName(members, 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)) {
                    targetFieldsWithInitializer.push(memberName);
                  }
                }
              }
            }
          }
          this.Public.prototype[superName] =
            classDescription.superClassDescription
            ? fieldsWithInitializer.length > 0
              ? (function $super() {
                   classDescription.superClassDescription.$constructor.apply(this,arguments);
                   initFields(null, this, fieldsWithInitializer);
                 })
              : classDescription.superClassDescription.$constructor
            : fieldsWithInitializer.length > 0
              ? (function $super() {
                   initFields(null, this, fieldsWithInitializer);
                 })
              : emptySuper;
          if (!this.$constructor) {
            this.$constructor = createDefaultConstructor(superName);
          }
          this.Public.prototype.getClass = createGetClass(publicConstructor);
          // TODO: constructor visibility!
          privateStatic[this.$class] = publicConstructor;
          // init static fields with initializer:
          for (var im in this.$imports) {
            var importDecl = this.$imports[im];
            var importedClassDesc = getClassDescription(importDecl);
            if (importedClassDesc) { // ignore unknown imports!
              privateStatic[im] = importedClassDesc.initialize();
            }
          }
          initFields(privateStatic, publicConstructor, targetMap.$static.fieldsWithInitializer);
          return publicConstructor;
        }
      };
    }
    ClassDescription.$static = ClassDescription$static;
    return ClassDescription;
  })();
  function Package() { }
  theGlobalObject.joo = new Package();
  var loadedClasses = {};
  theGlobalObject.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);
      }
    },
    run: function(mainClass) {
      if (typeof mainClass=="string") {
        this.load(mainClass);
        mainClass = eval(mainClass);
      }
      var args = [];
      for (var i=1; i<arguments.length; ++i) {
        args.push(arguments[i]);
      }
      var self = this;
      theGlobalObject.onload = function() {
        self.complete();
        mainClass.main.apply(null,args);
      }
    },
    prepare: function(packageDef /* import*, classDef, publicStaticMethods, members */) {
      var classDef = arguments[arguments.length-3];
      var publicStaticMethods = arguments[arguments.length-2];
      var members = arguments[arguments.length-1];
      var imports = {};
      for (var im=1; im<arguments.length-3; ++im) {
        var importDecl = arguments[im].split(" ")[1];
        var lastDotPos = importDecl.lastIndexOf(".");
        var abbr = importDecl.substring(lastDotPos+1);
        imports[abbr] = importDecl;
      }
      var classDesc = { $imports: imports, $publicStaticMethods: publicStaticMethods, $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 (imports[classDesc.$extends]) {
          classDesc.$extends = imports[classDesc.$extends];
        }
      }
      if (i<classParts.length)
        throw new Error("unexpected token '"+classParts[i]+" after class declaration.");
      new ClassDescription(classDesc);
    },
    init: function(clazz) {
      return ClassDescription.$static.getClassDescription(clazz.getName()).initialize();
    },
    complete: function() {
      var sb = [];
      var pendingCDsMap = ClassDescription.$static.pendingClassDescriptions;
      for (var missingClassName in pendingCDsMap) {
        if (sb.length > 0) sb.push(" ");
        sb.push("The following classes are waiting for their super class ",
          missingClassName,
          ": ");
        var pendingCDs = pendingCDsMap[missingClassName];
        for (var i = 0; i < pendingCDs.length; ++i) {
          if (i > 0) sb.push(", ");
          sb.push(pendingCDs[i].fullClassName);
        }
        sb.push(".");
      }
      if (sb.length > 0) {
        throw new Error(sb.join(""));
      }
    }
  };
})(this);
//  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",

"import joo.lang.JOObject",
"import joo.lang.JsonBuilder",

"public class Color extends JOObject",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)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 _Color",function(red,green,blue){
this[_super]();
this[_red]=red;
this[_green]=green;
this[_blue]=blue;
this[_updateAsString]();
},

"private updateAsString",function(){
this[_asString]=this[_red]<0
?"transparent"
:["rgb(",Math.round(this[_red]),",",Math.round(this[_green]),",",Math.round(this[_blue]),")"].join("");
},

"public clone",function(){
return new Color(this[_red],this[_green],this[_blue]);
},

"public getDarker",function(){
return this.darker();
},

"public darker",function(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 getBrighter",function(){
return this.brighter();
},

"public brighter",function(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 hashCode",function(){
return this[_asString];
},

"override public equals",function(color){
return color&&this[_asString]==color.toString();
},

"private static const",{JSON_PROPERTIES:function(){return ["1red","1green","1blue"];}},

"override protected isJsonProperty",function(property){
return JSON_PROPERTIES.contains(property);
},

"override protected addPropertiesFromJson",function(json,jsonBuilder){
this[_addPropertiesFromJson](json,jsonBuilder);
this[_updateAsString]();
},

"override public toString",function(){
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.css",

"public class URL",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"private static const",{TO_STRING:function(){return ["url(",")"];}},

"public _URL",function(url){this[_super]();
this.url=url;
},

"override public toString",function(){
return TO_STRING.join(this.url);
},

"public var",{url: undefined},
]}
);joo.Class.prepare("package joo.html",
"public class Browser",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)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($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public _Dimensions",function(width,height){this[_super]();
this.width=width;
this.height=height;
},

"public var",{width: undefined},
"public var",{height: undefined},
]}
);joo.Class.prepare("package joo.html",

"import joo.html.Element",

"public class Document",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public static const",{INSTANCE:function(){return new Document();}},

"public _Document",function(ownerWindow){
this[_super]();
this.ownerWindow=ownerWindow?ownerWindow:window;
this[_peer]=this.ownerWindow.document;
},

"public getPeer",function(){
return this[_peer];
},

"public getWindow",function(){
return this.ownerWindow;
},

"public createElement",function(elementName){
return new Element(this,this[_peer].createElement(elementName));
},

"public createTextNode",function(text){

return this[_peer].createTextNode(text);
},

"public getElement",function(peerOrId){
var thePeer=typeof peerOrId=="string"?this[_peer].getElementById(peerOrId):peerOrId;
if(!thePeer){
throw"Undefined Element "+peerOrId;
}
return new Element(this,thePeer);
},

"public getDocumentElement",function(){
return this.getElement(this[_peer].documentElement);
},

"public getBody",function(){
if(!this[_body]){
this[_body]=this.getElement(this[_peer].getElementsByTagName("body")[0]);
}
return this[_body];
},

"public write",function(text){
this[_peer].write(text);
},

"public close",function(){
this[_peer].close();
},

"override public toString",function(){
return"Document "+this[_peer];
},

"public var",{ownerWindow: undefined},
"private var",{peer: undefined},
"private var",{body: undefined},
]}
);joo.Class.prepare("package joo.html",

"import joo.lang.JOObject",
"import joo.html.Dimensions",
"import joo.html.Offset",

"public class Element extends JOObject",["setCssText"],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public _Element",function(ownerDocument,peer){
this[_super]();
this.ownerDocument=ownerDocument;
this[_peer]=peer;
},

"public getPeer",function(){
return this[_peer];
},

"private static const",{PREVENT_DEFAULT:function(){return (function preventDefault(){
this["returnValue"]=false;
});}},

"private static const",{STOP_PROPAGATION:function(){return (function stopPropagation(){
this["cancelBubble"]=true;
});}},

"private createIEEventHandler",function(listener){
return function(){
var event=window.event;
event.preventDefault=PREVENT_DEFAULT;
event.stopPropagation=STOP_PROPAGATION;

var body=window.document["body"];
event.pageX=event.clientX+body.scrollLeft;
event.pageY=event.clientY+body.scrollTop;
return listener(event);
};
},

"public addEventListener",function(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 setId",function(id){
this[_peer].id=id;
return this;
},

"public setClassName",function(className){
this[_peer].className=className;
return this;
},

"public setAttributes",function(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;
},

"public getAttribute",function(name){
return this[_peer].getAttribute(name);
},

"private static convertToString",function(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 setCssText",function(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 setStyle",function(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 remove",function(){
this[_peer].parentNode.removeChild(this[_peer]);
return this;
},

"public appendChild",function(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 getParentElement",function(){
return this.ownerDocument.getElement(this[_peer].parentNode);
},

"public getOffset",function(){
return new Offset(this[_peer].offsetLeft,this[_peer].offsetTop);
},

"public setOffset",function(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 getAbsoluteOffset",function(){
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 getDimensions",function(){
var thisPeer=this[_peer];
return new Dimensions(thisPeer.offsetWidth,thisPeer.offsetHeight);
},

"override public toString",function(){
return this[_peer].id||this[_peer].nodeName;
},

"public var",{ownerDocument: undefined},
"private var",{peer: undefined},
]}
);joo.Class.prepare("package joo.html",

"public class Offset",["getOffset"],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public static var",{HOME:function(){return new Offset(0,0);}},

"public _Offset",function(left,top){this[_super]();
this.left=left;
this.top=top;
},

"public static getOffset",function(offsetOrLeft,top){
if(top!==undefined){
return new Offset(offsetOrLeft,top);
}
return offsetOrLeft;
},

"public clone",function(){
return new Offset(this.left,this.top);
},

"public plus",function(offsetOrLeft,top){
var offset=getOffset(offsetOrLeft,top);
return new Offset(this.left+offset.left,this.top+offset.top);
},

"public minus",function(offsetOrLeft,top){
var offset=getOffset(offsetOrLeft,top);
return new Offset(this.left-offset.left,this.top-offset.top);
},

"public getDistance",function(){
return Math.sqrt(this.left*this.left+this.top*this.top);
},

"public scale",function(factor){
return new Offset(this.left*factor,this.top*factor);
},

"public isHome",function(){
return this.left==0&&this.top==0;
},

"override public toString",function(){
return[this.left,"px ",this.top,"px"].join("");
},

"public var",{left: undefined},
"public var",{top: undefined},
]}
);joo.Class.prepare("package joo.html.slant",

"import joo.html.Document",
"import joo.html.Element",
"import joo.html.Browser",
"import joo.css.Color",

"public class SlantCanvas extends Element",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public _SlantCanvas",function(document,canvas){
this[_super](document,canvas);
this.setAttributes({className:"canvas"});
},

"override public appendChild",function(child){
++this[_divIndex];
return this[_appendChild](child);
},

"private static rectCssText",function(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 add",function(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 addRect",function(color,
x0,y0,x1,y1,
zIndex,opacity,
borderColor,borderWidth){
return this[_add](rectCssText(color.toString(),Math.round(x0),Math.round(y0),Math.round(x1),Math.round(y1),String(borderColor),borderWidth),zIndex,opacity);
},



























"public addSlant",function(color,
x00,y00,x01,y01,
x10,y10,x11,y11,
zIndex,opacity,
borderColor,borderWidth){
color=color.toString();
borderColor=String(borderColor);
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 dx0=x00-x01;
var dx1=x10-x11;
var dy0=y00-y10;
var dy1=y01-y11;
var cssText;
if(dx0==0&&dx1==0){
if(dy0==0&&dy1==0){

cssText=rectCssText(color,x00,y00,x11,y11,borderColor,borderWidth);
}else if(dy0>=0&&dy1<=0){

cssText=["left:",x00,"px;top:",y10,"px;border-right-color:",color,
";border-width:",dy0,"px ",x11-x00,"px ",-dy1,"px 0;height:",y01-y00,"px;"];
}else if(dy0<=0&&dy1>=0){

cssText=["left:",x00,"px;top:",y00,"px;border-left-color:",color,
";border-width:",-dy0,"px 0 ",dy1,"px ",x11-x00,"px;height:",y11-y10,"px;"];
}
}else if(dx0<=0&&dx1>=0){

cssText=["left:",x00,"px;top:",y00,"px;border-top-color:",color,
";border-width:",y11-y00,"px ",dx1,"px 0 ",-dx0,"px;width:",x11-x01,"px;"];
}else if(dx0>=0&&dx1<=0){

cssText=["left:",x01,"px;top:",y00,"px;border-bottom-color:",color,
";border-width:0 ",-dx1,"px ",y11-y00,"px ",dx0,"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 rewind",function(offset){
if(offset===undefined){
offset=0;
}
this[_divIndex]=offset;
},

"public clearRest",function(){
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 getItemCount",function(){
return this[_divIndex];
},

"public getItem",function(index){
return this.getPeer().childNodes[index];
},

"private var",{divIndex:0},
"private var",{lastDivIndex:0},
]}
);joo.Class.prepare("package joo.lang",

"import joo.lang.JsonBuilder",

"public class JOObject",["getHashCode","equal","toJsonString","fromJsonString","toJsonObject","fromJsonObject"],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"private static var",{idCnt:0},function()

{

Array.prototype["hashCode"]=JOObject.prototype["hashCode"];
Array.prototype["equals"]=JOObject.prototype["0arrayEquals"];
},

"public static getHashCode",function(obj){
return obj&&typeof obj.hashCode=="function"?obj.hashCode():"_"+obj;
















},

"public static equal",function(o1,o2){
return o1===o2||o1&&typeof o1.equals=="function"&&o1.equals(o2);
},

"private arrayEquals",function(a){
if(this.length==a.length){
for(var i=0;i<this.length;++i){
if(!equal(this[i],a[i])){
return false;
}
}
return true;
}
return false;
},

"public static toJsonString",function(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 fromJsonString",function(str,secure){
return((typeof str!="string")||(secure&&!JSON_REG_EXP.test(str)))?null:eval('('+str+')');
},

"public static toJsonObject",function(obj){
return new JsonBuilder().toJsonObject(obj);
},

"public static fromJsonObject",function(json){
return new JsonBuilder().fromJsonObject(json);
},

"public getClass",function(){
return this["constructor"];
},

"public hashCode",function(){
return this["0id"]||(this["0id"]="_"+(idCnt++));
},

"public equals",function(joobject){
return this===joobject;
},

"public toJson",function(){
return new JsonBuilder().toJsonObject(this);
},

"protected addPropertiesToJson",function(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 isJsonProperty",function(property){
var value=this[property];
return typeof value!="function"&&value!==this.getClass().prototype[property];
},

"public fromJson",function(json){
this.addPropertiesFromJson(json,new JsonBuilder());
},

"protected addPropertiesFromJson",function(json,jsonBuilder){

for(var property in json){
if(property.charAt(0)!='$'){
this[property]=jsonBuilder.fromJsonObject(json[property]);
}
}
},

"override public toString",function(){
return this.getClass()["getName"]()+"@"+this.hashCode();
},

]}
);joo.Class.prepare("package joo.lang",
"class JsonBuilder",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return["toJsonObject",

function(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={};
JOObject.prototype.addPropertiesToJson.call(obj,json,this);
return json;
},"fromJsonObject",

function(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={};
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",

"import joo.html.Browser",
"import joo.html.Document",
"import joo.html.Element",
"import joo.util.TimedExecutor",
"import SoundBridge2",

"public class Sound",["init","isAvailable","callbackOnLoad","callbackOnSoundComplete","callbackOnID3"],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"private static const",{DEBUG:false},
"private static const",{FLASH_CONTAINER:function(){return (Browser.ENGINE==Browser.ENGINE_IE6||Browser.ENGINE==Browser.ENGINE_IE7||Browser.ENGINE==Browser.ENGINE_OPERA
?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 init",function(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 TimedExecutor(function(){
trace("Waiting for SoundBridge...");
soundBridge=FLASH_CONTAINER[SWF_ID];
if(!soundBridge||"nodeName"in soundBridge&&soundBridge["nodeName"]["toLowerCase"]()=="div"
||typeof soundBridge["data"]=="string"&&soundBridge["data"]["substring"](0,4)=="file"){
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 isAvailable",function(){
return soundAvailable;
},

"public _Sound",function(url,startImmediately){
this[_super]();
this[_index]=soundBridge.newSound();
INSTANCES[this[_index]]=this;
if(url){
this.loadSound(url,false);
if(startImmediately){
this.start();
}
}
},

"private call",function(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 loadSound",function(url,streaming){
this[_call]("loadSound",[url,streaming]);
},

"public start",function(secondOffset,loops){
if(this[_loaded]){
this[_call]("start",secondOffset===undefined?[]:[secondOffset,loops]);
}else{
this[_startOnLoad]=function(){
this.start(secondOffset,loops);
};
}
},

"public stop",function(){
this[_call]("stop",[]);
},

"public fade",function(duration,targetVolume){
var startVolume=this.getVolume();
var volumeDelta=targetVolume-startVolume;

var sound=this;
var startTime=new Date().getTime();
this[_fader]=new 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 getId3",function(){
return this[_call]("id3",[]);
},

"public getPan",function(){
return this[_call]("getPan",[]);
},

"public getTransform",function(){
return this[_call]("getTransform",[]);
},

"public getVolume",function(){
return this[_call]("getVolume",[]);
},

"public setPan",function(value){
this[_call]("setPan",[value]);
return this;
},

"public setTransform",function(transformObject){
this[_call]("setTransform",[transformObject]);
return this;
},

"public setVolume",function(value){
this[_call]("setVolume",[value]);
return this;
},

"public getDuration",function(){
return this[_call]("getDuration",[]);
},

"public getPosition",function(){
return this[_call]("getPosition",[]);
},

"public getBytesLoaded",function(){
return this[_call]("getBytesLoaded",[]);
},

"public getBytesTotal",function(){
return this[_call]("getBytesTotal",[]);
},

"public var",{onLoad:function(){return (function onLoad(success){
});}},

"public internalOnLoad",function(success){
this[_loaded]=true;
if(this[_startOnLoad]){
this[_startOnLoad]();
}
this.onLoad(success);
},

"private static getInstance",function(index){
return INSTANCES[index];
},

"public static callbackOnLoad",function(index,success){
trace("Sound.onLoad("+success+") index="+index);
getInstance(index).internalOnLoad(success);
},

"public var",{onSoundComplete:function(){return (function onSoundComplete(){
});}},

"public static callbackOnSoundComplete",function(index){
trace("Sound:onSoundComplete() event triggered");
getInstance(index).onSoundComplete();
},

"public onID3",function(){
},

"public static callbackOnID3",function(index){
trace("Sound:onID3() event triggered");
getInstance(index).onID3();
},

"private static trace",function(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($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public _GapArrayIterator",function(elements){
this[_super]();
this[_elements]=elements;
this[_findNext]();
},
"public hasNext",function(){
return this[_index]<this[_elements].length;
},
"public next",function(){
var next=this[_elements][this[_index]];
this[_findNext]();
return next;
},
"private findNext",function(){
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",

"import joo.lang.JOObject",
"import joo.util.GapArrayIterator",

"public class HashSet extends JOObject",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public _HashSet",function(element){
this[_super]();
this[_reset]();
if(element){
if(!this.addAll(element)){
this.add(element);
}
}
},
"public getSize",function(){
return this[_size];
},
"public isEmpty",function(){
return this[_size]==0;
},
"public iterator",function(){
return new GapArrayIterator(this[_elements]);
},
"public add",function(element){
if(element===undefined){
throw"IllegalArgument: may not add undefined to HashSet.";
}
var hashCode=JOObject.getHashCode(element);
if(hashCode in this[_indexByHashCode]){
return false;
}
this[_indexByHashCode][hashCode]=this[_elements].length;
this[_elements].push(element);
++this[_size];
return true;
},
"public addAll",function(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 pop",function(){
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][JOObject.getHashCode(result)];
return result;
}
}
return undefined;
},
"public remove",function(element){
var hashCode=JOObject.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 reset",function(){
this[_indexByHashCode]={};
this[_elements]=[];
this[_size]=0;
},
"public clear",function(){
this[_reset]();
},
"public contains",function(element){
return this[_indexByHashCode][JOObject.getHashCode(element)]!==undefined;
},
"private var",{indexByHashCode: undefined},
"private var",{elements: undefined},
"private var",{size: undefined},
"override public toString",function(){
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",["create"],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public static create",function(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 _Interval",function(a,b){this[_super]();
this.a=a;
this.b=b;
if(a>b){
throw"Interval: IllegalArguments "+this;
}
},

"public contains",function(n){
return this.a<=n&&n<=this.b;
},

"public includes",function(interval){
return this.a<=interval.a&&this.b>=interval.b;
},

"public intersection",function(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 compareTo",function(c){
return this.a>c?1:this.b<c?-1:0;
},

"public toString",function(){
return["[",this.a,",",this.b,"]"].join("");
},

"public var",{a: undefined},
"public var",{b: undefined},
]}
);joo.Class.prepare("package joo.util",

"public class TimedExecutor",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public _TimedExecutor",function(handler,timeout){this[_super]();
this[_handler]=handler;
this[_timeout]=timeout;
this[_trigger]=this[_trigger].bind(this);
},

"private setTimeout",function(delay){
this[_timer]=window.setTimeout(this[_trigger],Math.max(this[_timeout]-delay,0));
},

"private trigger",function(){
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 getTriggerStartTime",function(){
return this[_triggerStartTime];
},

"public getLastTriggerStartTime",function(){
return this[_lastTriggerStartTime];
},

"public isRunning",function(){
return! !this[_timer];
},

"public start",function(){
if(!this[_timer]){
this[_lastTriggerStartTime]=new Date().getTime();
this[_setTimeout](0);
return true;
}
return false;
},

"public stop",function(){
if(this[_timer]){
window.clearTimeout(this[_timer]);
this[_timer]=undefined;
return true;
}
return false;
},

"public restart",function(){
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($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)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 _Direction",function(name,dx,dy,compassArrow){this[_super]();
DIRS.push(this);++DIRS_COUNT;
this[_name]=name;
this.dx=dx;
this.dy=dy;
this[_compassArrow]=compassArrow;
},

"public getCompassArrow",function(){
return this[_compassArrow];
},

"override public toString",function(){
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 joo.sound.Sound",
"import joo.html.Document",
"import joo.html.Element",
"import joo.css.Color",
"import joo.util.TimedExecutor",
"import joox.faces.Transformer",
"import joox.faces.component.UIViewRoot",
"import net.jangaron.ui.Settings",

"public class Game",["main"],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public static main",function(jangaronLogoContainerId,jangaronLogoId){
Sound.init(function(soundAvailable){



if(soundAvailable){
new Sound("sound/prepare-to-transport.mp3",true);
}
var doc=Document.INSTANCE;
var logoContainer=doc.getElement(jangaronLogoContainerId);
var logo=doc.getElement(jangaronLogoId);
var logoColor=new Color(228,108,10);
var factor=0;
new TimedExecutor(function(){
factor+=.03;
logo.setStyle({backgroundColor:logoColor.darker(Math.min(factor,1))});
if(factor>=1.6){
initSettingsUI(logoContainer);
return false;
}
},80).start();
});
},

"private static initSettingsUI",function(logoContainer){
Transformer.main();
logoContainer.remove();
if(Sound.isAvailable()){

var UIViewRootRender=UIViewRoot.prototype.render;
UIViewRoot.prototype.render=function(){
var settings=window["settings"];
settings.playSound("click");
UIViewRootRender.call(this);
};
}

},
]}
);joo.Class.prepare("package net.jangaron",

"import joo.lang.JOObject",
"import joo.html.Browser",
"import joo.html.Document",
"import joo.html.Element",
"import joo.css.Color",
"import joo.util.HashSet",
"import joo.util.TimedExecutor",
"import joo.sound.Sound",
"import net.jangaron.ViewPort",
"import net.jangaron.Direction",
"import net.jangaron.Position",
"import net.jangaron.LightCycle",
"import net.jangaron.Wall",
"import net.jangaron.ui.Player",

"public class Grid extends JOObject",["main"],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"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 main",function(width,height,highRim,
startOpacity,obstacleCnt,
musicVolume,soundVolume,
viewPortDefs,
minIntervalMS){
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;
}
window["grid"]=new Grid(width,height,highRim,startOpacity,obstacleCnt,lightcycles,viewports,musicVolume,soundVolume,minIntervalMS);
});
},

"public _Grid",function(width,height,highRim,
startOpacity,obstacleCnt,
lightCycles,viewPorts,
musicVolume,soundVolume,
minIntervalMS){
this[_super]();
this[_lightCycles]=lightCycles;
this[_lightCycles].broadcast("setGrid",this);
this[_viewPorts]=viewPorts;
this[_viewPorts].broadcast("setGrid",this);
if(!minIntervalMS)
minIntervalMS=MIN_INTERVAL_MS;
this[_stepExecutor]=new TimedExecutor(this[_doStep].bind(this),minIntervalMS);
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 TimedExecutor(this[_animateTerminal].bind(this),40);
this[_terminal]=document.createElement("div").setClassName("terminal").setStyle({opacity:"0.8"});
this[_terminal].addEventListener("click",function(event){
return this[_onkeydown]({keyCode:KeyEvent.DOM_VK_RETURN,preventDefault:event.preventDefault.bind(event)});
}.bind(this));
document.getBody().appendChild(this[_terminal]);
htmlElement.addEventListener("keydown",this[_onkeydown].bind(this),true);
htmlElement.addEventListener("keyup",this[_onkeyup].bind(this),true);
window.addEventListener("blur",this[_onblur].bind(this),true);
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 Sound();
ambient.loadSound("http://dl.dropbox.com/u/7433264/Recognizer.mp3",true);
ambient.stop();
ambient.setVolume(musicVolume);

ambient.onSoundComplete=function(){
ambient.start();
};
this[_sounds][SOUND_AMBIENT]=ambient;
this[_sounds][SOUND_WON]=new Sound("sound/won.mp3",false).setVolume(musicVolume);
this[_sounds][SOUND_LOST]=new Sound("sound/lost.mp3",false).setVolume(musicVolume);
}
if(soundVolume>0){
this[_sounds][SOUND_START]=new Sound("sound/transform-and-start.mp3",false).setVolume(soundVolume);
this[_sounds][SOUND_BEEP]=new 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 getSound",function(name){
return this[_sounds][name];
},

"private createStatusLine",function(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 cssPercent",function(n){
return Math.floor(n*100)/100+"%";
},

"private addToStatusLine",function(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 getLightCycles",function(){
return this[_lightCycles];
},

"public getPrimaryViewPort",function(){
return this[_primaryViewPort];
},

"private init",function(){
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(window.parent==window){

if(!this[_stepExecutor].start()){

}
}else{
this[_viewPorts].broadcast("update");
}
},

"private createRandomWalls",function(number){
var GRAY=new 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 hasIntersectingWall",function(wall){
for(var i=0;i<this.walls.length;++i){
var w=this.walls[i];
if(w.intersects(wall)){
return true;
}
}
return false;
},

"public addWall",function(wall){
this.walls.push(wall);
},

"public removeWall",function(wall){
return this.walls.remove(wall);
},

"private doStep",function(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?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;
window.setTimeout(this[_gameOver],0);
return false;
}
return undefined;
},

"private getNextTurnTime",function(){
for(var ulc=0;ulc<this[_userLightCycles].length;++ulc){
var lightCycle=this[_userLightCycles][ulc];
var nextTurnTime=lightCycle.nextTurnTime();
if(nextTurnTime){
return nextTurnTime;
}
}
return undefined;
},"crashed",


function(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.keyMap=lightCycle.keyMap;
lightCycle.keyMap=undefined;
viewPort.setLightCycle(exchangeLC);
return;
}
}
throw new Error("View port of user-controlled lightcycle "+lightCycle.getName()+" not found!");
}
}
},

"private findExchangeLightCycle",function(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 isGameOver",function(){
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 updateStatusLine",function(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 updateFrameRate",function(passedMillis){
this[_passedMillisSum]+=passedMillis;
++this[_renderedFrames];
if(this[_passedMillisSum]>=1000){
window.status=Math.round(this[_renderedFrames]*100000/this[_passedMillisSum])/100;
this[_passedMillisSum]=0;
this[_renderedFrames]=0;
}
},

"public removeLightCycle",function(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 onkeydown",function(event){
event.time=new Date().getTime();
if(!this[_inGame]){
if(event.keyCode==KeyEvent.DOM_VK_RETURN){
this[_init]();
event.preventDefault();
return false;
}
return true;
}
switch(event.keyCode){
case KeyEvent.DOM_VK_SPACE:
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 onkeyup",function(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 onblur",function(){
if(this[_userLightCycles].length>0){
this[_stepExecutor].stop();
}
},

"private onfocus",function(){
if(this[_inGame]){
this[_stepExecutor].start();
}
},

"private static displayName",function(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 gameOver",function(){









var survivingPrograms=[];
var survivingUser;
var survivingTeams=new 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="<div></div><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 animateTerminal",function(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",

"import joo.util.PropertyAware",

"public class KeyMap extends PropertyAware",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public _KeyMap",function(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",

"import joo.lang.JOObject",
"import net.jangaron.Direction",
"import net.jangaron.Position",
"import net.jangaron.Wall",
"import joo.css.Color",
"import joo.sound.Sound",
"import joo.util.HashSet",

"public class LightCycle extends JOObject",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"private static const",{DEFAULT_MIN_SPEED:25},
"private static const",{DEFAULT_MAX_SPEED:80},
"private static const",{DEBUG:false},

"public _LightCycle",function(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 setGrid",function(grid){
this[_grid]=grid;
},

"public setTeam",function(team){
this[_team]=team;
},

"public getTeam",function(){
return this[_team];
},

"public setName",function(name){
this[_name]=name;
},

"public getName",function(){
return this[_name];
},

"public isUser",function(){
return! !this.keyMap;
},

"public setColor",function(color){
this[_color]=color;
},

"public getColor",function(){
return this[_color];
},

"public getOpacity",function(){
return this[_opacity];
},

"public getPosition",function(){
return this[_position];
},

"public getViewPosition",function(){
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 init",function(){
if(this[_grid].soundVolume>0){
if(!this[_sound]){
this[_sound]={

derezz:new Sound(this.isUser()?"sound/derezz.mp3":"sound/derezz2.mp3",false),
turnLeft:new Sound("sound/turn1.mp3",false),
turnRight:new 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 HashSet());
this[_cycleWall]=this[_createCycleWall]();
this[_cycleHeadWall]=this[_createCycleWall](true);
this[_updateCycleHeadWall]();
},

"private createCycleWall",function(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 updateCycleHeadWall",function(){
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 getCycleWall",function(){
return this[_cycleWall];
},

"private getLinePos",function(){
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 playSound",function(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 move",function(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 updateSpeed",function(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 update",function(){
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 moveWall",function(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 computeTurn",function(){
var theTurn;
var excludedWalls=new 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 mayTurn",function(){
return!this.isDead()&&
(this[_cycleWall].x2-this[_cycleWall].x1>=1||
this[_cycleWall].y2-this[_cycleWall].y1>=1);
},

"public nextTurnTime",function(){
return this[_turnQueue].length>0&&this[_mayTurn]()?this[_turnQueue][0]["time"]:undefined;
},

"public turn",function(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 checkCrashed",function(){
if(this.isDead())
return;
var excludedWalls=new 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 findCrashWall",function(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 isDead",function(){
return this[_opacity]<this[_grid].startOpacity;
},

"public onkeydown",function(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 onkeyup",function(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},
"public 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",

"import joo.css.Color",

"public class Line",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public _Line",function(viewPort,y){this[_super]();
this.viewPort=viewPort;
this[_y]=y;
this.HALF_LINE_WIDTH=viewPort.GRID_LINE_WIDTH/2;
},

"public update",function(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",

"import net.jangaron.Direction",

"public class Position",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public _Position",function(x,y,dir){this[_super]();
this.x=x;
this.y=y;
this.dir=dir;
},

"public clone",function(){
return new Position(this.x,this.y,this.dir);
},

"public setPosition",function(position){
this.x=position.x;
this.y=position.y;
this.dir=position.dir;
},

"public getPosition",function(distance){
var thisDir=this.dir;
return new Position(this.x+thisDir.dx*distance,this.y+thisDir.dy*distance,thisDir);
},

"public getOffset",function(steps){
return this[_offset](this.dir,steps);
},

"public getLeftOffset",function(steps){
return this[_offset](this.dir.turnRight,steps);
},

"private offset",function(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 move",function(distance){
var thisDir=this.dir;
this.x+=thisDir.dx*distance;
this.y+=thisDir.dy*distance;
},

"public turnLeft",function(){
this.dir=this.dir.turnLeft;
},

"public turnRight",function(){
this.dir=this.dir.turnRight;
},

"override public toString",function(){
return[this.x,"px ",this.y,"px"].join("");
},

"public var",{x: undefined},
"public var",{y: undefined},
"public var",{dir: undefined},
]}
);joo.Class.prepare("package net.jangaron",

"import joo.lang.JOObject",
"import net.jangaron.Direction",
"import net.jangaron.Trapez",
"import joo.util.HashSet",












"public class RelativeWall extends JOObject",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"private static const",{DEBUG:false},

"public _RelativeWall",function(wall){
this[_super]();
this.wall=wall;
this.wallProjection=new Trapez();
},

"public update",function(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 setValues",function(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;
},"mayHidePoint",






function(x,y){

},

"private mayHidePointNever",function(x,y){
return false;
},

"private mayHidePointMiddle",function(x,y){
return y>this.y1||y==this.y1&&this.x1<=x&&x<=this.x2;
},

"private mayHidePointLeft",function(x,y){

return x<this.x2&&(y>this.y1);
},

"private mayHidePointRight",function(x,y){

return x>this.x1&&(y>this.y1);
},





"public updateMaybeHides",function(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 removedFromUnhidden",function(unhiddenElements){
this[_maybeHides].forEach(function(other){
if(--other.hiddenByCnt==0){
unhiddenElements.add(other);
}
});
},

"public toString1",function(){
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",

"import joo.css.Color",

"public class SlantLine",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public _SlantLine",function(viewPort,gx){this[_super]();
this.viewPort=viewPort;
this.gx=gx;
},

"private clippedPoint",function(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 update",function(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",

"import joo.lang.JOObject",
"import joo.css.Color",
"import net.jangaron.TeamColor",

"public class TeamColor extends JOObject",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)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 TeamColor("",null);}},
"public static const",{GOLD_ORANGE:function(){return new TeamColor(TEAM_GOLD,COLOR_ORANGE);}},
"public static const",{GOLD_RED:function(){return new TeamColor(TEAM_GOLD,COLOR_RED);}},
"public static const",{GOLD_YELLOW:function(){return new TeamColor(TEAM_GOLD,COLOR_YELLOW);}},
"public static const",{BLUE_VIOLET:function(){return new TeamColor(TEAM_BLUE,COLOR_VIOLET);}},
"public static const",{BLUE_BLUE:function(){return new TeamColor(TEAM_BLUE,COLOR_BLUE);}},
"public static const",{GREEN_CYAN:function(){return new TeamColor(TEAM_GREEN,COLOR_CYAN);}},
"public static const",{GREEN_GREEN:function(){return new TeamColor(TEAM_GREEN,COLOR_GREEN);}},
"public static const",{EARTH_SILICON:function(){return new TeamColor(TEAM_EARTH,COLOR_SILICON);}},
"public static const",{EARTH_BROWN:function(){return new TeamColor(TEAM_EARTH,COLOR_BROWN);}},
"public static const",{WATER_AQUA:function(){return new TeamColor(TEAM_WATER,COLOR_AQUA);}},
"public static const",{PINK_PINK:function(){return new 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
];}},function()

{
for(var i=0;i<TEAMS_AND_COLORS.length;++i){
var teamColor=TEAMS_AND_COLORS[i];
teamColor.index=i;
}
},

"public _TeamColor",function(team,colorName){
this[_super]();
this[_team]=team;
this[_colorName]=colorName;
},

"public getTeam",function(){
return this[_team];
},

"public getColorName",function(){
return this[_colorName];
},

"private static const",{COLOR_BY_NAME:function(){return {
"Orange":new Color(228,108,10),
"Red":new Color(228,75,10),
"Yellow":new Color(245,169,10),
"Violet":new Color(125,0,150),
"Blue":new Color(64,0,192),
"Cyan":new Color(23,211,145),
"Green":new Color(10,228,108),
"Silicon":new Color(186,177,149),
"Brown":new Color(166,149,103),
"Aqua":new Color(115,209,193),
"Pink":new Color(227,166,193)
};}},

"public getColor",function(){
return COLOR_BY_NAME[this[_colorName]];
},

"override public hashCode",function(){
return this.toString();
},

"override public equals",function(teamColor){
return this.index==teamColor.index;
},

"override public toString",function(){
return[this[_team]," (",this[_colorName],")"].join("");
},

"private var",{team: undefined},
"private var",{colorName: undefined},
"public var",{index: undefined},
]}
);joo.Class.prepare("package net.jangaron",

"import joo.css.Color",

"public class Trapez",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public setValues",function(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 intersects",function(trapez){
return Math.max(this.x1,trapez.x1)<=Math.min(this.x2,trapez.x2);
},

"override public toString",function(){
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",

"import joo.html.Browser",
"import joo.html.Document",
"import joo.html.Dimensions",
"import joo.html.Element",
"import joo.html.slant.SlantCanvas",
"import joo.css.Color",
"import joo.util.HashSet",
"import net.jangaron.Line",
"import net.jangaron.SlantLine",
"import net.jangaron.RelativeWall",
"import net.jangaron.ZBuffer",


"public class ViewPort extends Element",["create"],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)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},






"public static create",function(document,style){
if(!document){
var gameWindow=window.open();
document=new 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 _ViewPort",function(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 createLayer",function(){
var div=this.ownerDocument.createElement("div").setStyle({zIndex:String(++this[_layerCount])});
this.appendChild(div);
return new SlantCanvas(this.ownerDocument,div.getPeer());
},

"private initDimensions",function(){
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 setLightCycle",function(lightCycle){
this[_lightCycle]=lightCycle;
this[_initHUD](lightCycle);
},

"public getLightCycle",function(){
return this[_lightCycle];
},

"public setGrid",function(grid){
this.grid=grid;
},

"public getPosition",function(){
return this[_lightCycle].getViewPosition();
},

"public getY",function(yIndex){
return yIndex<0?this.HORIZON:this.Y_FACTOR/(this.GRID_LINE_DISTANCE+yIndex);
},

"public project",function(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 insertRelativeWall",function(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 update",function(){
if(this[_sizeDirty]){
this[_initDimensions]();
}
this[_updateHUD]();
var position=this.getPosition();
this[_updateSlantLines](position);
this[_updateLines](position);
var relativeWalls=[];
var unhiddenRelativeWalls=new 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 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 createGridLines",function(){
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 updateSlantLines",function(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 updateLines",function(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 createHUD",function(){
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 initHUD",function(lightCycle){
var hud=this[_hudLayer].getItem(0);
var speedContainer=hud.nextSibling;
speedContainer.style["backgroundColor"]=hud.style["backgroundColor"]=lightCycle.getColor().toString();
var speedometer=speedContainer.firstChild;
speedometer.style["backgroundColor"]=lightCycle.getColor().darker().toString();
},

"private updateHUD",function(){
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",{layerCount:0},
"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",

"import joo.css.Color",
"import joo.lang.JOObject",

"public class Wall extends JOObject",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"private static const",{DEBUG:false},

"public _Wall",function(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 getOpacity",function(){
return this[_opacityHolder]?this[_opacityHolder].getOpacity():1;
},

"public check",function(){
if(!(this.x1<=this.x2&&this.y1<=this.y2)){
throw new Error("Wall: IllegalArgument: "+this);
}
},

"public intersects",function(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 toString",function(){
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",

"import joo.util.Interval",

"public class ZBuffer",[],function($jooPublic,$jooPrivate){with($jooPublic)with($jooPrivate)return[

"public _ZBuffer",function(){this[_super]();
this[_intervals]=[];
},

"public isIntervalVisible",function(a,b){
var thisIntervals=this[_intervals];
var aIndex=thisIntervals.binarySearch(a);

return aIndex<0||b>thisIntervals[aIndex]["b"];
},

"public addInterval",function(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 Interval(a,b);

thisIntervals.splice(aIndex,bIndex-aIndex+1,newInterval);
return true;
},

"override public toString",function(){
return this[_intervals].join(" ");
},

"private var",{intervals:function(){return [];}},
]}
);
homerecads={path:true};
