@h3xed/

Assault Man

HTML, CSS, JS

ASSAULT MAN

fork
loading
Files
  • index.html
  • style.css

This Plugin Crashed!

Error: Error: must not create an existing file {"type":"CREATE_FILE","wid":"0.9847840980482114","path":"index.html","file":{"path":"index.html","content":{"asEncoding":{"base64":"PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Ym9keXttYXJnaW46MDtwYWRkaW5nOjIwcHg7YmFja2dyb3VuZDojRTFFMUUxfTwvc3R5bGU+PGhlYWQ+PHRpdGxlPkFzc2F1bHQgTWFuPC90aXRsZT48bWV0YSBjaGFyc2V0PSJ1dGYtOCI+PC9oZWFkPjxib2R5PjxjYW52YXMgaWQ9ImNhbnZhcyIgd2lkdGg9IjYwMCIgaGVpZ2h0PSI1MDAiIHN0eWxlPSJkaXNwbGF5OmJsb2NrO21hcmdpbjphdXRvO2JhY2tncm91bmQ6I0YyRjJGMjtib3gtc2hhZG93OjAgMnB4IDNweCByZ2JhKDAsMCwwLDAuMSk7LXdlYmtpdC10b3VjaC1jYWxsb3V0Om5vbmU7LXdlYmtpdC11c2VyLXNlbGVjdDpub25lOy1raHRtbC11c2VyLXNlbGVjdDpub25lOy1tb3otdXNlci1zZWxlY3Q6bm9uZTstbXMtdXNlci1zZWxlY3Q6bm9uZTstby11c2VyLXNlbGVjdDpub25lO3VzZXItc2VsZWN0Om5vbmUiPjwvY2FudmFzPjxzY3JpcHQ+CiAgZnVuY3Rpb24gQ29udHJvbEhhbmRsZXIobWFpbikgewoJdGhpcy5hID0gZmFsc2U7Cgl0aGlzLmQgPSBmYWxzZTsKCXRoaXMudyA9IGZhbHNlOwoJdGhpcy5zID0gZmFsc2U7Cgl0aGlzLm0gPSBmYWxzZTsKICB0aGlzLnNwYWNlID0gZmFsc2U7Cgl0aGlzLnRhYiA9IGZhbHNlOwoJdGhpcy5tb3VzZUxlZnQgPSBmYWxzZTsKCXRoaXMubW91c2VYID0gMDsKCXRoaXMubW91c2VZID0gMDsKCXRoaXMubWFpbiA9IG1haW47Cgl0aGlzLmNhbnZhcyA9IG1haW4uY2FudmFzOwoJd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2tleWRvd24nLCB0aGlzLmtleURvd25FdmVudC5iaW5kKHRoaXMpKTsKCXdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdrZXl1cCcsIHRoaXMua2V5VXBFdmVudC5iaW5kKHRoaXMpKTsKCXRoaXMuY2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIHRoaXMubW91c2VEb3duRXZlbnQuYmluZCh0aGlzKSk7Cgl0aGlzLmNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgdGhpcy5tb3VzZVVwRXZlbnQuYmluZCh0aGlzKSk7Cgl0aGlzLmNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCdtb3VzZW1vdmUnLCB0aGlzLm1vdXNlTW92ZUV2ZW50LmJpbmQodGhpcykpOwoJdGhpcy5jYW52YXMuYWRkRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCB0aGlzLmNvbnRleHRNZW51RXZlbnQuYmluZCh0aGlzKSkKfQpDb250cm9sSGFuZGxlci5wcm90b3R5cGUuaW5pdCA9IGZ1bmN0aW9uKG1haW4pIHt9OwpDb250cm9sSGFuZGxlci5wcm90b3R5cGUuZW50ZXJGcmFtZSA9IGZ1bmN0aW9uKCkge307CkNvbnRyb2xIYW5kbGVyLnByb3RvdHlwZS5rZXlEb3duRXZlbnQgPSBmdW5jdGlvbihlKSB7CglpZiAoZS5rZXlDb2RlID09IDg3KSB7CgkJdGhpcy53ID0gdHJ1ZQoJfSBlbHNlIGlmIChlLmtleUNvZGUgPT0gODMpIHsKCQl0aGlzLnMgPSB0cnVlCgl9IGVsc2UgaWYgKGUua2V5Q29kZSA9PSA2NSkgewoJCXRoaXMuYSA9IHRydWUKCX0gZWxzZSBpZiAoZS5rZXlDb2RlID09IDY4KSB7CgkJdGhpcy5kID0gdHJ1ZQoJfSBlbHNlIGlmIChlLmtleUNvZGUgPT0gNzcpIHsKCQl0aGlzLm0gPSB0cnVlCiAgfSBlbHNlIGlmIChlLmtleUNvZGUgPT0gMzIpIHsKCQl0aGlzLnNwYWNlID0gdHJ1ZQoJfSBlbHNlIGlmIChlLmtleUNvZGUgPT0gOSkgewoJCXRoaXMudGFiID0gdHJ1ZTsKCQllLnByZXZlbnREZWZhdWx0KCkKCX0KfTsKQ29udHJvbEhhbmRsZXIucHJvdG90eXBlLmtleVVwRXZlbnQgPSBmdW5jdGlvbihlKSB7CglpZiAoZS5rZXlDb2RlID09IDg3IHx8IGUua2V5Q29kZSA9PSAzOCkgewoJCXRoaXMudyA9IGZhbHNlCgl9IGVsc2UgaWYgKGUua2V5Q29kZSA9PSA4MykgewoJCXRoaXMucyA9IGZhbHNlCgl9IGVsc2UgaWYgKGUua2V5Q29kZSA9PSA2NSkgewoJCXRoaXMuYSA9IGZhbHNlCgl9IGVsc2UgaWYgKGUua2V5Q29kZSA9PSA2OCkgewoJCXRoaXMuZCA9IGZhbHNlCgl9IGVsc2UgaWYgKGUua2V5Q29kZSA9PSA3NykgewoJCXRoaXMubSA9IGZhbHNlCiAgfSBlbHNlIGlmIChlLmtleUNvZGUgPT0gMzIpIHsKCQl0aGlzLnNwYWNlID0gZmFsc2UKCX0gZWxzZSBpZiAoZS5rZXlDb2RlID09IDkpIHsKCQl0aGlzLnRhYiA9IGZhbHNlOwoJCWUucHJldmVudERlZmF1bHQoKQoJfQp9OwpDb250cm9sSGFuZGxlci5wcm90b3R5cGUubW91c2VEb3duRXZlbnQgPSBmdW5jdGlvbihlKSB7CglpZiAoZS5idXR0b24gPT0gMCkgewoJCXRoaXMubW91c2VMZWZ0ID0gdHJ1ZQoJfQp9OwpDb250cm9sSGFuZGxlci5wcm90b3R5cGUubW91c2VVcEV2ZW50ID0gZnVuY3Rpb24oZSkgewoJaWYgKHRoaXMubW91c2VMZWZ0KSB7CgkJaWYgKHRoaXMubWFpbi5zdGF0ZSA9PSAnbWVudVNjcmVlbicgfHwgdGhpcy5tYWluLnN0YXRlID09ICdnYW1lT3ZlclNjcmVlbicpIHsKCQkJdGhpcy5tYWluLnN0YXJ0R2FtZSgpCgkJfQoJfQoJaWYgKGUuYnV0dG9uID09IDApIHsKCQl0aGlzLm1vdXNlTGVmdCA9IGZhbHNlCgl9Cn07CkNvbnRyb2xIYW5kbGVyLnByb3RvdHlwZS5tb3VzZU1vdmVFdmVudCA9IGZ1bmN0aW9uKGUpIHsKCXZhciByZWN0ID0gdGhpcy5jYW52YXMuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7Cgl0aGlzLm1vdXNlWCA9IGUuY2xpZW50WCAtIHJlY3QubGVmdDsKCXRoaXMubW91c2VZID0gZS5jbGllbnRZIC0gcmVjdC50b3AKfTsKQ29udHJvbEhhbmRsZXIucHJvdG90eXBlLmNvbnRleHRNZW51RXZlbnQgPSBmdW5jdGlvbihlKSB7CgllLnByZXZlbnREZWZhdWx0KCkKfTsKCmZ1bmN0aW9uIENyZWF0ZUxldmVsKG1haW4pIHsKCXZhciBsZXZlbFdpZHRoID0gbWFpbi5sZXZlbFdpZHRoOwoJdmFyIGxldmVsSGVpZ2h0ID0gbWFpbi5sZXZlbEhlaWdodDsKCXZhciBpLCB4LCB5OwoJZm9yIChpID0gMDsgaSA8IDEwMDA7IGkrKykgewoJCXggPSBNYXRoLnJhbmRvbSgpICogKGxldmVsV2lkdGggLSAyMCkgKyAxMDsKCQl5ID0gTWF0aC5yYW5kb20oKSAqIChsZXZlbEhlaWdodCAtIDQwKSArIDMwOwoJCW1haW4ud2FsbEhhbmRsZXIuY3JlYXRlKHgsIHksIDAsIE1hdGgucmFuZG9tKCkgKiAxMCArIDgpCgl9Cglmb3IgKGkgPSAwOyBpIDwgMzU7IGkrKykgewoJCXggPSBNYXRoLnJhbmRvbSgpICogKGxldmVsV2lkdGggLSAyMCkgKyAxMDsKCQl5ID0gTWF0aC5yYW5kb20oKSAqIChsZXZlbEhlaWdodCAtIDQwKSArIDMwOwoJCW1haW4ucGlja3VwSGFuZGxlci5jcmVhdGUoeCwgeSkKCX0KCWZvciAoaSA9IDA7IGkgPCA3OyBpKyspIHsKCQl4ID0gTWF0aC5yYW5kb20oKSAqIChsZXZlbFdpZHRoIC0gMjAwKSArIDEwMDsKCQl5ID0gTWF0aC5yYW5kb20oKSAqIChsZXZlbEhlaWdodCAtIDIyMCkgKyAxMjA7CgkJbWFpbi5iYXNlSGFuZGxlci5jcmVhdGUoeCwgeSwgMCkKCX0KCWZvciAoaSA9IDA7IGkgPCA2OyBpKyspIHsKCQl4ID0gTWF0aC5yYW5kb20oKSAqIChsZXZlbFdpZHRoIC0gMjAwKSArIDEwMDsKCQl5ID0gTWF0aC5yYW5kb20oKSAqIChsZXZlbEhlaWdodCAtIDIyMCkgKyAxMjA7CgkJbWFpbi5iYXNlSGFuZGxlci5jcmVhdGUoeCwgeSwgMSkKCX0KCWZvciAoaSA9IDA7IGkgPCA1OyBpKyspIHsKCQl4ID0gTWF0aC5yYW5kb20oKSAqIChsZXZlbFdpZHRoIC0gMjAwKSArIDEwMDsKCQl5ID0gTWF0aC5yYW5kb20oKSAqIChsZXZlbEhlaWdodCAtIDIyMCkgKyAxMjA7CgkJbWFpbi5iYXNlSGFuZGxlci5jcmVhdGUoeCwgeSwgMikKCX0KCWZvciAoaSA9IDA7IGkgPCAzOyBpKyspIHsKCQl4ID0gTWF0aC5yYW5kb20oKSAqIChsZXZlbFdpZHRoIC0gMjAwKSArIDEwMDsKCQl5ID0gTWF0aC5yYW5kb20oKSAqIChsZXZlbEhlaWdodCAtIDIyMCkgKyAxMjA7CgkJbWFpbi5iYXNlSGFuZGxlci5jcmVhdGUoeCwgeSwgMykKCX0KCWZvciAoaSA9IDA7IGkgPCAyOyBpKyspIHsKCQl4ID0gTWF0aC5yYW5kb20oKSAqIChsZXZlbFdpZHRoIC0gMjAwKSArIDEwMDsKCQl5ID0gTWF0aC5yYW5kb20oKSAqIChsZXZlbEhlaWdodCAtIDIyMCkgKyAxMjA7CgkJbWFpbi5iYXNlSGFuZGxlci5jcmVhdGUoeCwgeSwgNCkKCX0KCXggPSBNYXRoLnJhbmRvbSgpICogKGxldmVsV2lkdGggLSAyMDApICsgMTAwOwoJeSA9IE1hdGgucmFuZG9tKCkgKiAobGV2ZWxIZWlnaHQgLSAyMjApICsgMTIwOwoJbWFpbi5iYXNlSGFuZGxlci5jcmVhdGUoeCwgeSwgNSkKfQoKCgpmdW5jdGlvbiBFbmVteUhhbmRsZXIobWFpbikgewoJdGhpcy5zcGVlZCA9IDAuOTsKCXRoaXMuc3Bhd25NYXggPSAzMDA7Cgl0aGlzLnNob3RTcGVlZCA9IDMuMDsKCXRoaXMubGlzdCA9IFtdOwoJdGhpcy5wb29sID0gW10KfQpFbmVteUhhbmRsZXIucHJvdG90eXBlLmluaXQgPSBmdW5jdGlvbihtYWluKSB7Cgl0aGlzLmxpc3QubGVuZ3RoID0gMDsKCXRoaXMucGxheWVySGFuZGxlciA9IG1haW4ucGxheWVySGFuZGxlcjsKCXRoaXMucGxheWVyU2hvdEhhbmRsZXIgPSBtYWluLnBsYXllclNob3RIYW5kbGVyOwoJdGhpcy5lbmVteVNob3RIYW5kbGVyID0gbWFpbi5lbmVteVNob3RIYW5kbGVyOwoJdGhpcy5waWNrdXBIYW5kbGVyID0gbWFpbi5waWNrdXBIYW5kbGVyOwoJdGhpcy5sZXZlbFdpZHRoID0gbWFpbi5sZXZlbFdpZHRoOwoJdGhpcy5sZXZlbEhlaWdodCA9IG1haW4ubGV2ZWxIZWlnaHQKfTsKRW5lbXlIYW5kbGVyLnByb3RvdHlwZS5lbnRlckZyYW1lID0gZnVuY3Rpb24oKSB7Cgl2YXIgcGxheWVyID0gdGhpcy5wbGF5ZXJIYW5kbGVyOwoJdmFyIGksIGosIGVuZW15LCBzaG90LCBkaXN0LCBkaXN0MiwgdlgsIHZZOwoJZm9yIChpID0gdGhpcy5saXN0Lmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7CgkJZW5lbXkgPSB0aGlzLmxpc3RbaV07CgkJZW5lbXkucmVsb2FkLS07CgkJZW5lbXkuZGVsYXktLTsKCQlpZiAoZW5lbXkuZGVsYXkgPD0gMCkgewoJCQl2WCA9IHBsYXllci54IC0gZW5lbXkueDsKCQkJdlkgPSBwbGF5ZXIueSAtIGVuZW15Lnk7CgkJCWRpc3QyID0gdlggKiB2WCArIHZZICogdlk7CgkJCWlmIChkaXN0MiA8IDE0NCkgewoJCQkJZGlzdCA9IDgKCQkJfSBlbHNlIGlmIChkaXN0MiA8IDU3NikgewoJCQkJZGlzdCA9IDE2CgkJCX0gZWxzZSBpZiAoZGlzdDIgPCAyMzA0KSB7CgkJCQlkaXN0ID0gMzIKCQkJfSBlbHNlIGlmIChkaXN0MiA8IDkyMTYpIHsKCQkJCWRpc3QgPSA2NAoJCQl9IGVsc2UgaWYgKGRpc3QyIDwgMzY4NjQpIHsKCQkJCWRpc3QgPSAxMjgKCQkJfSBlbHNlIGlmIChkaXN0MiA8IDE0NzQ1NikgewoJCQkJZGlzdCA9IDI1NgoJCQl9IGVsc2UgaWYgKGRpc3QyIDwgNTg5ODI0KSB7CgkJCQlkaXN0ID0gNTEyCgkJCX0gZWxzZSBpZiAoZGlzdDIgPCAyMzU5Mjk2KSB7CgkJCQlkaXN0ID0gMTAyNAoJCQl9IGVsc2UgewoJCQkJZGlzdCA9IDIwNDgKCQkJfQoJCQlkaXN0ID0gMC41ICogKGRpc3QyIC8gZGlzdCArIGRpc3QpOwoJCQlkaXN0ID0gMC41ICogKGRpc3QyIC8gZGlzdCArIGRpc3QpOwoJCQlpZiAoZGlzdCAtIHBsYXllci5yYWRpdXMgLSBlbmVteS5yYWRpdXMgPiBNYXRoLm1heCgyMDAgKyBlbmVteS5sZXZlbCAqIDUwLCAzNTApKSB7CgkJCQllbmVteS5kZWxheSA9IE1hdGguZmxvb3IoKGRpc3QgLSBwbGF5ZXIucmFkaXVzIC0gZW5lbXkucmFkaXVzIC0gTWF0aC5tYXgoMjAwICsgZW5lbXkubGV2ZWwgKiA1MCwgMzUwKSkgLyAocGxheWVyLnNwZWVkICsgdGhpcy5zcGVlZCkpCgkJCX0KCQkJaWYgKGRpc3QgLSBwbGF5ZXIucmFkaXVzIC0gZW5lbXkucmFkaXVzIDw9IDApIHsKCQkJCXBsYXllci52WCA9IHZYICogMC4wNjsKCQkJCXBsYXllci52WSA9IHZZICogMC4wNgoJCQl9CgkJCWlmIChkaXN0IC0gcGxheWVyLnJhZGl1cyAtIGVuZW15LnJhZGl1cyA8PSAyMDAgKyBlbmVteS5sZXZlbCAqIDUwKSB7CgkJCQlpZiAoZW5lbXkucmVsb2FkIDw9IDApIHsKCQkJCQl0aGlzLmVuZW15U2hvdEhhbmRsZXIuY3JlYXRlKGVuZW15LngsIGVuZW15LnksIHZYIC8gZGlzdCAqIHRoaXMuc2hvdFNwZWVkICsgTWF0aC5yYW5kb20oKSAqIDQgLSAyLCB2WSAvIGRpc3QgKiB0aGlzLnNob3RTcGVlZCArIE1hdGgucmFuZG9tKCkgKiA0IC0gMiwgZW5lbXkuc2hvdFJhZGl1cywgZW5lbXkuc2hvdERhbWFnZSk7CgkJCQkJZW5lbXkucmVsb2FkID0gZW5lbXkucmVsb2FkUmF0ZQoJCQkJfQoJCQkJdlggPSB2WCAvIGRpc3QgKiB0aGlzLnNwZWVkOwoJCQkJdlkgPSB2WSAvIGRpc3QgKiB0aGlzLnNwZWVkCgkJCX0gZWxzZSB7CgkJCQl2WCA9IDA7CgkJCQl2WSA9IDAKCQkJfQoJCQlpZiAoZGlzdCAtIHBsYXllci5yYWRpdXMgLSBlbmVteS5yYWRpdXMgPD0gMzUwKSB7CgkJCQlmb3IgKGogPSB0aGlzLnBsYXllclNob3RIYW5kbGVyLmxpc3QubGVuZ3RoIC0gMTsgaiA+PSAwOyBqLS0pIHsKCQkJCQlzaG90ID0gdGhpcy5wbGF5ZXJTaG90SGFuZGxlci5saXN0W2pdOwoJCQkJCWRpc3QyID0gKHNob3QueCAtIGVuZW15LngpICogKHNob3QueCAtIGVuZW15LngpICsgKHNob3QueSAtIGVuZW15LnkpICogKHNob3QueSAtIGVuZW15LnkpOwoJCQkJCWlmIChkaXN0MiA8IDE0NCkgewoJCQkJCQlkaXN0ID0gOAoJCQkJCX0gZWxzZSBpZiAoZGlzdDIgPCA1NzYpIHsKCQkJCQkJZGlzdCA9IDE2CgkJCQkJfSBlbHNlIGlmIChkaXN0MiA8IDIzMDQpIHsKCQkJCQkJZGlzdCA9IDMyCgkJCQkJfSBlbHNlIGlmIChkaXN0MiA8IDkyMTYpIHsKCQkJCQkJZGlzdCA9IDY0CgkJCQkJfSBlbHNlIGlmIChkaXN0MiA8IDM2ODY0KSB7CgkJCQkJCWRpc3QgPSAxMjgKCQkJCQl9IGVsc2UgaWYgKGRpc3QyIDwgMTQ3NDU2KSB7CgkJCQkJCWRpc3QgPSAyNTYKCQkJCQl9IGVsc2UgaWYgKGRpc3QyIDwgNTg5ODI0KSB7CgkJCQkJCWRpc3QgPSA1MTIKCQkJCQl9IGVsc2UgaWYgKGRpc3QyIDwgMjM1OTI5NikgewoJCQkJCQlkaXN0ID0gMTAyNAoJCQkJCX0gZWxzZSB7CgkJCQkJCWRpc3QgPSAyMDQ4CgkJCQkJfQoJCQkJCWRpc3QgPSAwLjUgKiAoZGlzdDIgLyBkaXN0ICsgZGlzdCk7CgkJCQkJZGlzdCA9IDAuNSAqIChkaXN0MiAvIGRpc3QgKyBkaXN0KSAtIHNob3QucmFkaXVzIC0gZW5lbXkucmFkaXVzOwoJCQkJCWlmIChkaXN0IDw9IDApIHsKCQkJCQkJdGhpcy5wbGF5ZXJTaG90SGFuZGxlci5oaXQoaik7CgkJCQkJCXRoaXMuZGFtYWdlKGksIHBsYXllci5kYW1hZ2UpOwoJCQkJCX0KCQkJCX0KCQkJfQoJCX0gZWxzZSB7CgkJCXZYID0gMDsKCQkJdlkgPSAwCgkJfQoJCWVuZW15LnZYID0gKGVuZW15LnZYICogMTkgKyB2WCkgKiAwLjA1OwoJCWVuZW15LnZZID0gKGVuZW15LnZZICogMTkgKyB2WSkgKiAwLjA1OwoJCWVuZW15LnZYICs9IE1hdGgucmFuZG9tKCkgKiAwLjIgLSAwLjE7CgkJZW5lbXkudlkgKz0gTWF0aC5yYW5kb20oKSAqIDAuMiAtIDAuMTsKCQllbmVteS54ICs9IGVuZW15LnZYOwoJCWVuZW15LnkgKz0gZW5lbXkudlk7CgkJaWYgKGVuZW15LnggPCBlbmVteS5yYWRpdXMpIHsKCQkJZW5lbXkueCA9IGVuZW15LnJhZGl1czsKCQkJZW5lbXkudlggKj0gLTEKCQl9IGVsc2UgaWYgKGVuZW15LnggPiB0aGlzLmxldmVsV2lkdGggLSBlbmVteS5yYWRpdXMpIHsKCQkJZW5lbXkueCA9IHRoaXMubGV2ZWxXaWR0aCAtIGVuZW15LnJhZGl1czsKCQkJZW5lbXkudlggKj0gLTEKCQl9CgkJaWYgKGVuZW15LnkgPCAyMCArIGVuZW15LnJhZGl1cykgewoJCQllbmVteS55ID0gMjAgKyBlbmVteS5yYWRpdXM7CgkJCWVuZW15LnZZICo9IC0xCgkJfSBlbHNlIGlmIChlbmVteS55ID4gdGhpcy5sZXZlbEhlaWdodCAtIGVuZW15LnJhZGl1cykgewoJCQllbmVteS55ID0gdGhpcy5sZXZlbEhlaWdodCAtIGVuZW15LnJhZGl1czsKCQkJZW5lbXkudlkgKj0gLTEKCQl9Cgl9Cn07CkVuZW15SGFuZGxlci5wcm90b3R5cGUuY3JlYXRlID0gZnVuY3Rpb24oeCwgeSwgbGV2ZWwpIHsKCWlmICh0aGlzLmxpc3QubGVuZ3RoID49IHRoaXMuc3Bhd25NYXgpIHsKCQlyZXR1cm4KCX0KICBwbGF5ZXIgPSB0aGlzLnBsYXllckhhbmRsZXI7CiAgcGxheWVyLmVsZWZ0KysKCXZhciBlbmVteSA9IHRoaXMucG9vbC5sZW5ndGggPiAwID8gdGhpcy5wb29sLnBvcCgpIDogbmV3IE9iamVjdCgpOwoJZW5lbXkueCA9IHg7CgllbmVteS55ID0geTsKCWVuZW15LnZYID0gMDsKCWVuZW15LnZZID0gMDsKCWVuZW15LmxldmVsID0gbGV2ZWw7CgllbmVteS5yZWxvYWQgPSAwOwoJZW5lbXkuZGVsYXkgPSA1OwoJZW5lbXkucmFkaXVzID0gOCArIGxldmVsICogMC42OwoJZW5lbXkuaHAgPSA0ICsgbGV2ZWwgKiA1OwoJZW5lbXkucmVsb2FkUmF0ZSA9IDI3IC0gbGV2ZWwgKiAzICsgTWF0aC5yYW5kb20oKSAqIDEwOwoJZW5lbXkuc2hvdFJhZGl1cyA9IDM7CgllbmVteS5zaG90RGFtYWdlID0gMSArIGxldmVsOwoJdGhpcy5saXN0LnB1c2goZW5lbXkpCn07CkVuZW15SGFuZGxlci5wcm90b3R5cGUuZGFtYWdlID0gZnVuY3Rpb24oaSwgZG1nKSB7Cgl0aGlzLmxpc3RbaV0uaHAgLT0gZG1nOwoJaWYgKHRoaXMubGlzdFtpXS5ocCA8PSAwKSB7CgkJZW5lbXkgPSB0aGlzLmxpc3RbaV07CgkJdGhpcy5wbGF5ZXJIYW5kbGVyLmtpbGxzKys7CiAgICB0aGlzLnBsYXllckhhbmRsZXIuZWxlZnQtLQoJCWlmIChNYXRoLnJhbmRvbSgpIDwgMC4wNSkgewoJCQl0aGlzLnBpY2t1cEhhbmRsZXIuY3JlYXRlKGVuZW15LngsIGVuZW15LnkpCgkJfQoJCXRoaXMucG9vbC5wdXNoKGVuZW15KTsKCQl0aGlzLmxpc3Quc3BsaWNlKGksIDEpCgl9Cn07CgpmdW5jdGlvbiBFbmVteVNob3RIYW5kbGVyKG1haW4pIHsKCXRoaXMubGlzdCA9IFtdOwoJdGhpcy5wb29sID0gW10KfQpFbmVteVNob3RIYW5kbGVyLnByb3RvdHlwZS5pbml0ID0gZnVuY3Rpb24obWFpbikgewoJdGhpcy5saXN0Lmxlbmd0aCA9IDA7Cgl0aGlzLnBsYXllckhhbmRsZXIgPSBtYWluLnBsYXllckhhbmRsZXI7Cgl0aGlzLnNwZWVkID0gbWFpbi5lbmVteUhhbmRsZXIuc2hvdFNwZWVkCn07CkVuZW15U2hvdEhhbmRsZXIucHJvdG90eXBlLmVudGVyRnJhbWUgPSBmdW5jdGlvbigpIHsKCXZhciBwbGF5ZXIgPSB0aGlzLnBsYXllckhhbmRsZXI7Cgl2YXIgc2hvdCwgaSwgaiwgaywgY2xvc2VzdCwgZGlzdCwgZGlzdDI7Cglmb3IgKGkgPSB0aGlzLmxpc3QubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHsKCQlzaG90ID0gdGhpcy5saXN0W2ldOwoJCXNob3QueCArPSBzaG90LnZYOwoJCXNob3QueSArPSBzaG90LnZZOwoJCXNob3QuZGVsYXktLTsKCQlpZiAoc2hvdC5kZWxheSA8PSAwKSB7CgkJCWRpc3QyID0gKHBsYXllci54IC0gc2hvdC54KSAqIChwbGF5ZXIueCAtIHNob3QueCkgKyAocGxheWVyLnkgLSBzaG90LnkpICogKHBsYXllci55IC0gc2hvdC55KTsKCQkJaWYgKGRpc3QyIDwgMTQ0KSB7CgkJCQlkaXN0ID0gOAoJCQl9IGVsc2UgaWYgKGRpc3QyIDwgNTc2KSB7CgkJCQlkaXN0ID0gMTYKCQkJfSBlbHNlIGlmIChkaXN0MiA8IDIzMDQpIHsKCQkJCWRpc3QgPSAzMgoJCQl9IGVsc2UgaWYgKGRpc3QyIDwgOTIxNikgewoJCQkJZGlzdCA9IDY0CgkJCX0gZWxzZSBpZiAoZGlzdDIgPCAzNjg2NCkgewoJCQkJZGlzdCA9IDEyOAoJCQl9IGVsc2UgaWYgKGRpc3QyIDwgMTQ3NDU2KSB7CgkJCQlkaXN0ID0gMjU2CgkJCX0gZWxzZSBpZiAoZGlzdDIgPCA1ODk4MjQpIHsKCQkJCWRpc3QgPSA1MTIKCQkJfSBlbHNlIGlmIChkaXN0MiA8IDIzNTkyOTYpIHsKCQkJCWRpc3QgPSAxMDI0CgkJCX0gZWxzZSBpZiAoZGlzdDIgPCA5NDM3MTg0KSB7CgkJCQlkaXN0ID0gMjA0OAoJCQl9IGVsc2UgewoJCQkJZGlzdCA9IDUwOTYKCQkJfQoJCQlkaXN0ID0gMC41ICogKGRpc3QyIC8gZGlzdCArIGRpc3QpOwoJCQlkaXN0ID0gMC41ICogKGRpc3QyIC8gZGlzdCArIGRpc3QpIC0gcGxheWVyLnJhZGl1cyAtIHNob3QucmFkaXVzOwoJCQlpZiAoZGlzdCA8PSAwKSB7CgkJCQlwbGF5ZXIuaHAgLT0gc2hvdC5kYW1hZ2U7CgkJCQlpZiAocGxheWVyLmhwIDwgMCkgewoJCQkJCXBsYXllci5ocCA9IDAKCQkJCX0KCQkJCXNob3QucmFkaXVzID0gMAoJCQl9CgkJCXNob3QuZGVsYXkgPSBkaXN0IC8gKHBsYXllci5zcGVlZCArIHRoaXMuc3BlZWQpCgkJfQoJCXNob3QucmFkaXVzIC09IDAuMDM7CgkJaWYgKHNob3QucmFkaXVzIDw9IDEpIHsKCQkJdGhpcy5wb29sLnB1c2goc2hvdCk7CgkJCXRoaXMubGlzdC5zcGxpY2UoaSwgMSk7CgkJCWNvbnRpbnVlCgkJfQoJfQp9OwpFbmVteVNob3RIYW5kbGVyLnByb3RvdHlwZS5jcmVhdGUgPSBmdW5jdGlvbih4LCB5LCB2WCwgdlksIHJhZGl1cywgZGFtYWdlKSB7Cgl2YXIgc2hvdCA9IHRoaXMucG9vbC5sZW5ndGggPiAwID8gdGhpcy5wb29sLnBvcCgpIDogbmV3IE9iamVjdCgpOwoJc2hvdC54ID0geDsKCXNob3QueSA9IHk7CglzaG90LnZYID0gdlg7CglzaG90LnZZID0gdlk7CglzaG90LmRlbGF5ID0gMDsKCXNob3QucmFkaXVzID0gcmFkaXVzOwoJc2hvdC5kYW1hZ2UgPSBkYW1hZ2U7Cgl0aGlzLmxpc3QucHVzaChzaG90KQp9OwoKZnVuY3Rpb24gQmFzZXMoKSB7Cgl0aGlzLmxldmVscyA9IFt7CgkJcmFkaXVzOiAxMzAsCgkJd2FsbHM6IFsKCQkJWzYwLCA0LCAwLjc4NTRdCgkJXSwKCQl0dXJyZXRzOiBbCgkJCVs2MCwgMiwgMF0KCQldCgl9LCB7CgkJcmFkaXVzOiAxNDAsCgkJd2FsbHM6IFsKCQkJWzgwLCA4LCAwLjM5MjddLAoJCQlbMTEwLCA0LCAwLjc4NTRdCgkJXSwKCQl0dXJyZXRzOiBbCgkJCVs4MCwgNCwgMC43ODU0XQoJCV0KCX0sIHsKCQlyYWRpdXM6IDIxMCwKCQl3YWxsczogWwoJCQlbNjAsIDgsIDAuMzkyN10sCgkJCVsxMzAsIDE2LCAwXQoJCV0sCgkJdHVycmV0czogWwoJCQlbMTAwLCA4LCAwXQoJCV0KCX0sIHsKCQlyYWRpdXM6IDI0MCwKCQl3YWxsczogWwoJCQlbNjUsIDgsIDAuMzkyN10sCgkJCVsxMzAsIDE2LCAwXQoJCV0sCgkJdHVycmV0czogWwoJCQlbNzUsIDgsIDBdLAoJCQlbMTQ2LCA4LCAxLjM3NDQ1XQoJCV0KCX0sIHsKCQlyYWRpdXM6IDI3MCwKCQl3YWxsczogWwoJCQlbMTMwLCAxNiwgMF0sCgkJCVsxNzUsIDMyLCAwXQoJCV0sCgkJdHVycmV0czogWwoJCQlbNzUsIDgsIDBdLAoJCQlbMTAwLCA4LCAxLjE3ODFdLAoJCQlbMTQ2LCA4LCAxLjM3NDQ1XQoJCV0KCX0sIHsKCQlyYWRpdXM6IDM0MCwKCQl3YWxsczogWwoJCQlbODAsIDMyLCAwXSwKCQkJWzEwMCwgOCwgMS4xNzgxXSwKCQkJWzIwMCwgMTYsIDAuNTg5MDVdLAoJCQlbMjA1LCAxNiwgMC4yOTQ1MjVdLAoJCQlbMjI1LCA2NCwgMF0KCQldLAoJCXR1cnJldHM6IFsKCQkJWzcwLCAxNiwgMF0sCgkJCVsxNDAsIDgsIDBdLAoJCQlbMTcwLCAxNiwgMC41ODkwNV0sCgkJCVsxODUsIDgsIDBdCgkJXQoJfV0KfQoKZnVuY3Rpb24gQmFzZUhhbmRsZXIobWFpbikgewoJdGhpcy5zcGVlZCA9IDA7Cgl0aGlzLnNob3RTcGVlZCA9IDIuNTsKCXRoaXMubGV2ZWxzID0gbmV3IEJhc2VzKCkubGV2ZWxzOwoJdGhpcy5saXN0ID0gW107Cgl0aGlzLnBvb2wgPSBbXQp9CkJhc2VIYW5kbGVyLnByb3RvdHlwZS5pbml0ID0gZnVuY3Rpb24obWFpbikgewoJdGhpcy5saXN0Lmxlbmd0aCA9IDA7Cgl0aGlzLm1haW4gPSBtYWluOwoJdGhpcy5wbGF5ZXJIYW5kbGVyID0gbWFpbi5wbGF5ZXJIYW5kbGVyOwoJdGhpcy5wbGF5ZXJTaG90SGFuZGxlciA9IG1haW4ucGxheWVyU2hvdEhhbmRsZXI7Cgl0aGlzLndhbGxIYW5kbGVyID0gbWFpbi53YWxsSGFuZGxlcjsKCXRoaXMudHVycmV0SGFuZGxlciA9IG1haW4udHVycmV0SGFuZGxlcjsKCXRoaXMuZW5lbXlIYW5kbGVyID0gbWFpbi5lbmVteUhhbmRsZXI7Cgl0aGlzLmVuZW15U2hvdEhhbmRsZXIgPSBtYWluLmVuZW15U2hvdEhhbmRsZXI7Cgl0aGlzLnBpY2t1cEhhbmRsZXIgPSBtYWluLnBpY2t1cEhhbmRsZXIKfTsKQmFzZUhhbmRsZXIucHJvdG90eXBlLmVudGVyRnJhbWUgPSBmdW5jdGlvbigpIHsKCXZhciBwbGF5ZXIgPSB0aGlzLnBsYXllckhhbmRsZXI7Cgl2YXIgaSwgYmFzZSwgZGlzdCwgdlgsIHZZOwoJZm9yIChpID0gdGhpcy5saXN0Lmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7CgkJYmFzZSA9IHRoaXMubGlzdFtpXTsKCQlpZiAoTWF0aC5yYW5kb20oKSA8IGJhc2Uuc3Bhd25SYXRlKSB7CgkJCXRoaXMuZW5lbXlIYW5kbGVyLmNyZWF0ZShiYXNlLngsIGJhc2UueSwgYmFzZS5sZXZlbCkKCQl9CgkJYmFzZS5yZWxvYWQtLTsKCQliYXNlLmRlbGF5LS07CgkJaWYgKGJhc2UuZGVsYXkgPD0gMCkgewoJCQl2WCA9IHBsYXllci54IC0gYmFzZS54OwoJCQl2WSA9IHBsYXllci55IC0gYmFzZS55OwoJCQlkaXN0MiA9IHZYICogdlggKyB2WSAqIHZZOwoJCQlpZiAoZGlzdDIgPCAxNDQpIHsKCQkJCWRpc3QgPSA4CgkJCX0gZWxzZSBpZiAoZGlzdDIgPCA1NzYpIHsKCQkJCWRpc3QgPSAxNgoJCQl9IGVsc2UgaWYgKGRpc3QyIDwgMjMwNCkgewoJCQkJZGlzdCA9IDMyCgkJCX0gZWxzZSBpZiAoZGlzdDIgPCA5MjE2KSB7CgkJCQlkaXN0ID0gNjQKCQkJfSBlbHNlIGlmIChkaXN0MiA8IDM2ODY0KSB7CgkJCQlkaXN0ID0gMTI4CgkJCX0gZWxzZSBpZiAoZGlzdDIgPCAxNDc0NTYpIHsKCQkJCWRpc3QgPSAyNTYKCQkJfSBlbHNlIGlmIChkaXN0MiA8IDU4OTgyNCkgewoJCQkJZGlzdCA9IDUxMgoJCQl9IGVsc2UgaWYgKGRpc3QyIDwgMjM1OTI5NikgewoJCQkJZGlzdCA9IDEwMjQKCQkJfSBlbHNlIHsKCQkJCWRpc3QgPSAyMDQ4CgkJCX0KCQkJZGlzdCA9IDAuNSAqIChkaXN0MiAvIGRpc3QgKyBkaXN0KTsKCQkJZGlzdCA9IDAuNSAqIChkaXN0MiAvIGRpc3QgKyBkaXN0KTsKCQkJaWYgKGRpc3QgLSBwbGF5ZXIucmFkaXVzIC0gYmFzZS5yYWRpdXMgPiAzNTAgKyBiYXNlLmxldmVsICogNTApIHsKCQkJCWJhc2UuZGVsYXkgPSBNYXRoLmZsb29yKChkaXN0IC0gcGxheWVyLnJhZGl1cyAtIGJhc2UucmFkaXVzIC0gKDM1MCArIGJhc2UubGV2ZWwgKiA1MCkpIC8gcGxheWVyLnNwZWVkKQoJCQl9CgkJCWlmIChkaXN0IC0gcGxheWVyLnJhZGl1cyAtIGJhc2UucmFkaXVzIDw9IDM1MCArIGJhc2UubGV2ZWwgKiA1MCkgewoJCQkJaWYgKGJhc2UucmVsb2FkIDw9IDApIHsKCQkJCQl0aGlzLmVuZW15U2hvdEhhbmRsZXIuY3JlYXRlKGJhc2UueCwgYmFzZS55LCB2WCAvIGRpc3QgKiB0aGlzLnNob3RTcGVlZCArIE1hdGgucmFuZG9tKCkgKiA0IC0gMiwgdlkgLyBkaXN0ICogdGhpcy5zaG90U3BlZWQgKyBNYXRoLnJhbmRvbSgpICogNCAtIDIsIGJhc2Uuc2hvdFJhZGl1cywgYmFzZS5zaG90RGFtYWdlKTsKCQkJCQliYXNlLnJlbG9hZCA9IGJhc2UucmVsb2FkUmF0ZQoJCQkJfQoJCQl9CgkJCWlmIChkaXN0IC0gcGxheWVyLnJhZGl1cyAtIGJhc2UucmFkaXVzIDw9IDApIHsKCQkJCXBsYXllci52WCA9IHZYICogMC4wNjsKCQkJCXBsYXllci52WSA9IHZZICogMC4wNgoJCQl9CgkJCWlmIChkaXN0IC0gcGxheWVyLnJhZGl1cyAtIGJhc2UucmFkaXVzIDw9IDM1MCkgewoJCQkJZm9yIChqID0gdGhpcy5wbGF5ZXJTaG90SGFuZGxlci5saXN0Lmxlbmd0aCAtIDE7IGogPj0gMDsgai0tKSB7CgkJCQkJc2hvdCA9IHRoaXMucGxheWVyU2hvdEhhbmRsZXIubGlzdFtqXTsKCQkJCQlkaXN0MiA9IChzaG90LnggLSBiYXNlLngpICogKHNob3QueCAtIGJhc2UueCkgKyAoc2hvdC55IC0gYmFzZS55KSAqIChzaG90LnkgLSBiYXNlLnkpOwoJCQkJCWlmIChkaXN0MiA8IDE0NCkgewoJCQkJCQlkaXN0ID0gOAoJCQkJCX0gZWxzZSBpZiAoZGlzdDIgPCA1NzYpIHsKCQkJCQkJZGlzdCA9IDE2CgkJCQkJfSBlbHNlIGlmIChkaXN0MiA8IDIzMDQpIHsKCQkJCQkJZGlzdCA9IDMyCgkJCQkJfSBlbHNlIGlmIChkaXN0MiA8IDkyMTYpIHsKCQkJCQkJZGlzdCA9IDY0CgkJCQkJfSBlbHNlIGlmIChkaXN0MiA8IDM2ODY0KSB7CgkJCQkJCWRpc3QgPSAxMjgKCQkJCQl9IGVsc2UgaWYgKGRpc3QyIDwgMTQ3NDU2KSB7CgkJCQkJCWRpc3QgPSAyNTYKCQkJCQl9IGVsc2UgaWYgKGRpc3QyIDwgNTg5ODI0KSB7CgkJCQkJCWRpc3QgPSA1MTIKCQkJCQl9IGVsc2UgaWYgKGRpc3QyIDwgMjM1OTI5NikgewoJCQkJCQlkaXN0ID0gMTAyNAoJCQkJCX0gZWxzZSB7CgkJCQkJCWRpc3QgPSAyMDQ4CgkJCQkJfQoJCQkJCWRpc3QgPSAwLjUgKiAoZGlzdDIgLyBkaXN0ICsgZGlzdCk7CgkJCQkJZGlzdCA9IDAuNSAqIChkaXN0MiAvIGRpc3QgKyBkaXN0KSAtIHNob3QucmFkaXVzIC0gYmFzZS5yYWRpdXM7CgkJCQkJaWYgKGRpc3QgPD0gMCkgewoJCQkJCQl0aGlzLnBsYXllclNob3RIYW5kbGVyLmhpdChqKTsKCQkJCQkJdGhpcy5kYW1hZ2UoaSwgcGxheWVyLmRhbWFnZSk7CgkJCQkJfQoJCQkJfQoJCQl9CgkJfQoJfQp9OwpCYXNlSGFuZGxlci5wcm90b3R5cGUuY3JlYXRlID0gZnVuY3Rpb24oeCwgeSwgbGV2ZWwpIHsKCXZhciBiYXNlID0gdGhpcy5wb29sLmxlbmd0aCA+IDAgPyB0aGlzLnBvb2wucG9wKCkgOiBuZXcgT2JqZWN0KCk7CgliYXNlLnggPSB4OwoJYmFzZS55ID0geTsKCWJhc2UubGV2ZWwgPSBsZXZlbDsKCWJhc2UucmVsb2FkID0gMDsKCWJhc2UuZGVsYXkgPSBNYXRoLmNlaWwoTWF0aC5yYW5kb20oKSAqIDYwKTsKCWJhc2UucmFkaXVzID0gMTUgKyBsZXZlbCAqIDEwOwoJYmFzZS5ocCA9IDQwICsgbGV2ZWwgKiAxNTU7CgliYXNlLnNwYXduUmF0ZSA9IDAuMDAyICsgbGV2ZWwgKiAwLjAwMzsKCWJhc2UucmVsb2FkUmF0ZSA9IDI1IC0gbGV2ZWwgKiAyOwoJYmFzZS5zaG90UmFkaXVzID0gNSArIGxldmVsOwoJYmFzZS5zaG90RGFtYWdlID0gNCArIGxldmVsICogMjsKCXRoaXMuYWRkVHVycmV0c0FuZFdhbGxzKHgsIHksIGxldmVsKTsKCXRoaXMubGlzdC5wdXNoKGJhc2UpCn07CkJhc2VIYW5kbGVyLnByb3RvdHlwZS5hZGRUdXJyZXRzQW5kV2FsbHMgPSBmdW5jdGlvbih4LCB5LCBsZXZlbCkgewoJdmFyIGJhc2UgPSB0aGlzLmxldmVsc1tsZXZlbF07Cgl2YXIgcmFkaXVzLCBjb3VudCwgaW50ZXJ2YWwsIHN0YXJ0LCBpLCBqLCBYLCBZOwoJdGhpcy53YWxsSGFuZGxlci5jbGVhclJhZGl1cyh4LCB5LCBiYXNlLnJhZGl1cyk7Cglmb3IgKGkgPSAwOyBpIDwgYmFzZS53YWxscy5sZW5ndGg7IGkrKykgewoJCXJhZGl1cyA9IGJhc2Uud2FsbHNbaV1bMF07CgkJY291bnQgPSBiYXNlLndhbGxzW2ldWzFdOwoJCXN0YXJ0ID0gYmFzZS53YWxsc1tpXVsyXTsKCQlpbnRlcnZhbCA9IDYuMjgzMiAvIGNvdW50OwoJCWZvciAoaiA9IDA7IGogPCBjb3VudDsgaisrKSB7CgkJCVggPSBNYXRoLmNvcyhzdGFydCArIGludGVydmFsICogaikgKiByYWRpdXM7CgkJCVkgPSBNYXRoLnNpbihzdGFydCArIGludGVydmFsICogaikgKiByYWRpdXM7CgkJCXRoaXMud2FsbEhhbmRsZXIuY3JlYXRlKHggKyBYLCB5ICsgWSwgbGV2ZWwpCgkJfQoJfQoJZm9yIChpID0gMDsgaSA8IGJhc2UudHVycmV0cy5sZW5ndGg7IGkrKykgewoJCXJhZGl1cyA9IGJhc2UudHVycmV0c1tpXVswXTsKCQljb3VudCA9IGJhc2UudHVycmV0c1tpXVsxXTsKCQlzdGFydCA9IGJhc2UudHVycmV0c1tpXVsyXTsKCQlpbnRlcnZhbCA9IDYuMjgzMiAvIGNvdW50OwoJCWZvciAoaiA9IDA7IGogPCBjb3VudDsgaisrKSB7CgkJCVggPSBNYXRoLmNvcyhzdGFydCArIGludGVydmFsICogaikgKiByYWRpdXM7CgkJCVkgPSBNYXRoLnNpbihzdGFydCArIGludGVydmFsICogaikgKiByYWRpdXM7CgkJCXRoaXMudHVycmV0SGFuZGxlci5jcmVhdGUoeCArIFgsIHkgKyBZLCBsZXZlbCkKCQl9Cgl9Cn07CkJhc2VIYW5kbGVyLnByb3RvdHlwZS5kYW1hZ2UgPSBmdW5jdGlvbihpLCBkbWcpIHsKCXRoaXMubGlzdFtpXS5ocCAtPSBkbWc7CglpZiAodGhpcy5saXN0W2ldLmhwIDw9IDApIHsKCQl2YXIgYmFzZSA9IHRoaXMubGlzdFtpXTsKCQl0aGlzLnBsYXllckhhbmRsZXIua2lsbHMrKzsKCQlmb3IgKHZhciBqID0gMDsgaiA8IDEgKyBiYXNlLmxldmVsICogMzsgaisrKSB7CgkJCXRoaXMucGlja3VwSGFuZGxlci5jcmVhdGUoYmFzZS54ICsgTWF0aC5yYW5kb20oKSAqIDEwIC0gNSwgYmFzZS55ICsgTWF0aC5yYW5kb20oKSAqIDEwIC0gNSkKCQl9CgkJdmFyIGJsYXN0ID0gYmFzZS5sZXZlbCArIDg7CgkJdGhpcy5wb29sLnB1c2goYmFzZSk7CiAgICB2YXIgdGVtcDEgPSB0aGlzLmxpc3RbaV0KICAgIGZvciAodmFyIGogPSAwOyBqIDwgMTAwOyBqKyspIHsKCQkJdGhpcy5wbGF5ZXJTaG90SGFuZGxlci5jcmVhdGUodGhpcy5wbGF5ZXJIYW5kbGVyLngsIHRoaXMucGxheWVySGFuZGxlci55LCBNYXRoLnJhbmRvbSgpICogMiAtIDEsIE1hdGgucmFuZG9tKCkgKiAyIC0gMSkKCQl9CgkJdGhpcy5saXN0LnNwbGljZShpLCAxKQoJfQp9OwoKZnVuY3Rpb24gR2FtZU92ZXJTY3JlZW4obWFpbikgewoJbWFpbi5zdGF0ZSA9ICdnYW1lT3ZlclNjcmVlbic7CgltYWluLmNvbnRyb2xIYW5kbGVyLm1vdXNlTGVmdCA9IGZhbHNlOwoJbWFpbi5jb250ZXh0LmZpbGxTdHlsZSA9ICdyZ2JhKDI1NSwyNTUsMjU1LDAuOCknOwoJbWFpbi5jb250ZXh0LmZpbGxSZWN0KDAsIDIwLCBtYWluLmNhbnZhcy53aWR0aCwgbWFpbi5jYW52YXMuaGVpZ2h0IC0gMjApOwoJdmFyIGhXID0gbWFpbi5jYW52YXMud2lkdGggKiAwLjU7Cgl2YXIgaEggPSBtYWluLmNhbnZhcy5oZWlnaHQgKiAwLjU7Cgl2YXIgZGFyayA9ICdyZ2JhKDAsMCwwLDAuOSknOwoJdmFyIG1lZGl1bSA9ICdyZ2JhKDAsMCwwLDAuNSknOwoJdmFyIGxpZ2h0ID0gJ3JnYmEoMCwwLDAsMC4zKSc7CgluZXcgVGV4dChtYWluLmNvbnRleHQsICdHYW1lIE92ZXInLCBoVywgaEggLSAyMCwgJ25vcm1hbCAyMXB4LzEgJyArIG1haW4uZm9udEZhbWlseSwgZGFyayk7CgluZXcgVGV4dChtYWluLmNvbnRleHQsICdDbGljayB0byBQbGF5IEFnYWluJywgaFcsIGhIICsgMjAsICdub3JtYWwgMTdweC8xICcgKyBtYWluLmZvbnRGYW1pbHksIGRhcmspOwp9CgpmdW5jdGlvbiBNYWluKCkgewoJdGhpcy5mb250RmFtaWx5ID0gJyJTZWdvZSBVSSIsQXJpYWwsc2Fucy1zZXJpZic7Cgl0aGlzLmhhbmRsZXJzID0gWydjb250cm9sJywgJ2VuZW15JywgJ3dhbGwnLCAndHVycmV0JywgJ2Jhc2UnLCAncGxheWVyJywgJ3BsYXllclNob3QnLCAnZW5lbXlTaG90JywgJ3ZpZXcnLCAncGlja3VwJywgJ3JlbmRlciddOwoJdGhpcy5sZXZlbFdpZHRoID0gNjAwMDsKCXRoaXMubGV2ZWxIZWlnaHQgPSA2MDAwOwoJdGhpcy5zdGF0ZSA9ICdsb2FkaW5nJzsKCXRoaXMuY2FudmFzID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2NhbnZhcycpOwoJdGhpcy5jb250ZXh0ID0gdGhpcy5jYW52YXMuZ2V0Q29udGV4dCgnMmQnKTsKCXRoaXMucHJvY2Vzc1RpbWUgPSBuZXcgUHJvY2Vzc1RpbWUoKTsKCXRoaXMucHJvY2Vzc0NvdW50ID0gMDsKCWZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5oYW5kbGVycy5sZW5ndGg7IGkrKykgewoJCXZhciBuYW1lID0gdGhpcy5oYW5kbGVyc1tpXSArICdIYW5kbGVyJzsKCQl0aGlzW25hbWVdID0gbmV3IHdpbmRvd1tuYW1lLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgbmFtZS5zbGljZSgxKV0odGhpcykKCX0KCXNldEludGVydmFsKHRoaXMuZW50ZXJGcmFtZS5iaW5kKHRoaXMpLCAxNi42NjY3KTsKCW5ldyBNZW51U2NyZWVuKHRoaXMpCn0KTWFpbi5wcm90b3R5cGUuc3RhcnRHYW1lID0gZnVuY3Rpb24oKSB7Cglmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuaGFuZGxlcnMubGVuZ3RoOyBpKyspIHsKCQl0aGlzW3RoaXMuaGFuZGxlcnNbaV0gKyAnSGFuZGxlciddLmluaXQodGhpcykKCX0KCW5ldyBDcmVhdGVMZXZlbCh0aGlzKTsKCXRoaXMuc3RhdGUgPSAnZ2FtZScKfTsKTWFpbi5wcm90b3R5cGUuZW50ZXJGcmFtZSA9IGZ1bmN0aW9uKCkgewoJaWYgKHRoaXMuc3RhdGUgIT0gJ2dhbWUnKSB7CgkJcmV0dXJuCgl9Cglmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuaGFuZGxlcnMubGVuZ3RoOyBpKyspIHsKCQl0aGlzW3RoaXMuaGFuZGxlcnNbaV0gKyAnSGFuZGxlciddLmVudGVyRnJhbWUoKQoJfQoJaWYgKHRoaXMucGxheWVySGFuZGxlci5ocCA8PSAwKSB7CgkJbmV3IEdhbWVPdmVyU2NyZWVuKHRoaXMpCgl9Cn07CgpmdW5jdGlvbiBNZW51U2NyZWVuKG1haW4pIHsKCW1haW4uc3RhdGUgPSAnbWVudVNjcmVlbic7CgltYWluLmNvbnRyb2xIYW5kbGVyLm1vdXNlTGVmdCA9IGZhbHNlOwoJbWFpbi5jb250ZXh0LmNsZWFyUmVjdCgwLCAwLCBtYWluLmNhbnZhcy53aWR0aCwgbWFpbi5jYW52YXMuaGVpZ2h0KTsKCXZhciBoVyA9IG1haW4uY2FudmFzLndpZHRoICogMC41OwoJdmFyIGhIID0gbWFpbi5jYW52YXMuaGVpZ2h0ICogMC41OwoJdmFyIGRhcmsgPSAncmdiYSgwLDAsMCwwLjkpJzsKCXZhciBtZWRpdW0gPSAncmdiYSgwLDAsMCwwLjUpJzsKCXZhciBsaWdodCA9ICdyZ2JhKDAsMCwwLDAuMyknOwoKCW5ldyBUZXh0KG1haW4uY29udGV4dCwgJ0NsaWNrIHRvIFN0YXJ0JywgaFcsIGhIIC0gNTAsICdub3JtYWwgMTdweC8xICcgKyBtYWluLmZvbnRGYW1pbHksIGRhcmspOwoJbmV3IFRleHQobWFpbi5jb250ZXh0LCAnVXNlICJXQVNEIiB0byBtb3ZlIGFuZCAiTGVmdCBDbGljayIgdG8gc2hvb3QuJywgaFcsIGhIIC0gMjAsICdub3JtYWwgMTVweC8xICcgKyBtYWluLmZvbnRGYW1pbHksIG1lZGl1bSk7CgluZXcgVGV4dChtYWluLmNvbnRleHQsICciVGFiIiBvciAiTSIgc2hvd3MgdGhlIG1pbmltYXAuIExhcmdlciBkb3RzIGFyZSBoYXJkZXIgYmFzZXMuJywgaFcsIGhILCAnbm9ybWFsIDE1cHgvMSAnICsgbWFpbi5mb250RmFtaWx5LCBtZWRpdW0pOwoJbmV3IFRleHQobWFpbi5jb250ZXh0LCAnRW5lbWllcyBhbmQgYmFzZXMgZHJvcCBibHVlIG9yYnMsIHdoaWNoIGluY3JlYXNlIHlvdXIgcG93ZXIuJywgaFcsIGhIICsgMjAsICdub3JtYWwgMTVweC8xICcgKyBtYWluLmZvbnRGYW1pbHksIG1lZGl1bSk7Cn0KCmZ1bmN0aW9uIE9iamVjdCgpIHt9CgpmdW5jdGlvbiBQaWNrdXBIYW5kbGVyKG1haW4pIHsKCXRoaXMucmFkaXVzID0gNzsKCXRoaXMuZGFtYWdlID0gMC40OwoJdGhpcy5yZWxvYWRSYXRlID0gMC45NTsKCXRoaXMuaHAgPSAzOwoJdGhpcy5saXN0ID0gW107Cgl0aGlzLnBvb2wgPSBbXQp9ClBpY2t1cEhhbmRsZXIucHJvdG90eXBlLmluaXQgPSBmdW5jdGlvbihtYWluKSB7Cgl0aGlzLmxpc3QubGVuZ3RoID0gMDsKCXRoaXMucGxheWVySGFuZGxlciA9IG1haW4ucGxheWVySGFuZGxlcjsKCXRoaXMucGxheWVyU2hvdEhhbmRsZXIgPSBtYWluLnBsYXllclNob3RIYW5kbGVyCn07ClBpY2t1cEhhbmRsZXIucHJvdG90eXBlLmVudGVyRnJhbWUgPSBmdW5jdGlvbigpIHsKCXZhciBwbGF5ZXIgPSB0aGlzLnBsYXllckhhbmRsZXI7Cgl2YXIgZGlzdDsKCWZvciAodmFyIGkgPSB0aGlzLmxpc3QubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHsKCQl2YXIgcGlja3VwID0gdGhpcy5saXN0W2ldOwoJCXBpY2t1cC5kZWxheS0tOwoJCWlmIChwaWNrdXAuZGVsYXkgPD0gMCkgewoJCQlkaXN0ID0gTWF0aC5zcXJ0KChwbGF5ZXIueCAtIHBpY2t1cC54KSAqIChwbGF5ZXIueCAtIHBpY2t1cC54KSArIChwbGF5ZXIueSAtIHBpY2t1cC55KSAqIChwbGF5ZXIueSAtIHBpY2t1cC55KSkgLSBwbGF5ZXIucmFkaXVzIC0gcGlja3VwLnJhZGl1czsKCQkJaWYgKGRpc3QgPD0gMCkgewoJCQkJcGxheWVyLm1heEhwICs9IE1hdGguY2VpbChNYXRoLnJhbmRvbSgpICogMTApICsgNzsKCQkJCXBsYXllci5ocCArPSA1OwoJCQkJcGxheWVyLmRhbWFnZSArPSBNYXRoLnJhbmRvbSgpICogMC4wMyArIDAuMDM7CgkJCQlpZiAocGxheWVyLnJlbG9hZFJhdGUgPiAzLjApIHsKCQkJCQlwbGF5ZXIucmVsb2FkUmF0ZSAqPSAwLjk5CgkJCQl9CgkJCQlmb3IgKHZhciBqID0gMDsgaiA8IDk7IGorKykgewoJCQkJCXRoaXMucGxheWVyU2hvdEhhbmRsZXIuY3JlYXRlKHBpY2t1cC54LCBwaWNrdXAueSwgTWF0aC5yYW5kb20oKSAqIDIgLSAxLCBNYXRoLnJhbmRvbSgpICogMiAtIDEpCgkJCQl9CgkJCQl0aGlzLnBvb2wucHVzaChwaWNrdXApOwoJCQkJdGhpcy5saXN0LnNwbGljZShpLCAxKQoJCQl9IGVsc2UgaWYgKGRpc3QgPD0gNDApIHsKCQkJCXBpY2t1cC54ICs9IChwbGF5ZXIueCAtIHBpY2t1cC54KSAqICgxNjAgLSBkaXN0ICogNCkgKiAwLjAwMTsKCQkJCXBpY2t1cC55ICs9IChwbGF5ZXIueSAtIHBpY2t1cC55KSAqICgxNjAgLSBkaXN0ICogNCkgKiAwLjAwMQoJCQl9CgkJCXBpY2t1cC5kZWxheSA9IChkaXN0IC0gNDApIC8gcGxheWVyLnNwZWVkCgkJfQoJfQp9OwpQaWNrdXBIYW5kbGVyLnByb3RvdHlwZS5jcmVhdGUgPSBmdW5jdGlvbih4LCB5KSB7Cgl2YXIgcGlja3VwID0gdGhpcy5wb29sLmxlbmd0aCA+IDAgPyB0aGlzLnBvb2wucG9wKCkgOiBuZXcgT2JqZWN0KCk7CglwaWNrdXAueCA9IHg7CglwaWNrdXAueSA9IHk7CglwaWNrdXAuZGVsYXkgPSAwOwoJcGlja3VwLnJhZGl1cyA9IHRoaXMucmFkaXVzOwoJdGhpcy5saXN0LnB1c2gocGlja3VwKQp9OwoKZnVuY3Rpb24gUGxheWVySGFuZGxlcihtYWluKSB7Cgl0aGlzLnJhZGl1cyA9IDEyLjA7Cgl0aGlzLmFjY2VsID0gMC4zOwoJdGhpcy5zcGVlZCA9IDIuMDsKCXRoaXMuc3RhcnRIcCA9IDEwMC4wOwoJdGhpcy5zdGFydFJlbG9hZFJhdGUgPSAxMi4wOwoJdGhpcy5zaG90U3BlZWQgPSA1LjA7Cgl0aGlzLnN0YXJ0RGFtYWdlID0gMS4wOwoJdGhpcy50dXJyZXRSYWRpdXMgPSB0aGlzLnJhZGl1cyAqIDAuNjsKCXRoaXMuaHA7Cgl0aGlzLm1heEhwOwogIHRoaXMuZWxlZnQgPSAwCgl0aGlzLmtpbGxzOwoJdGhpcy5kYW1hZ2U7Cgl0aGlzLnJlbG9hZFJhdGU7Cgl0aGlzLmxpc3QgPSBbdGhpc10KfQpQbGF5ZXJIYW5kbGVyLnByb3RvdHlwZS5pbml0ID0gZnVuY3Rpb24obWFpbikgewoJdGhpcy5jYW52YXMgPSBtYWluLmNhbnZhczsKCXRoaXMuY29udHJvbEhhbmRsZXIgPSBtYWluLmNvbnRyb2xIYW5kbGVyOwoJdGhpcy52aWV3SGFuZGxlciA9IG1haW4udmlld0hhbmRsZXI7Cgl0aGlzLmxldmVsV2lkdGggPSBtYWluLmxldmVsV2lkdGg7Cgl0aGlzLmxldmVsSGVpZ2h0ID0gbWFpbi5sZXZlbEhlaWdodDsKCXRoaXMucGxheWVyU2hvdEhhbmRsZXIgPSBtYWluLnBsYXllclNob3RIYW5kbGVyOwoJdGhpcy5wcm9jZXNzVGltZSA9IG1haW4ucHJvY2Vzc1RpbWU7Cgl0aGlzLnggPSBtYWluLmxldmVsV2lkdGggKiAwLjU7Cgl0aGlzLnkgPSBtYWluLmxldmVsSGVpZ2h0ICogMC41OwoJdGhpcy52WCA9IDA7Cgl0aGlzLnZZID0gMDsKCXRoaXMuaHAgPSB0aGlzLnN0YXJ0SHA7Cgl0aGlzLm1heEhwID0gdGhpcy5zdGFydEhwOwoJdGhpcy5raWxscyA9IDA7Cgl0aGlzLmRhbWFnZSA9IHRoaXMuc3RhcnREYW1hZ2U7Cgl0aGlzLnJlbG9hZCA9IDA7Cgl0aGlzLnJlbG9hZFJhdGUgPSB0aGlzLnN0YXJ0UmVsb2FkUmF0ZTsKCXRoaXMudGljayA9IGZhbHNlCn07ClBsYXllckhhbmRsZXIucHJvdG90eXBlLmVudGVyRnJhbWUgPSBmdW5jdGlvbigpIHsKCXZhciBvYmosIGksIHZYLCB2WTsKCXZYID0gdGhpcy5jb250cm9sSGFuZGxlci5hID8gLXRoaXMuYWNjZWwgOiAodGhpcy5jb250cm9sSGFuZGxlci5kID8gdGhpcy5hY2NlbCA6IDApOwoJdlkgPSB0aGlzLmNvbnRyb2xIYW5kbGVyLncgPyAtdGhpcy5hY2NlbCA6ICh0aGlzLmNvbnRyb2xIYW5kbGVyLnMgPyB0aGlzLmFjY2VsIDogMCk7CglpZiAodlggIT0gMCAmJiB2WSAhPSAwKSB7CgkJdlggKj0gMC43MDcxOwoJCXZZICo9IDAuNzA3MQoJfSBlbHNlIGlmICh2WCA9PSAwICYmIHZZID09IDApIHsKCQl0aGlzLnZYICo9IDAuNzsKCQl0aGlzLnZZICo9IDAuNwoJfQoJdGhpcy52WCArPSB2WDsKCXRoaXMudlkgKz0gdlk7CglkaXN0ID0gTWF0aC5zcXJ0KHRoaXMudlggKiB0aGlzLnZYICsgdGhpcy52WSAqIHRoaXMudlkpOwoJaWYgKGRpc3QgPiB0aGlzLnNwZWVkKSB7CgkJZGlzdCA9IHRoaXMuc3BlZWQgLyBkaXN0OwoJCXRoaXMudlggKj0gZGlzdDsKCQl0aGlzLnZZICo9IGRpc3QKCX0KCXRoaXMueCArPSB0aGlzLnZYOwoJdGhpcy55ICs9IHRoaXMudlk7CglpZiAodGhpcy54IDwgdGhpcy5yYWRpdXMpIHsKCQl0aGlzLnggPSB0aGlzLnJhZGl1cwoJfSBlbHNlIGlmICh0aGlzLnggPiB0aGlzLmxldmVsV2lkdGggLSB0aGlzLnJhZGl1cykgewoJCXRoaXMueCA9IHRoaXMubGV2ZWxXaWR0aCAtIHRoaXMucmFkaXVzCgl9CglpZiAodGhpcy55IDwgMjAgKyB0aGlzLnJhZGl1cykgewoJCXRoaXMueSA9IDIwICsgdGhpcy5yYWRpdXMKCX0gZWxzZSBpZiAodGhpcy55ID4gdGhpcy5sZXZlbEhlaWdodCAtIHRoaXMucmFkaXVzKSB7CgkJdGhpcy55ID0gdGhpcy5sZXZlbEhlaWdodCAtIHRoaXMucmFkaXVzCgl9CglpZiAodGhpcy5ocCA8IHRoaXMubWF4SHApIHsKCQl0aGlzLmhwICs9IHRoaXMubWF4SHAgKiAwLjAwMDM7CgkJaWYgKHRoaXMuaHAgPiB0aGlzLm1heEhwKSB7CgkJCXRoaXMuaHAgPSB0aGlzLm1heEhwCgkJfQoJfQoJdGhpcy5yZWxvYWQtLTsKCWlmICh0aGlzLmNvbnRyb2xIYW5kbGVyLm1vdXNlTGVmdCAmJiB0aGlzLnJlbG9hZCA8PSAwKSB7CgkJdlggPSB0aGlzLmNvbnRyb2xIYW5kbGVyLm1vdXNlWCArIHRoaXMudmlld0hhbmRsZXIueCAtIHRoaXMuY2FudmFzLndpZHRoICogMC41IC0gdGhpcy54OwoJCXZZID0gdGhpcy5jb250cm9sSGFuZGxlci5tb3VzZVkgKyB0aGlzLnZpZXdIYW5kbGVyLnkgLSB0aGlzLmNhbnZhcy5oZWlnaHQgKiAwLjUgLSB0aGlzLnk7CgkJZGlzdCA9IE1hdGguc3FydCh2WCAqIHZYICsgdlkgKiB2WSk7CgkJdlggLz0gZGlzdDsKCQl2WSAvPSBkaXN0OwoJCXRoaXMudGljayA9ICF0aGlzLnRpY2s7CgkJaWYgKHRoaXMudGljaykgewoJCQl0aGlzLnBsYXllclNob3RIYW5kbGVyLmNyZWF0ZSh0aGlzLnggKyB2WSAqIHRoaXMudHVycmV0UmFkaXVzLCB0aGlzLnkgLSB2WCAqIHRoaXMudHVycmV0UmFkaXVzLCB2WCAqIHRoaXMuc2hvdFNwZWVkICsgTWF0aC5yYW5kb20oKSAqIDAuNiAtIDAuMywgdlkgKiB0aGlzLnNob3RTcGVlZCArIE1hdGgucmFuZG9tKCkgKiAwLjYgLSAwLjMpCgkJfSBlbHNlIHsKCQkJdGhpcy5wbGF5ZXJTaG90SGFuZGxlci5jcmVhdGUodGhpcy54IC0gdlkgKiB0aGlzLnR1cnJldFJhZGl1cywgdGhpcy55ICsgdlggKiB0aGlzLnR1cnJldFJhZGl1cywgdlggKiB0aGlzLnNob3RTcGVlZCArIE1hdGgucmFuZG9tKCkgKiAwLjYgLSAwLjMsIHZZICogdGhpcy5zaG90U3BlZWQgKyBNYXRoLnJhbmRvbSgpICogMC42IC0gMC4zKQoJCX0KCQl0aGlzLnJlbG9hZCA9IHRoaXMucmVsb2FkUmF0ZQoJfQp9OwoKZnVuY3Rpb24gUGxheWVyU2hvdEhhbmRsZXIobWFpbikgewoJdGhpcy5yYWRpdXMgPSAzOwoJdGhpcy5saXN0ID0gW107Cgl0aGlzLnBvb2wgPSBbXQp9ClBsYXllclNob3RIYW5kbGVyLnByb3RvdHlwZS5pbml0ID0gZnVuY3Rpb24obWFpbikgewoJdGhpcy5saXN0Lmxlbmd0aCA9IDA7Cgl0aGlzLnBsYXllckhhbmRsZXIgPSBtYWluLnBsYXllckhhbmRsZXI7Cgl0aGlzLnNwZWVkID0gbWFpbi5wbGF5ZXJIYW5kbGVyLnNob3RTcGVlZAp9OwpQbGF5ZXJTaG90SGFuZGxlci5wcm90b3R5cGUuZW50ZXJGcmFtZSA9IGZ1bmN0aW9uKCkgewoJdmFyIHNob3QsIGk7Cglmb3IgKGkgPSB0aGlzLmxpc3QubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHsKCQlzaG90ID0gdGhpcy5saXN0W2ldOwoJCXNob3QueCArPSBzaG90LnZYOwoJCXNob3QueSArPSBzaG90LnZZOwoJCXNob3QucmFkaXVzIC09IDAuMDQ1OwoJCWlmIChzaG90LnJhZGl1cyA8PSAxKSB7CgkJCXRoaXMucG9vbC5wdXNoKHNob3QpOwoJCQl0aGlzLmxpc3Quc3BsaWNlKGksIDEpOwoJCQljb250aW51ZQoJCX0KCX0KfTsKUGxheWVyU2hvdEhhbmRsZXIucHJvdG90eXBlLmNyZWF0ZSA9IGZ1bmN0aW9uKHgsIHksIHZYLCB2WSkgewoJdmFyIHNob3QgPSB0aGlzLnBvb2wubGVuZ3RoID4gMCA/IHRoaXMucG9vbC5wb3AoKSA6IG5ldyBPYmplY3QoKTsKCXNob3QueCA9IHg7CglzaG90LnkgPSB5OwoJc2hvdC52WCA9IHZYOwoJc2hvdC52WSA9IHZZOwoJc2hvdC5yYWRpdXMgPSB0aGlzLnJhZGl1czsKCXRoaXMubGlzdC5wdXNoKHNob3QpCn07ClBsYXllclNob3RIYW5kbGVyLnByb3RvdHlwZS5oaXQgPSBmdW5jdGlvbihpKSB7Cgl0aGlzLnBvb2wucHVzaCh0aGlzLmxpc3RbaV0pOwoJdGhpcy5saXN0LnNwbGljZShpLCAxKQp9OwoKZnVuY3Rpb24gUHJvY2Vzc1RpbWUoKSB7Cgl0aGlzLmxvZyA9IHt9Cn0KUHJvY2Vzc1RpbWUucHJvdG90eXBlLmxvZ1RpbWUgPSBmdW5jdGlvbihuYW1lLCBwcm9jZXNzVGltZSkgewoJaWYgKG5hbWUgaW4gdGhpcy5sb2cpIHsKCQlpZiAocHJvY2Vzc1RpbWUgPiB0aGlzLmxvZ1tuYW1lXSkgewoJCQl0aGlzLmxvZ1tuYW1lXSA9IHByb2Nlc3NUaW1lCgkJfQoJfSBlbHNlIHsKCQl0aGlzLmxvZ1tuYW1lXSA9IHByb2Nlc3NUaW1lCgl9Cn07ClByb2Nlc3NUaW1lLnByb3RvdHlwZS5vdXRwdXRMb2cgPSBmdW5jdGlvbigpIHsKCWNvbnNvbGUuY2xlYXIoKTsKCWZvciAodmFyIG5hbWUgaW4gdGhpcy5sb2cpIHsKCQljb25zb2xlLmxvZyhuYW1lICsgJyAnICsgKG5ldyBBcnJheSgxOCAtIG5hbWUubGVuZ3RoKS5qb2luKCcgJykpICsgJyAgIG1heDonICsgKHRoaXMubG9nW25hbWVdID4gMCA/IHRoaXMubG9nW25hbWVdIDogJycpKTsKCQl0aGlzLmxvZ1tuYW1lXSA9IDAKCX0KfTsKCmZ1bmN0aW9uIFJlbmRlckhhbmRsZXIobWFpbikgewoJdGhpcy5tYXBTaXplID0gMjAwOwoJdGhpcy5tYXBYID0gdGhpcy5tYXBTaXplIC8gbWFpbi5sZXZlbFdpZHRoOwoJdGhpcy5tYXBZID0gdGhpcy5tYXBTaXplIC8gbWFpbi5sZXZlbEhlaWdodDsKCXRoaXMubWFpbiA9IG1haW47Cgl0aGlzLmNhbnZhcyA9IG1haW4uY2FudmFzOwoJdGhpcy5jb250ZXh0ID0gbWFpbi5jb250ZXh0Cn0KUmVuZGVySGFuZGxlci5wcm90b3R5cGUuaW5pdCA9IGZ1bmN0aW9uKG1haW4pIHsKCXRoaXMuZHJhd0xpc3QgPSBbewoJCWNvbG9yOiAncmdiYSgwLDI1NSwwLDAuNzUpJywKCQloYW5kbGVyOiBtYWluLnBsYXllckhhbmRsZXIKCX0sIHsKCQljb2xvcjogJ3JnYmEoMCwxNDcsMTY5LDAuOCknLAoJCWhhbmRsZXI6IG1haW4ucGlja3VwSGFuZGxlcgoJfSwgewoJCWNvbG9yOiAncmdiYSgyNTUsMTI4LDUxLDAuNSknLAoJCWhhbmRsZXI6IG1haW4ud2FsbEhhbmRsZXIKCX0sIHsKCQljb2xvcjogJ3JnYmEoOTAsMzEsMzEsMC42KScsCgkJaGFuZGxlcjogbWFpbi50dXJyZXRIYW5kbGVyCgl9LCB7CgkJY29sb3I6ICdyZ2JhKDI1NSw1MSwwLDAuOCknLAoJCWhhbmRsZXI6IG1haW4uYmFzZUhhbmRsZXIKCX0sIHsKCQljb2xvcjogJyM2NmZmZmYnLAoJCWhhbmRsZXI6IG1haW4uZW5lbXlIYW5kbGVyCgl9LCB7CgkJY29sb3I6ICdyZ2JhKDAsMCwyNTUsMC44KScsLy9ECgkJaGFuZGxlcjogbWFpbi5wbGF5ZXJTaG90SGFuZGxlcgoJfSwgewoJCWNvbG9yOiAncmdiYSgyNTUsNTEsMjA0KScsLy9ECgkJaGFuZGxlcjogbWFpbi5lbmVteVNob3RIYW5kbGVyCgl9XTsKCXRoaXMuYmFzZUhhbmRsZXIgPSBtYWluLmJhc2VIYW5kbGVyOwoJdGhpcy5wbGF5ZXJIYW5kbGVyID0gbWFpbi5wbGF5ZXJIYW5kbGVyOwoJdGhpcy5jb250cm9sSGFuZGxlciA9IG1haW4uY29udHJvbEhhbmRsZXI7Cgl0aGlzLnZpZXdIYW5kbGVyID0gbWFpbi52aWV3SGFuZGxlcjsKCXRoaXMuYmdDYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTsKCXRoaXMuYmdDYW52YXMud2lkdGggPSBtYWluLmxldmVsV2lkdGg7Cgl0aGlzLmJnQ2FudmFzLmhlaWdodCA9IG1haW4ubGV2ZWxIZWlnaHQ7Cgl0aGlzLmJnQ29udGV4dCA9IHRoaXMuYmdDYW52YXMuZ2V0Q29udGV4dCgnMmQnKTsKCWZvciAodmFyIGkgPSAwOyBpIDwgNTAwOyBpKyspIHsKCQl0aGlzLmJnQ29udGV4dC5maWxsU3R5bGUgPSAncmdiYSgwLDAsMCwnICsgKE1hdGgucmFuZG9tKCkgKiAwLjEpICsgJyknOwoJCXRoaXMuYmdDb250ZXh0LmJlZ2luUGF0aCgpOwoJCXRoaXMuYmdDb250ZXh0LmFyYyhNYXRoLnJhbmRvbSgpICogbWFpbi5sZXZlbFdpZHRoLCBNYXRoLnJhbmRvbSgpICogbWFpbi5sZXZlbEhlaWdodCwgTWF0aC5yYW5kb20oKSAqIDEwMCwgMCwgNi4yODMyKTsKCQl0aGlzLmJnQ29udGV4dC5maWxsKCk7CgkJdGhpcy5iZ0NvbnRleHQuY2xvc2VQYXRoKCkKCX0KCXRoaXMuYmdDb250ZXh0LmZpbGxTdHlsZSA9ICdyZ2JhKDcwLDcwLDcwLDAuMTUpJwp9OwpSZW5kZXJIYW5kbGVyLnByb3RvdHlwZS5lbnRlckZyYW1lID0gZnVuY3Rpb24oKSB7Cgl2YXIgY29udGV4dCA9IHRoaXMuY29udGV4dDsKCXZhciBvYmosIHgsIHksIGksIGo7Cgl2YXIgb2Zmc2V0WCA9IHRoaXMuY2FudmFzLndpZHRoICogMC41IC0gdGhpcy52aWV3SGFuZGxlci54OwoJdmFyIG9mZnNldFkgPSB0aGlzLmNhbnZhcy5oZWlnaHQgKiAwLjUgLSB0aGlzLnZpZXdIYW5kbGVyLnk7Cgljb250ZXh0LmNsZWFyUmVjdCgwLCAwLCB0aGlzLmNhbnZhcy53aWR0aCwgdGhpcy5jYW52YXMuaGVpZ2h0KTsKCWNvbnRleHQuZHJhd0ltYWdlKHRoaXMuYmdDYW52YXMsIG9mZnNldFgsIG9mZnNldFkpOwoJZm9yIChpID0gMDsgaSA8IHRoaXMuZHJhd0xpc3QubGVuZ3RoOyBpKyspIHsKCQljb250ZXh0LmZpbGxTdHlsZSA9IHRoaXMuZHJhd0xpc3RbaV0uY29sb3I7CgkJZm9yIChqID0gdGhpcy5kcmF3TGlzdFtpXS5oYW5kbGVyLmxpc3QubGVuZ3RoIC0gMTsgaiA+PSAwOyBqLS0pIHsKCQkJb2JqID0gdGhpcy5kcmF3TGlzdFtpXS5oYW5kbGVyLmxpc3Rbal07CgkJCXggPSBvYmoueCArIG9mZnNldFg7CgkJCXkgPSBvYmoueSArIG9mZnNldFk7CgkJCWlmICh4ID4gLW9iai5yYWRpdXMgJiYgeCA8IHRoaXMuY2FudmFzLndpZHRoICsgb2JqLnJhZGl1cyAmJiB5ID4gLW9iai5yYWRpdXMgJiYgeSA8IHRoaXMuY2FudmFzLmhlaWdodCArIG9iai5yYWRpdXMpIHsKCQkJCWlmIChpID4gNSkgewoJCQkJCWNvbnRleHQuZmlsbFJlY3QoeCAtIG9iai5yYWRpdXMsIHkgLSBvYmoucmFkaXVzLCBvYmoucmFkaXVzICogMiwgb2JqLnJhZGl1cyAqIDIpOwoJCQkJCWlmIChNYXRoLnJhbmRvbSgpIDwgMC4yICYmIHR5cGVvZiB0aGlzLmRyYXdMaXN0W2ldLnBhaW50ICE9PSAndW5kZWZpbmVkJykgewoJCQkJCQl0aGlzLmJnQ29udGV4dC5maWxsUmVjdChvYmoueCwgb2JqLnksIDIsIDIpCgkJCQkJfQoJCQkJfSBlbHNlIHsKCQkJCQljb250ZXh0LmJlZ2luUGF0aCgpOwoJCQkJCWNvbnRleHQuYXJjKHgsIHksIG9iai5yYWRpdXMsIDAsIDYuMjgzMik7CgkJCQkJY29udGV4dC5maWxsKCk7CgkJCQkJY29udGV4dC5jbG9zZVBhdGgoKQoJCQkJfQoJCQl9CgkJfQoJfQoJY29udGV4dC5maWxsU3R5bGUgPSAnIzQ0NDQ0NCc7Cgljb250ZXh0LmZpbGxSZWN0KDAsIDAsIHRoaXMuY2FudmFzLndpZHRoLCAyMCk7Cgljb250ZXh0LnRleHRBbGlnbiA9ICdsZWZ0JzsKCWNvbnRleHQuZm9udCA9ICdib2xkIDExcHgvMSBBcmlhbCc7Cgljb250ZXh0LmZpbGxTdHlsZSA9ICcjQUFBQUFBJzsKCWNvbnRleHQuZmlsbFRleHQoJ0hlYWx0aCcsIDUsIDEwKTsKCWNvbnRleHQuZmlsbFRleHQoJ0RhbWFnZScsIDE0NSwgMTApOwoJY29udGV4dC5maWxsVGV4dCgnRmlyZSBSYXRlJywgMjMwLCAxMCk7Cgljb250ZXh0LmZpbGxUZXh0KCdLaWxscycsIDM0NSwgMTApOwoJY29udGV4dC5maWxsVGV4dCgnRFBTJywgNDIwLCAxMCk7CiAgY29udGV4dC5maWxsVGV4dCgnRHJvbmVzIExlZnQnLCA0OTAsIDEwKTsKCWNvbnRleHQuZm9udCA9ICdib2xkIDE1cHgvMSBBcmlhbCc7Cgljb250ZXh0LmZpbGxTdHlsZSA9ICcjREREREREJzsKCWNvbnRleHQuZmlsbFRleHQoTWF0aC5yb3VuZCh0aGlzLnBsYXllckhhbmRsZXIuaHApICsgJy8nICsgdGhpcy5wbGF5ZXJIYW5kbGVyLm1heEhwLCA0MywgMTApOwoJY29udGV4dC5maWxsVGV4dChNYXRoLnJvdW5kKHRoaXMucGxheWVySGFuZGxlci5kYW1hZ2UgKiAxMCkgLyAxMCwgMTkzLCAxMCk7Cgljb250ZXh0LmZpbGxUZXh0KChNYXRoLnJvdW5kKDYwIC8gdGhpcy5wbGF5ZXJIYW5kbGVyLnJlbG9hZFJhdGUgKiAxMCkgLyAxMCkgKyAnL3MnLCAyODIsIDEwKTsKCWNvbnRleHQuZmlsbFRleHQodGhpcy5wbGF5ZXJIYW5kbGVyLmtpbGxzLCAzNzIsIDEwKTsKCWNvbnRleHQuZmlsbFRleHQoKE1hdGgucm91bmQoNjAgLyB0aGlzLnBsYXllckhhbmRsZXIucmVsb2FkUmF0ZSAqIHRoaXMucGxheWVySGFuZGxlci5kYW1hZ2UgKiAxMCkgLyAxMCksIDQ0NiwgMTApOwogIGNvbnRleHQuZmlsbFRleHQodGhpcy5wbGF5ZXJIYW5kbGVyLmVsZWZ0LCA1NTYsIDEwKQoJaWYgKHRoaXMuY29udHJvbEhhbmRsZXIudGFiIHx8IHRoaXMuY29udHJvbEhhbmRsZXIubSkgewoJCWNvbnRleHQuZmlsbFN0eWxlID0gJ3JnYmEoMjU1LDI1NSwyNTUsMC44NSknOwoJCWNvbnRleHQuZmlsbFJlY3QoMCwgMjAsIHRoaXMubWFwU2l6ZSwgdGhpcy5tYXBTaXplKTsKCQljb250ZXh0LmZpbGxTdHlsZSA9ICdyZ2JhKDE1OCwwLDAsMC41KSc7CgkJZm9yIChpID0gdGhpcy5iYXNlSGFuZGxlci5saXN0Lmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7CgkJCW9iaiA9IHRoaXMuYmFzZUhhbmRsZXIubGlzdFtpXTsKCQkJaiA9IDMgKyBvYmoubGV2ZWwgKiAyOwoJCQl4ID0gTWF0aC5yb3VuZChvYmoueCAqIHRoaXMubWFwWCAtIGogKiAwLjUpOwoJCQl5ID0gMjAgKyBNYXRoLnJvdW5kKG9iai55ICogdGhpcy5tYXBZIC0gaiAqIDAuNSk7CgkJCWNvbnRleHQuZmlsbFJlY3QoeCwgeSwgaiwgaikKCQl9CgkJY29udGV4dC5maWxsU3R5bGUgPSAncmdiYSgwLDAsMCwwLjcpJzsKCQl4ID0gTWF0aC5yb3VuZCh0aGlzLnBsYXllckhhbmRsZXIueCAqIHRoaXMubWFwWCAtIDMpOwoJCXkgPSAyMCArIE1hdGgucm91bmQodGhpcy5wbGF5ZXJIYW5kbGVyLnkgKiB0aGlzLm1hcFkgLSAzKTsKCQljb250ZXh0LmZpbGxSZWN0KHgsIHksIDYsIDYpCgl9Cn07CgpmdW5jdGlvbiBUZXh0KGNvbnRleHQsIHRleHQsIHgsIHksIGZvbnQsIHN0eWxlLCBhbGlnbiwgYmFzZWxpbmUpIHsKCWNvbnRleHQuZm9udCA9IHR5cGVvZiBmb250ID09PSAndW5kZWZpbmVkJyA/ICdub3JtYWwgMTZweC8xIEFyaWFsJyA6IGZvbnQ7Cgljb250ZXh0LmZpbGxTdHlsZSA9IHR5cGVvZiBzdHlsZSA9PT0gJ3VuZGVmaW5lZCcgPyAnIzAwMDAwMCcgOiBzdHlsZTsKCWNvbnRleHQudGV4dEFsaWduID0gdHlwZW9mIGFsaWduID09PSAndW5kZWZpbmVkJyA/ICdjZW50ZXInIDogYWxpZ247Cgljb250ZXh0LnRleHRCYXNlbGluZSA9IHR5cGVvZiBiYXNlbGluZSA9PT0gJ3VuZGVmaW5lZCcgPyAnbWlkZGxlJyA6IGJhc2VsaW5lOwoJY29udGV4dC5maWxsVGV4dCh0ZXh0LCB4LCB5KQp9CgpmdW5jdGlvbiBUdXJyZXRIYW5kbGVyKG1haW4pIHsKCXRoaXMuc3BlZWQgPSAwOwoJdGhpcy5zaG90U3BlZWQgPSAyLjU7Cgl0aGlzLmxpc3QgPSBbXTsKCXRoaXMucG9vbCA9IFtdCn0KVHVycmV0SGFuZGxlci5wcm90b3R5cGUuaW5pdCA9IGZ1bmN0aW9uKG1haW4pIHsKCXRoaXMubGlzdC5sZW5ndGggPSAwOwoJdGhpcy5wbGF5ZXJIYW5kbGVyID0gbWFpbi5wbGF5ZXJIYW5kbGVyOwoJdGhpcy5wbGF5ZXJTaG90SGFuZGxlciA9IG1haW4ucGxheWVyU2hvdEhhbmRsZXI7Cgl0aGlzLmVuZW15U2hvdEhhbmRsZXIgPSBtYWluLmVuZW15U2hvdEhhbmRsZXI7Cgl0aGlzLnBpY2t1cEhhbmRsZXIgPSBtYWluLnBpY2t1cEhhbmRsZXIKfTsKVHVycmV0SGFuZGxlci5wcm90b3R5cGUuZW50ZXJGcmFtZSA9IGZ1bmN0aW9uKCkgewoJdmFyIHBsYXllciA9IHRoaXMucGxheWVySGFuZGxlcjsKCXZhciBpLCBqLCB0dXJyZXQsIHNob3QsIGRpc3QsIGRpc3QyLCB2WCwgdlk7Cglmb3IgKGkgPSB0aGlzLmxpc3QubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHsKCQl0dXJyZXQgPSB0aGlzLmxpc3RbaV07CgkJdHVycmV0LnJlbG9hZC0tOwoJCXR1cnJldC5kZWxheS0tOwoJCWlmICh0dXJyZXQuZGVsYXkgPD0gMCkgewoJCQl2WCA9IHBsYXllci54IC0gdHVycmV0Lng7CgkJCXZZID0gcGxheWVyLnkgLSB0dXJyZXQueTsKCQkJZGlzdDIgPSB2WCAqIHZYICsgdlkgKiB2WTsKCQkJaWYgKGRpc3QyIDwgMTQ0KSB7CgkJCQlkaXN0ID0gOAoJCQl9IGVsc2UgaWYgKGRpc3QyIDwgNTc2KSB7CgkJCQlkaXN0ID0gMTYKCQkJfSBlbHNlIGlmIChkaXN0MiA8IDIzMDQpIHsKCQkJCWRpc3QgPSAzMgoJCQl9IGVsc2UgaWYgKGRpc3QyIDwgOTIxNikgewoJCQkJZGlzdCA9IDY0CgkJCX0gZWxzZSBpZiAoZGlzdDIgPCAzNjg2NCkgewoJCQkJZGlzdCA9IDEyOAoJCQl9IGVsc2UgaWYgKGRpc3QyIDwgMTQ3NDU2KSB7CgkJCQlkaXN0ID0gMjU2CgkJCX0gZWxzZSBpZiAoZGlzdDIgPCA1ODk4MjQpIHsKCQkJCWRpc3QgPSA1MTIKCQkJfSBlbHNlIGlmIChkaXN0MiA8IDIzNTkyOTYpIHsKCQkJCWRpc3QgPSAxMDI0CgkJCX0gZWxzZSB7CgkJCQlkaXN0ID0gMjA0OAoJCQl9CgkJCWRpc3QgPSAwLjUgKiAoZGlzdDIgLyBkaXN0ICsgZGlzdCk7CgkJCWRpc3QgPSAwLjUgKiAoZGlzdDIgLyBkaXN0ICsgZGlzdCk7CgkJCWlmIChkaXN0IC0gcGxheWVyLnJhZGl1cyAtIHR1cnJldC5yYWRpdXMgPiBNYXRoLm1heCgyNTAgKyB0dXJyZXQubGV2ZWwgKiA1MCwgMzUwKSkgewoJCQkJdHVycmV0LmRlbGF5ID0gTWF0aC5mbG9vcigoZGlzdCAtIHBsYXllci5yYWRpdXMgLSB0dXJyZXQucmFkaXVzIC0gTWF0aC5tYXgoMjUwICsgdHVycmV0LmxldmVsICogNTAsIDM1MCkpIC8gcGxheWVyLnNwZWVkKQoJCQl9CgkJCWlmIChkaXN0IC0gcGxheWVyLnJhZGl1cyAtIHR1cnJldC5yYWRpdXMgPD0gMjUwICsgdHVycmV0LmxldmVsICogNTApIHsKCQkJCWlmICh0dXJyZXQucmVsb2FkIDw9IDApIHsKCQkJCQl0aGlzLmVuZW15U2hvdEhhbmRsZXIuY3JlYXRlKHR1cnJldC54LCB0dXJyZXQueSwgdlggLyBkaXN0ICogdGhpcy5zaG90U3BlZWQgKyBNYXRoLnJhbmRvbSgpICogNCAtIDIsIHZZIC8gZGlzdCAqIHRoaXMuc2hvdFNwZWVkICsgTWF0aC5yYW5kb20oKSAqIDQgLSAyLCB0dXJyZXQuc2hvdFJhZGl1cywgdHVycmV0LnNob3REYW1hZ2UpOwoJCQkJCXR1cnJldC5yZWxvYWQgPSB0dXJyZXQucmVsb2FkUmF0ZQoJCQkJfQoJCQl9CgkJCWlmIChkaXN0IC0gcGxheWVyLnJhZGl1cyAtIHR1cnJldC5yYWRpdXMgPD0gMCkgewoJCQkJcGxheWVyLnZYID0gdlggKiAwLjA2OwoJCQkJcGxheWVyLnZZID0gdlkgKiAwLjA2CgkJCX0KCQkJaWYgKGRpc3QgLSBwbGF5ZXIucmFkaXVzIC0gdHVycmV0LnJhZGl1cyA8PSAzNTApIHsKCQkJCWZvciAoaiA9IHRoaXMucGxheWVyU2hvdEhhbmRsZXIubGlzdC5sZW5ndGggLSAxOyBqID49IDA7IGotLSkgewoJCQkJCXNob3QgPSB0aGlzLnBsYXllclNob3RIYW5kbGVyLmxpc3Rbal07CgkJCQkJZGlzdDIgPSAoc2hvdC54IC0gdHVycmV0LngpICogKHNob3QueCAtIHR1cnJldC54KSArIChzaG90LnkgLSB0dXJyZXQueSkgKiAoc2hvdC55IC0gdHVycmV0LnkpOwoJCQkJCWlmIChkaXN0MiA8IDE0NCkgewoJCQkJCQlkaXN0ID0gOAoJCQkJCX0gZWxzZSBpZiAoZGlzdDIgPCA1NzYpIHsKCQkJCQkJZGlzdCA9IDE2CgkJCQkJfSBlbHNlIGlmIChkaXN0MiA8IDIzMDQpIHsKCQkJCQkJZGlzdCA9IDMyCgkJCQkJfSBlbHNlIGlmIChkaXN0MiA8IDkyMTYpIHsKCQkJCQkJZGlzdCA9IDY0CgkJCQkJfSBlbHNlIGlmIChkaXN0MiA8IDM2ODY0KSB7CgkJCQkJCWRpc3QgPSAxMjgKCQkJCQl9IGVsc2UgaWYgKGRpc3QyIDwgMTQ3NDU2KSB7CgkJCQkJCWRpc3QgPSAyNTYKCQkJCQl9IGVsc2UgaWYgKGRpc3QyIDwgNTg5ODI0KSB7CgkJCQkJCWRpc3QgPSA1MTIKCQkJCQl9IGVsc2UgaWYgKGRpc3QyIDwgMjM1OTI5NikgewoJCQkJCQlkaXN0ID0gMTAyNAoJCQkJCX0gZWxzZSB7CgkJCQkJCWRpc3QgPSAyMDQ4CgkJCQkJfQoJCQkJCWRpc3QgPSAwLjUgKiAoZGlzdDIgLyBkaXN0ICsgZGlzdCk7CgkJCQkJZGlzdCA9IDAuNSAqIChkaXN0MiAvIGRpc3QgKyBkaXN0KSAtIHNob3QucmFkaXVzIC0gdHVycmV0LnJhZGl1czsKCQkJCQlpZiAoZGlzdCA8PSAwKSB7CgkJCQkJCXRoaXMucGxheWVyU2hvdEhhbmRsZXIuaGl0KGopOwoJCQkJCQl0aGlzLmRhbWFnZShpLCBwbGF5ZXIuZGFtYWdlKTsKCQkJCQl9CgkJCQl9CgkJCX0KCQl9Cgl9Cn07ClR1cnJldEhhbmRsZXIucHJvdG90eXBlLmNyZWF0ZSA9IGZ1bmN0aW9uKHgsIHksIGxldmVsKSB7Cgl2YXIgdHVycmV0ID0gdGhpcy5wb29sLmxlbmd0aCA+IDAgPyB0aGlzLnBvb2wucG9wKCkgOiBuZXcgT2JqZWN0KCk7Cgl0dXJyZXQueCA9IHg7Cgl0dXJyZXQueSA9IHk7Cgl0dXJyZXQubGV2ZWwgPSBsZXZlbDsKCXR1cnJldC5yZWxvYWQgPSAwOwoJdHVycmV0LmRlbGF5ID0gTWF0aC5jZWlsKE1hdGgucmFuZG9tKCkgKiA2MCk7Cgl0dXJyZXQucmFkaXVzID0gTWF0aC5taW4oMTIgKyBsZXZlbCAqIDMsIDE1KTsKCXR1cnJldC5ocCA9IDMwICsgbGV2ZWwgKiA0NTsKCXR1cnJldC5yZWxvYWRSYXRlID0gMTcgLSBsZXZlbCAqIDIgKyBNYXRoLnJhbmRvbSgpICogMTA7Cgl0dXJyZXQuc2hvdFJhZGl1cyA9IDMuNSArIGxldmVsICogMC41OwoJdHVycmV0LnNob3REYW1hZ2UgPSAzICsgbGV2ZWwgKiAyOwoJdGhpcy5saXN0LnB1c2godHVycmV0KQp9OwpUdXJyZXRIYW5kbGVyLnByb3RvdHlwZS5kYW1hZ2UgPSBmdW5jdGlvbihpLCBkbWcpIHsKCXRoaXMubGlzdFtpXS5ocCAtPSBkbWc7CglpZiAodGhpcy5saXN0W2ldLmhwIDw9IDApIHsKCQl2YXIgdHVycmV0ID0gdGhpcy5saXN0W2ldOwoJCXRoaXMucGxheWVySGFuZGxlci5raWxscysrOwoJCXRoaXMucGlja3VwSGFuZGxlci5jcmVhdGUodHVycmV0LngsIHR1cnJldC55KTsKCQlmb3IgKHZhciBqID0gMDsgaiA8IDMwOyBqKyspIHsKCQl9CgkJdGhpcy5wb29sLnB1c2godHVycmV0KTsKCQl0aGlzLmxpc3Quc3BsaWNlKGksIDEpCgl9Cn07CgpmdW5jdGlvbiBWaWV3SGFuZGxlcihtYWluKSB7Cgl0aGlzLng7Cgl0aGlzLnkKfQpWaWV3SGFuZGxlci5wcm90b3R5cGUuaW5pdCA9IGZ1bmN0aW9uKG1haW4pIHsKCXRoaXMueCA9IG1haW4ubGV2ZWxXaWR0aCAqIDAuNTsKCXRoaXMueSA9IG1haW4ubGV2ZWxIZWlnaHQgKiAwLjU7Cgl0aGlzLmNhbnZhcyA9IG1haW4uY2FudmFzOwoJdGhpcy5wbGF5ZXJIYW5kbGVyID0gbWFpbi5wbGF5ZXJIYW5kbGVyOwoJdGhpcy5sZXZlbFdpZHRoID0gbWFpbi5sZXZlbFdpZHRoOwoJdGhpcy5sZXZlbEhlaWdodCA9IG1haW4ubGV2ZWxIZWlnaHQKfTsKVmlld0hhbmRsZXIucHJvdG90eXBlLmVudGVyRnJhbWUgPSBmdW5jdGlvbigpIHsKCXRoaXMueCArPSAodGhpcy5wbGF5ZXJIYW5kbGVyLnggLSB0aGlzLngpICogMC4wNTsKCWlmICh0aGlzLnggPCB0aGlzLnBsYXllckhhbmRsZXIueCArIDEgJiYgdGhpcy54ID4gdGhpcy5wbGF5ZXJIYW5kbGVyLnggLSAxKSB7CgkJdGhpcy54ID0gdGhpcy5wbGF5ZXJIYW5kbGVyLngKCX0KCXRoaXMueSArPSAodGhpcy5wbGF5ZXJIYW5kbGVyLnkgLSB0aGlzLnkpICogMC4wNTsKCWlmICh0aGlzLnkgPCB0aGlzLnBsYXllckhhbmRsZXIueSArIDEgJiYgdGhpcy55ID4gdGhpcy5wbGF5ZXJIYW5kbGVyLnkgLSAxKSB7CgkJdGhpcy55ID0gdGhpcy5wbGF5ZXJIYW5kbGVyLnkKCX0KCWlmICh0aGlzLnggPCB0aGlzLmNhbnZhcy53aWR0aCAqIDAuNSkgewoJCXRoaXMueCA9IHRoaXMuY2FudmFzLndpZHRoICogMC41Cgl9IGVsc2UgaWYgKHRoaXMueCA+IHRoaXMubGV2ZWxXaWR0aCAtIHRoaXMuY2FudmFzLndpZHRoICogMC41KSB7CgkJdGhpcy54ID0gdGhpcy5sZXZlbFdpZHRoIC0gdGhpcy5jYW52YXMud2lkdGggKiAwLjUKCX0KCWlmICh0aGlzLnkgPCB0aGlzLmNhbnZhcy5oZWlnaHQgKiAwLjUpIHsKCQl0aGlzLnkgPSB0aGlzLmNhbnZhcy5oZWlnaHQgKiAwLjUKCX0gZWxzZSBpZiAodGhpcy55ID4gdGhpcy5sZXZlbEhlaWdodCAtIHRoaXMuY2FudmFzLmhlaWdodCAqIDAuNSkgewoJCXRoaXMueSA9IHRoaXMubGV2ZWxIZWlnaHQgLSB0aGlzLmNhbnZhcy5oZWlnaHQgKiAwLjUKCX0KfTsKCmZ1bmN0aW9uIFdhbGxIYW5kbGVyKG1haW4pIHsKCXRoaXMuc3BlZWQgPSAwOwoJdGhpcy5saXN0ID0gW107Cgl0aGlzLnBvb2wgPSBbXQp9CldhbGxIYW5kbGVyLnByb3RvdHlwZS5pbml0ID0gZnVuY3Rpb24obWFpbikgewoJdGhpcy5saXN0Lmxlbmd0aCA9IDA7Cgl0aGlzLnBsYXllckhhbmRsZXIgPSBtYWluLnBsYXllckhhbmRsZXI7Cgl0aGlzLnBsYXllclNob3RIYW5kbGVyID0gbWFpbi5wbGF5ZXJTaG90SGFuZGxlcjsKCXRoaXMucGlja3VwSGFuZGxlciA9IG1haW4ucGlja3VwSGFuZGxlcgp9OwpXYWxsSGFuZGxlci5wcm90b3R5cGUuZW50ZXJGcmFtZSA9IGZ1bmN0aW9uKCkgewoJdmFyIHBsYXllciA9IHRoaXMucGxheWVySGFuZGxlcjsKCXZhciBpLCBqLCB3YWxsLCBzaG90LCBkaXN0LCBkaXN0MiwgdlgsIHZZOwoJZm9yIChpID0gdGhpcy5saXN0Lmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7CgkJd2FsbCA9IHRoaXMubGlzdFtpXTsKCQl3YWxsLmRlbGF5LS07CgkJaWYgKHdhbGwuZGVsYXkgPD0gMCkgewoJCQl2WCA9IHBsYXllci54IC0gd2FsbC54OwoJCQl2WSA9IHBsYXllci55IC0gd2FsbC55OwoJCQlkaXN0MiA9IHZYICogdlggKyB2WSAqIHZZOwoJCQlpZiAoZGlzdDIgPCAxNDQpIHsKCQkJCWRpc3QgPSA4CgkJCX0gZWxzZSBpZiAoZGlzdDIgPCA1NzYpIHsKCQkJCWRpc3QgPSAxNgoJCQl9IGVsc2UgaWYgKGRpc3QyIDwgMjMwNCkgewoJCQkJZGlzdCA9IDMyCgkJCX0gZWxzZSBpZiAoZGlzdDIgPCA5MjE2KSB7CgkJCQlkaXN0ID0gNjQKCQkJfSBlbHNlIGlmIChkaXN0MiA8IDM2ODY0KSB7CgkJCQlkaXN0ID0gMTI4CgkJCX0gZWxzZSBpZiAoZGlzdDIgPCAxNDc0NTYpIHsKCQkJCWRpc3QgPSAyNTYKCQkJfSBlbHNlIGlmIChkaXN0MiA8IDU4OTgyNCkgewoJCQkJZGlzdCA9IDUxMgoJCQl9IGVsc2UgaWYgKGRpc3QyIDwgMjM1OTI5NikgewoJCQkJZGlzdCA9IDEwMjQKCQkJfSBlbHNlIHsKCQkJCWRpc3QgPSAyMDQ4CgkJCX0KCQkJZGlzdCA9IDAuNSAqIChkaXN0MiAvIGRpc3QgKyBkaXN0KTsKCQkJZGlzdCA9IDAuNSAqIChkaXN0MiAvIGRpc3QgKyBkaXN0KTsKCQkJaWYgKGRpc3QgLSBwbGF5ZXIucmFkaXVzIC0gd2FsbC5yYWRpdXMgPiAzNTApIHsKCQkJCXdhbGwuZGVsYXkgPSBNYXRoLmZsb29yKChkaXN0IC0gcGxheWVyLnJhZGl1cyAtIHdhbGwucmFkaXVzIC0gMzUwKSAvIHBsYXllci5zcGVlZCkKCQkJfQoJCQlpZiAoZGlzdCAtIHBsYXllci5yYWRpdXMgLSB3YWxsLnJhZGl1cyA8PSAwKSB7CgkJCQlwbGF5ZXIudlggPSB2WCAqIDAuMDY7CgkJCQlwbGF5ZXIudlkgPSB2WSAqIDAuMDYKCQkJfQoJCQlpZiAoZGlzdCAtIHBsYXllci5yYWRpdXMgLSB3YWxsLnJhZGl1cyA8PSAzNTApIHsKCQkJCWZvciAoaiA9IHRoaXMucGxheWVyU2hvdEhhbmRsZXIubGlzdC5sZW5ndGggLSAxOyBqID49IDA7IGotLSkgewoJCQkJCXNob3QgPSB0aGlzLnBsYXllclNob3RIYW5kbGVyLmxpc3Rbal07CgkJCQkJZGlzdDIgPSAoc2hvdC54IC0gd2FsbC54KSAqIChzaG90LnggLSB3YWxsLngpICsgKHNob3QueSAtIHdhbGwueSkgKiAoc2hvdC55IC0gd2FsbC55KTsKCQkJCQlpZiAoZGlzdDIgPCAxNDQpIHsKCQkJCQkJZGlzdCA9IDgKCQkJCQl9IGVsc2UgaWYgKGRpc3QyIDwgNTc2KSB7CgkJCQkJCWRpc3QgPSAxNgoJCQkJCX0gZWxzZSBpZiAoZGlzdDIgPCAyMzA0KSB7CgkJCQkJCWRpc3QgPSAzMgoJCQkJCX0gZWxzZSBpZiAoZGlzdDIgPCA5MjE2KSB7CgkJCQkJCWRpc3QgPSA2NAoJCQkJCX0gZWxzZSBpZiAoZGlzdDIgPCAzNjg2NCkgewoJCQkJCQlkaXN0ID0gMTI4CgkJCQkJfSBlbHNlIGlmIChkaXN0MiA8IDE0NzQ1NikgewoJCQkJCQlkaXN0ID0gMjU2CgkJCQkJfSBlbHNlIGlmIChkaXN0MiA8IDU4OTgyNCkgewoJCQkJCQlkaXN0ID0gNTEyCgkJCQkJfSBlbHNlIGlmIChkaXN0MiA8IDIzNTkyOTYpIHsKCQkJCQkJZGlzdCA9IDEwMjQKCQkJCQl9IGVsc2UgewoJCQkJCQlkaXN0ID0gMjA0OAoJCQkJCX0KCQkJCQlkaXN0ID0gMC41ICogKGRpc3QyIC8gZGlzdCArIGRpc3QpOwoJCQkJCWRpc3QgPSAwLjUgKiAoZGlzdDIgLyBkaXN0ICsgZGlzdCkgLSBzaG90LnJhZGl1cyAtIHdhbGwucmFkaXVzOwoJCQkJCWlmIChkaXN0IDw9IDApIHsKCQkJCQkJdGhpcy5wbGF5ZXJTaG90SGFuZGxlci5oaXQoaik7CgkJCQkJCXRoaXMuZGFtYWdlKGksIHBsYXllci5kYW1hZ2UpOwoJCQkJCX0KCQkJCX0KCQkJfQoJCX0KCX0KfTsKV2FsbEhhbmRsZXIucHJvdG90eXBlLmNyZWF0ZSA9IGZ1bmN0aW9uKHgsIHksIGxldmVsLCByYWRpdXMpIHsKCXZhciB3YWxsID0gdGhpcy5wb29sLmxlbmd0aCA+IDAgPyB0aGlzLnBvb2wucG9wKCkgOiBuZXcgT2JqZWN0KCk7Cgl3YWxsLnggPSB4OwoJd2FsbC55ID0geTsKCXdhbGwuZGVsYXkgPSBNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAzMCk7Cgl3YWxsLnJhZGl1cyA9IHR5cGVvZiByYWRpdXMgPT09ICd1bmRlZmluZWQnID8gOSA6IHJhZGl1czsKCXdhbGwuaHAgPSAyNSArIGxldmVsICogNDU7Cgl0aGlzLmxpc3QucHVzaCh3YWxsKQp9OwpXYWxsSGFuZGxlci5wcm90b3R5cGUuY2xlYXJSYWRpdXMgPSBmdW5jdGlvbih4LCB5LCByYWRpdXMpIHsKCXZhciBpLCB3YWxsLCBkaXN0OwoJZm9yIChpID0gdGhpcy5saXN0Lmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7CgkJd2FsbCA9IHRoaXMubGlzdFtpXTsKCQlkaXN0ID0gTWF0aC5zcXJ0KCh4IC0gd2FsbC54KSAqICh4IC0gd2FsbC54KSArICh5IC0gd2FsbC55KSAqICh5IC0gd2FsbC55KSk7CgkJaWYgKGRpc3QgPD0gcmFkaXVzKSB7CgkJCXRoaXMubGlzdC5zcGxpY2UoaSwgMSkKCQl9Cgl9Cn07CldhbGxIYW5kbGVyLnByb3RvdHlwZS5kYW1hZ2UgPSBmdW5jdGlvbihpLCBkbWcpIHsKCXRoaXMubGlzdFtpXS5ocCAtPSBkbWc7CglpZiAodGhpcy5saXN0W2ldLmhwIDw9IDApIHsKCQl2YXIgd2FsbCA9IHRoaXMubGlzdFtpXTsKCQlpZiAoTWF0aC5yYW5kb20oKSA8IDAuMDEpIHsKCQkJdGhpcy5waWNrdXBIYW5kbGVyLmNyZWF0ZSh3YWxsLngsIHdhbGwueSkKCQl9CgkJZm9yICh2YXIgaiA9IDA7IGogPCAxMDsgaisrKSB7CgkJfQoJCXRoaXMucG9vbC5wdXNoKHdhbGwpOwoJCXRoaXMubGlzdC5zcGxpY2UoaSwgMSkKCX0KfTsKd2luZG93Lm9ubG9hZCA9IGZ1bmN0aW9uKCkgewoJbmV3IE1haW4oKQp9Owo8L3NjcmlwdD4KPC9ib2R5PjwvaHRtbD4="},"asBuffer":null},"loaded":true}}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
<!DOCTYPE html><html lang="en"><style type="text/css">body{margin:0;padding:20px;background:#E1E1E1}</style><head><title>Assault Man</title><meta charset="utf-8"></head><body><canvas id="canvas" width="600" height="500" style="display:block;margin:auto;background:#F2F2F2;box-shadow:0 2px 3px rgba(0,0,0,0.1);-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none"></canvas><script>
  function ControlHandler(main) {
	this.a = false;
	this.d = false;
	this.w = false;
	this.s = false;
	this.m = false;
  this.space = false;
	this.tab = false;
	this.mouseLeft = false;
	this.mouseX = 0;
	this.mouseY = 0;
	this.main = main;
	this.canvas = main.canvas;
	window.addEventListener('keydown', this.keyDownEvent.bind(this));
	window.addEventListener('keyup', this.keyUpEvent.bind(this));
	this.canvas.addEventListener('mousedown', this.mouseDownEvent.bind(this));
	this.canvas.addEventListener('mouseup', this.mouseUpEvent.bind(this));
	this.canvas.addEventListener('mousemove', this.mouseMoveEvent.bind(this));
	this.canvas.addEventListener('contextmenu', this.contextMenuEvent.bind(this))
}
ControlHandler.prototype.init = function(main) {};
ControlHandler.prototype.enterFrame = function() {};
ControlHandler.prototype.keyDownEvent = function(e) {
	if (e.keyCode == 87) {
		this.w = true
	} else if (e.keyCode == 83) {
		this.s = true
	} else if (e.keyCode == 65) {
		this.a = true
	} else if (e.keyCode == 68) {
		this.d = true
	} else if (e.keyCode == 77) {
		this.m = true
  } else if (e.keyCode == 32) {
		this.space = true
	} else if (e.keyCode == 9) {
		this.tab = true;
		e.preventDefault()
	}
};
ControlHandler.prototype.keyUpEvent = function(e) {
	if (e.keyCode == 87 || e.keyCode == 38) {
		this.w = false
	} else if (e.keyCode == 83) {
		this.s = false
	} else if (e.keyCode == 65) {
		this.a = false
	} else if (e.keyCode == 68) {
		this.d = false
	} else if (e.keyCode == 77) {
		this.m = false
  } else if (e.keyCode == 32) {
		this.space = false
	} else if (e.keyCode == 9) {
		this.tab = false;
		e.preventDefault()
	}
};
ControlHandler.prototype.mouseDownEvent = function(e) {
	if (e.button == 0) {
		this.mouseLeft = true
	}
};
ControlHandler.prototype.mouseUpEvent = function(e) {
	if (this.mouseLeft) {
		if (this.main.state == 'menuScreen' || this.main.state == 'gameOverScreen') {
			this.main.startGame()
		}
	}
	if (e.button == 0) {
		this.mouseLeft = false
	}
};
ControlHandler.prototype.mouseMoveEvent = function(e) {
	var rect = this.canvas.getBoundingClientRect();
	this.mouseX = e.clientX - rect.left;
	this.mouseY = e.clientY - rect.top
};
ControlHandler.prototype.contextMenuEvent = function(e) {
	e.preventDefault()
};

function CreateLevel(main) {
	var levelWidth = main.levelWidth;
	var levelHeight = main.levelHeight;
	var i, x, y;
	for (i = 0; i < 1000; i++) {
		x = Math.random() * (levelWidth - 20) + 10;
		y = Math.random() * (levelHeight - 40) + 30;
		main.wallHandler.create(x, y, 0, Math.random() * 10 + 8)
	}
	for (i = 0; i < 35; i++) {
		x = Math.random() * (levelWidth - 20) + 10;
		y = Math.random() * (levelHeight - 40) + 30;
		main.pickupHandler.create(x, y)
	}
	for (i = 0; i < 7; i++) {
		x = Math.random() * (levelWidth - 200) + 100;
		y = Math.random() * (levelHeight - 220) + 120;
		main.baseHandler.create(x, y, 0)
	}
	for (i = 0; i < 6; i++) {
		x = Math.random() * (levelWidth - 200) + 100;
		y = Math.random() * (levelHeight - 220) + 120;
		main.baseHandler.create(x, y, 1)
	}
	for (i = 0; i < 5; i++) {
		x = Math.random() * (levelWidth - 200) + 100;
		y = Math.random() * (levelHeight - 220) + 120;
		main.baseHandler.create(x, y, 2)
	}
	for (i = 0; i < 3; i++) {
		x = Math.random() * (levelWidth - 200) + 100;
		y = Math.random() * (levelHeight - 220) + 120;
		main.baseHandler.create(x, y, 3)
	}
	for (i = 0; i < 2; i++) {
		x = Math.random() * (levelWidth - 200) + 100;
		y = Math.random() * (levelHeight - 220) + 120;
		main.baseHandler.create(x, y, 4)
	}
	x = Math.random() * (levelWidth - 200) + 100;
	y = Math.random() * (levelHeight - 220) + 120;
	main.baseHandler.create(x, y, 5)
}



function EnemyHandler(main) {
	this.speed = 0.9;
	this.spawnMax = 300;
	this.shotSpeed = 3.0;
	this.list = [];
	this.pool = []
}
EnemyHandler.prototype.init = function(main) {
	this.list.length = 0;
	this.playerHandler = main.playerHandler;
	this.playerShotHandler = main.playerShotHandler;
	this.enemyShotHandler = main.enemyShotHandler;
	this.pickupHandler = main.pickupHandler;
	this.levelWidth = main.levelWidth;
	this.levelHeight = main.levelHeight
};
EnemyHandler.prototype.enterFrame = function() {
	var player = this.playerHandler;
	var i, j, enemy, shot, dist, dist2, vX, vY;
	for (i = this.list.length - 1; i >= 0; i--) {
		enemy = this.list[i];
		enemy.reload--;
		enemy.delay--;
		if (enemy.delay <= 0) {
			vX = player.x - enemy.x;
			vY = player.y - enemy.y;
			dist2 = vX * vX + vY * vY;
			if (dist2 < 144) {
				dist = 8
			} else if (dist2 < 576) {
				dist = 16
			} else if (dist2 < 2304) {
				dist = 32
			} else if (dist2 < 9216) {
				dist = 64
			} else if (dist2 < 36864) {
				dist = 128
			} else if (dist2 < 147456) {
				dist = 256
			} else if (dist2 < 589824) {
				dist = 512
			} else if (dist2 < 2359296) {
				dist = 1024
			} else {
				dist = 2048
			}
			dist = 0.5 * (dist2 / dist + dist);
			dist = 0.5 * (dist2 / dist + dist);
			if (dist - player.radius - enemy.radius > Math.max(200 + enemy.level * 50, 350)) {
				enemy.delay = Math.floor((dist - player.radius - enemy.radius - Math.max(200 + enemy.level * 50, 350)) / (player.speed + this.speed))
			}
			if (dist - player.radius - enemy.radius <= 0) {
				player.vX = vX * 0.06;
				player.vY = vY * 0.06
			}
			if (dist - player.radius - enemy.radius <= 200 + enemy.level * 50) {
				if (enemy.reload <= 0) {
					this.enemyShotHandler.create(enemy.x, enemy.y, vX / dist * this.shotSpeed + Math.random() * 4 - 2, vY / dist * this.shotSpeed + Math.random() * 4 - 2, enemy.shotRadius, enemy.shotDamage);
					enemy.reload = enemy.reloadRate
				}
				vX = vX / dist * this.speed;
				vY = vY / dist * this.speed
			} else {
				vX = 0;
				vY = 0
			}
			if (dist - player.radius - enemy.radius <= 350) {
				for (j = this.playerShotHandler.list.length - 1; j >= 0; j--) {
					shot = this.playerShotHandler.list[j];
					dist2 = (shot.x - enemy.x) * (shot.x - enemy.x) + (shot.y - enemy.y) * (shot.y - enemy.y);
					if (dist2 < 144) {
						dist = 8
					} else if (dist2 < 576) {
						dist = 16
					} else if (dist2 < 2304) {
						dist = 32
					} else if (dist2 < 9216) {
						dist = 64
					} else if (dist2 < 36864) {
						dist = 128
					} else if (dist2 < 147456) {
						dist = 256
					} else if (dist2 < 589824) {
						dist = 512
					} else if (dist2 < 2359296) {
						dist = 1024
					} else {
						dist = 2048
					}
					dist = 0.5 * (dist2 / dist + dist);
					dist = 0.5 * (dist2 / dist + dist) - shot.radius - enemy.radius;
					if (dist <= 0) {
						this.playerShotHandler.hit(j);
						this.damage(i, player.damage);
					}
				}
			}
		} else {
			vX = 0;
			vY = 0
		}
		enemy.vX = (enemy.vX * 19 + vX) * 0.05;
		enemy.vY = (enemy.vY * 19 + vY) * 0.05;
		enemy.vX += Math.random() * 0.2 - 0.1;
		enemy.vY += Math.random() * 0.2 - 0.1;
		enemy.x += enemy.vX;
		enemy.y += enemy.vY;
		if (enemy.x < enemy.radius) {
			enemy.x = enemy.radius;
			enemy.vX *= -1
		} else if (enemy.x > this.levelWidth - enemy.radius) {
			enemy.x = this.levelWidth - enemy.radius;
			enemy.vX *= -1
		}
		if (enemy.y < 20 + enemy.radius) {
			enemy.y = 20 + enemy.radius;
			enemy.vY *= -1
		} else if (enemy.y > this.levelHeight - enemy.radius) {
			enemy.y = this.levelHeight - enemy.radius;
			enemy.vY *= -1
		}
	}
};
EnemyHandler.prototype.create = function(x, y, level) {
	if (this.list.length >= this.spawnMax) {
		return
	}
  player = this.playerHandler;
  player.eleft++
	var enemy = this.pool.length > 0 ? this.pool.pop() : new Object();
	enemy.x = x;
	enemy.y = y;
	enemy.vX = 0;
	enemy.vY = 0;
	enemy.level = level;
	enemy.reload = 0;
	enemy.delay = 5;
	enemy.radius = 8 + level * 0.6;
	enemy.hp = 4 + level * 5;
	enemy.reloadRate = 27 - level * 3 + Math.random() * 10;
	enemy.shotRadius = 3;
	enemy.shotDamage = 1 + level;
	this.list.push(enemy)
};
EnemyHandler.prototype.damage = function(i, dmg) {
	this.list[i].hp -= dmg;
	if (this.list[i].hp <= 0) {
		enemy = this.list[i];
		this.playerHandler.kills++;
    this.playerHandler.eleft--
		if (Math.random() < 0.05) {
			this.pickupHandler.create(enemy.x, enemy.y)
		}
		this.pool.push(enemy);
		this.list.splice(i, 1)
	}
};

function EnemyShotHandler(main) {
	this.list = [];
	this.pool = []
}
EnemyShotHandler.prototype.init = function(main) {
	this.list.length = 0;
	this.playerHandler = main.playerHandler;
	this.speed = main.enemyHandler.shotSpeed
};
EnemyShotHandler.prototype.enterFrame = function() {
	var player = this.playerHandler;
	var shot, i, j, k, closest, dist, dist2;
	for (i = this.list.length - 1; i >= 0; i--) {
		shot = this.list[i];
		shot.x += shot.vX;
		shot.y += shot.vY;
		shot.delay--;
		if (shot.delay <= 0) {
			dist2 = (player.x - shot.x) * (player.x - shot.x) + (player.y - shot.y) * (player.y - shot.y);
			if (dist2 < 144) {
				dist = 8
			} else if (dist2 < 576) {
				dist = 16
			} else if (dist2 < 2304) {
				dist = 32
			} else if (dist2 < 9216) {
				dist = 64
			} else if (dist2 < 36864) {
				dist = 128
			} else if (dist2 < 147456) {
				dist = 256
			} else if (dist2 < 589824) {
				dist = 512
			} else if (dist2 < 2359296) {
				dist = 1024
			} else if (dist2 < 9437184) {
				dist = 2048
			} else {
				dist = 5096
			}
			dist = 0.5 * (dist2 / dist + dist);
			dist = 0.5 * (dist2 / dist + dist) - player.radius - shot.radius;
			if (dist <= 0) {
				player.hp -= shot.damage;
				if (player.hp < 0) {
					player.hp = 0
				}
				shot.radius = 0
			}
			shot.delay = dist / (player.speed + this.speed)
		}
		shot.radius -= 0.03;
		if (shot.radius <= 1) {
			this.pool.push(shot);
			this.list.splice(i, 1);
			continue
		}
	}
};
EnemyShotHandler.prototype.create = function(x, y, vX, vY, radius, damage) {
	var shot = this.pool.length > 0 ? this.pool.pop() : new Object();
	shot.x = x;
	shot.y = y;
	shot.vX = vX;
	shot.vY = vY;
	shot.delay = 0;
	shot.radius = radius;
	shot.damage = damage;
	this.list.push(shot)
};

function Bases() {
	this.levels = [{
		radius: 130,
		walls: [
			[60, 4, 0.7854]
		],
		turrets: [
			[60, 2, 0]
		]
	}, {
		radius: 140,
		walls: [
			[80, 8, 0.3927],
			[110, 4, 0.7854]
		],
		turrets: [
			[80, 4, 0.7854]
		]
	}, {
		radius: 210,
		walls: [
			[60, 8, 0.3927],
			[130, 16, 0]
		],
		turrets: [
			[100, 8, 0]
		]
	}, {
		radius: 240,
		walls: [
			[65, 8, 0.3927],
			[130, 16, 0]
		],
		turrets: [
			[75, 8, 0],
			[146, 8, 1.37445]
		]
	}, {
		radius: 270,
		walls: [
			[130, 16, 0],
			[175, 32, 0]
		],
		turrets: [
			[75, 8, 0],
			[100, 8, 1.1781],
			[146, 8, 1.37445]
		]
	}, {
		radius: 340,
		walls: [
			[80, 32, 0],
			[100, 8, 1.1781],
			[200, 16, 0.58905],
			[205, 16, 0.294525],
			[225, 64, 0]
		],
		turrets: [
			[70, 16, 0],
			[140, 8, 0],
			[170, 16, 0.58905],
			[185, 8, 0]
		]
	}]
}

function BaseHandler(main) {
	this.speed = 0;
	this.shotSpeed = 2.5;
	this.levels = new Bases().levels;
	this.list = [];
	this.pool = []
}
BaseHandler.prototype.init = function(main) {
	this.list.length = 0;
	this.main = main;
	this.playerHandler = main.playerHandler;
	this.playerShotHandler = main.playerShotHandler;
	this.wallHandler = main.wallHandler;
	this.turretHandler = main.turretHandler;
	this.enemyHandler = main.enemyHandler;
	this.enemyShotHandler = main.enemyShotHandler;
	this.pickupHandler = main.pickupHandler
};
BaseHandler.prototype.enterFrame = function() {
	var player = this.playerHandler;
	var i, base, dist, vX, vY;
	for (i = this.list.length - 1; i >= 0; i--) {
		base = this.list[i];
		if (Math.random() < base.spawnRate) {
			this.enemyHandler.create(base.x, base.y, base.level)
		}
		base.reload--;
		base.delay--;
		if (base.delay <= 0) {
			vX = player.x - base.x;
			vY = player.y - base.y;
			dist2 = vX * vX + vY * vY;
			if (dist2 < 144) {
				dist = 8
			} else if (dist2 < 576) {
				dist = 16
			} else if (dist2 < 2304) {
				dist = 32
			} else if (dist2 < 9216) {
				dist = 64
			} else if (dist2 < 36864) {
				dist = 128
			} else if (dist2 < 147456) {
				dist = 256
			} else if (dist2 < 589824) {
				dist = 512
			} else if (dist2 < 2359296) {
				dist = 1024
			} else {
				dist = 2048
			}
			dist = 0.5 * (dist2 / dist + dist);
			dist = 0.5 * (dist2 / dist + dist);
			if (dist - player.radius - base.radius > 350 + base.level * 50) {
				base.delay = Math.floor((dist - player.radius - base.radius - (350 + base.level * 50)) / player.speed)
			}
			if (dist - player.radius - base.radius <= 350 + base.level * 50) {
				if (base.reload <= 0) {
					this.enemyShotHandler.create(base.x, base.y, vX / dist * this.shotSpeed + Math.random() * 4 - 2, vY / dist * this.shotSpeed + Math.random() * 4 - 2, base.shotRadius, base.shotDamage);
					base.reload = base.reloadRate
				}
			}
			if (dist - player.radius - base.radius <= 0) {
				player.vX = vX * 0.06;
				player.vY = vY * 0.06
			}
			if (dist - player.radius - base.radius <= 350) {
				for (j = this.playerShotHandler.list.length - 1; j >= 0; j--) {
					shot = this.playerShotHandler.list[j];
					dist2 = (shot.x - base.x) * (shot.x - base.x) + (shot.y - base.y) * (shot.y - base.y);
					if (dist2 < 144) {
						dist = 8
					} else if (dist2 < 576) {
						dist = 16
					} else if (dist2 < 2304) {
						dist = 32
					} else if (dist2 < 9216) {
						dist = 64
					} else if (dist2 < 36864) {
						dist = 128
					} else if (dist2 < 147456) {
						dist = 256
					} else if (dist2 < 589824) {
						dist = 512
					} else if (dist2 < 2359296) {
						dist = 1024
					} else {
						dist = 2048
					}
					dist = 0.5 * (dist2 / dist + dist);
					dist = 0.5 * (dist2 / dist + dist) - shot.radius - base.radius;
					if (dist <= 0) {
						this.playerShotHandler.hit(j);
						this.damage(i, player.damage);
					}
				}
			}
		}
	}
};
BaseHandler.prototype.create = function(x, y, level) {
	var base = this.pool.length > 0 ? this.pool.pop() : new Object();
	base.x = x;
	base.y = y;
	base.level = level;
	base.reload = 0;
	base.delay = Math.ceil(Math.random() * 60);
	base.radius = 15 + level * 10;
	base.hp = 40 + level * 155;
	base.spawnRate = 0.002 + level * 0.003;
	base.reloadRate = 25 - level * 2;
	base.shotRadius = 5 + level;
	base.shotDamage = 4 + level * 2;
	this.addTurretsAndWalls(x, y, level);
	this.list.push(base)
};
BaseHandler.prototype.addTurretsAndWalls = function(x, y, level) {
	var base = this.levels[level];
	var radius, count, interval, start, i, j, X, Y;
	this.wallHandler.clearRadius(x, y, base.radius);
	for (i = 0; i < base.walls.length; i++) {
		radius = base.walls[i][0];
		count = base.walls[i][1];
		start = base.walls[i][2];
		interval = 6.2832 / count;
		for (j = 0; j < count; j++) {
			X = Math.cos(start + interval * j) * radius;
			Y = Math.sin(start + interval * j) * radius;
			this.wallHandler.create(x + X, y + Y, level)
		}
	}
	for (i = 0; i < base.turrets.length; i++) {
		radius = base.turrets[i][0];
		count = base.turrets[i][1];
		start = base.turrets[i][2];
		interval = 6.2832 / count;
		for (j = 0; j < count; j++) {
			X = Math.cos(start + interval * j) * radius;
			Y = Math.sin(start + interval * j) * radius;
			this.turretHandler.create(x + X, y + Y, level)
		}
	}
};
BaseHandler.prototype.damage = function(i, dmg) {
	this.list[i].hp -= dmg;
	if (this.list[i].hp <= 0) {
		var base = this.list[i];
		this.playerHandler.kills++;
		for (var j = 0; j < 1 + base.level * 3; j++) {
			this.pickupHandler.create(base.x + Math.random() * 10 - 5, base.y + Math.random() * 10 - 5)
		}
		var blast = base.level + 8;
		this.pool.push(base);
    var temp1 = this.list[i]
    for (var j = 0; j < 100; j++) {
			this.playerShotHandler.create(this.playerHandler.x, this.playerHandler.y, Math.random() * 2 - 1, Math.random() * 2 - 1)
		}
		this.list.splice(i, 1)
	}
};

function GameOverScreen(main) {
	main.state = 'gameOverScreen';
	main.controlHandler.mouseLeft = false;
	main.context.fillStyle = 'rgba(255,255,255,0.8)';
	main.context.fillRect(0, 20, main.canvas.width, main.canvas.height - 20);
	var hW = main.canvas.width * 0.5;
	var hH = main.canvas.height * 0.5;
	var dark = 'rgba(0,0,0,0.9)';
	var medium = 'rgba(0,0,0,0.5)';
	var light = 'rgba(0,0,0,0.3)';
	new Text(main.context, 'Game Over', hW, hH - 20, 'normal 21px/1 ' + main.fontFamily, dark);
	new Text(main.context, 'Click to Play Again', hW, hH + 20, 'normal 17px/1 ' + main.fontFamily, dark);
}

function Main() {
	this.fontFamily = '"Segoe UI",Arial,sans-serif';
	this.handlers = ['control', 'enemy', 'wall', 'turret', 'base', 'player', 'playerShot', 'enemyShot', 'view', 'pickup', 'render'];
	this.levelWidth = 6000;
	this.levelHeight = 6000;
	this.state = 'loading';
	this.canvas = document.getElementById('canvas');
	this.context = this.canvas.getContext('2d');
	this.processTime = new ProcessTime();
	this.processCount = 0;
	for (var i = 0; i < this.handlers.length; i++) {
		var name = this.handlers[i] + 'Handler';
		this[name] = new window[name.charAt(0).toUpperCase() + name.slice(1)](this)
	}
	setInterval(this.enterFrame.bind(this), 16.6667);
	new MenuScreen(this)
}
Main.prototype.startGame = function() {
	for (var i = 0; i < this.handlers.length; i++) {
		this[this.handlers[i] + 'Handler'].init(this)
	}
	new CreateLevel(this);
	this.state = 'game'
};
Main.prototype.enterFrame = function() {
	if (this.state != 'game') {
		return
	}
	for (var i = 0; i < this.handlers.length; i++) {
		this[this.handlers[i] + 'Handler'].enterFrame()
	}
	if (this.playerHandler.hp <= 0) {
		new GameOverScreen(this)
	}
};

function MenuScreen(main) {
	main.state = 'menuScreen';
	main.controlHandler.mouseLeft = false;
	main.context.clearRect(0, 0, main.canvas.width, main.canvas.height);
	var hW = main.canvas.width * 0.5;
	var hH = main.canvas.height * 0.5;
	var dark = 'rgba(0,0,0,0.9)';
	var medium = 'rgba(0,0,0,0.5)';
	var light = 'rgba(0,0,0,0.3)';

	new Text(main.context, 'Click to Start', hW, hH - 50, 'normal 17px/1 ' + main.fontFamily, dark);
	new Text(main.context, 'Use "WASD" to move and "Left Click" to shoot.', hW, hH - 20, 'normal 15px/1 ' + main.fontFamily, medium);
	new Text(main.context, '"Tab" or "M" shows the minimap. Larger dots are harder bases.', hW, hH, 'normal 15px/1 ' + main.fontFamily, medium);
	new Text(main.context, 'Enemies and bases drop blue orbs, which increase your power.', hW, hH + 20, 'normal 15px/1 ' + main.fontFamily, medium);
}

function Object() {}

function PickupHandler(main) {
	this.radius = 7;
	this.damage = 0.4;
	this.reloadRate = 0.95;
	this.hp = 3;
	this.list = [];
	this.pool = []
}
PickupHandler.prototype.init = function(main) {
	this.list.length = 0;
	this.playerHandler = main.playerHandler;
	this.playerShotHandler = main.playerShotHandler
};
PickupHandler.prototype.enterFrame = function() {
	var player = this.playerHandler;
	var dist;
	for (var i = this.list.length - 1; i >= 0; i--) {
		var pickup = this.list[i];
		pickup.delay--;
		if (pickup.delay <= 0) {
			dist = Math.sqrt((player.x - pickup.x) * (player.x - pickup.x) + (player.y - pickup.y) * (player.y - pickup.y)) - player.radius - pickup.radius;
			if (dist <= 0) {
				player.maxHp += Math.ceil(Math.random() * 10) + 7;
				player.hp += 5;
				player.damage += Math.random() * 0.03 + 0.03;
				if (player.reloadRate > 3.0) {
					player.reloadRate *= 0.99
				}
				for (var j = 0; j < 9; j++) {
					this.playerShotHandler.create(pickup.x, pickup.y, Math.random() * 2 - 1, Math.random() * 2 - 1)
				}
				this.pool.push(pickup);
				this.list.splice(i, 1)
			} else if (dist <= 40) {
				pickup.x += (player.x - pickup.x) * (160 - dist * 4) * 0.001;
				pickup.y += (player.y - pickup.y) * (160 - dist * 4) * 0.001
			}
			pickup.delay = (dist - 40) / player.speed
		}
	}
};
PickupHandler.prototype.create = function(x, y) {
	var pickup = this.pool.length > 0 ? this.pool.pop() : new Object();
	pickup.x = x;
	pickup.y = y;
	pickup.delay = 0;
	pickup.radius = this.radius;
	this.list.push(pickup)
};

function PlayerHandler(main) {
	this.radius = 12.0;
	this.accel = 0.3;
	this.speed = 2.0;
	this.startHp = 100.0;
	this.startReloadRate = 12.0;
	this.shotSpeed = 5.0;
	this.startDamage = 1.0;
	this.turretRadius = this.radius * 0.6;
	this.hp;
	this.maxHp;
  this.eleft = 0
	this.kills;
	this.damage;
	this.reloadRate;
	this.list = [this]
}
PlayerHandler.prototype.init = function(main) {
	this.canvas = main.canvas;
	this.controlHandler = main.controlHandler;
	this.viewHandler = main.viewHandler;
	this.levelWidth = main.levelWidth;
	this.levelHeight = main.levelHeight;
	this.playerShotHandler = main.playerShotHandler;
	this.processTime = main.processTime;
	this.x = main.levelWidth * 0.5;
	this.y = main.levelHeight * 0.5;
	this.vX = 0;
	this.vY = 0;
	this.hp = this.startHp;
	this.maxHp = this.startHp;
	this.kills = 0;
	this.damage = this.startDamage;
	this.reload = 0;
	this.reloadRate = this.startReloadRate;
	this.tick = false
};
PlayerHandler.prototype.enterFrame = function() {
	var obj, i, vX, vY;
	vX = this.controlHandler.a ? -this.accel : (this.controlHandler.d ? this.accel : 0);
	vY = this.controlHandler.w ? -this.accel : (this.controlHandler.s ? this.accel : 0);
	if (vX != 0 && vY != 0) {
		vX *= 0.7071;
		vY *= 0.7071
	} else if (vX == 0 && vY == 0) {
		this.vX *= 0.7;
		this.vY *= 0.7
	}
	this.vX += vX;
	this.vY += vY;
	dist = Math.sqrt(this.vX * this.vX + this.vY * this.vY);
	if (dist > this.speed) {
		dist = this.speed / dist;
		this.vX *= dist;
		this.vY *= dist
	}
	this.x += this.vX;
	this.y += this.vY;
	if (this.x < this.radius) {
		this.x = this.radius
	} else if (this.x > this.levelWidth - this.radius) {
		this.x = this.levelWidth - this.radius
	}
	if (this.y < 20 + this.radius) {
		this.y = 20 + this.radius
	} else if (this.y > this.levelHeight - this.radius) {
		this.y = this.levelHeight - this.radius
	}
	if (this.hp < this.maxHp) {
		this.hp += this.maxHp * 0.0003;
		if (this.hp > this.maxHp) {
			this.hp = this.maxHp
		}
	}
	this.reload--;
	if (this.controlHandler.mouseLeft && this.reload <= 0) {
		vX = this.controlHandler.mouseX + this.viewHandler.x - this.canvas.width * 0.5 - this.x;
		vY = this.controlHandler.mouseY + this.viewHandler.y - this.canvas.height * 0.5 - this.y;
		dist = Math.sqrt(vX * vX + vY * vY);
		vX /= dist;
		vY /= dist;
		this.tick = !this.tick;
		if (this.tick) {
			this.playerShotHandler.create(this.x + vY * this.turretRadius, this.y - vX * this.turretRadius, vX * this.shotSpeed + Math.random() * 0.6 - 0.3, vY * this.shotSpeed + Math.random() * 0.6 - 0.3)
		} else {
			this.playerShotHandler.create(this.x - vY * this.turretRadius, this.y + vX * this.turretRadius, vX * this.shotSpeed + Math.random() * 0.6 - 0.3, vY * this.shotSpeed + Math.random() * 0.6 - 0.3)
		}
		this.reload = this.reloadRate
	}
};

function PlayerShotHandler(main) {
	this.radius = 3;
	this.list = [];
	this.pool = []
}
PlayerShotHandler.prototype.init = function(main) {
	this.list.length = 0;
	this.playerHandler = main.playerHandler;
	this.speed = main.playerHandler.shotSpeed
};
PlayerShotHandler.prototype.enterFrame = function() {
	var shot, i;
	for (i = this.list.length - 1; i >= 0; i--) {
		shot = this.list[i];
		shot.x += shot.vX;
		shot.y += shot.vY;
		shot.radius -= 0.045;
		if (shot.radius <= 1) {
			this.pool.push(shot);
			this.list.splice(i, 1);
			continue
		}
	}
};
PlayerShotHandler.prototype.create = function(x, y, vX, vY) {
	var shot = this.pool.length > 0 ? this.pool.pop() : new Object();
	shot.x = x;
	shot.y = y;
	shot.vX = vX;
	shot.vY = vY;
	shot.radius = this.radius;
	this.list.push(shot)
};
PlayerShotHandler.prototype.hit = function(i) {
	this.pool.push(this.list[i]);
	this.list.splice(i, 1)
};

function ProcessTime() {
	this.log = {}
}
ProcessTime.prototype.logTime = function(name, processTime) {
	if (name in this.log) {
		if (processTime > this.log[name]) {
			this.log[name] = processTime
		}
	} else {
		this.log[name] = processTime
	}
};
ProcessTime.prototype.outputLog = function() {
	console.clear();
	for (var name in this.log) {
		console.log(name + ' ' + (new Array(18 - name.length).join(' ')) + '   max:' + (this.log[name] > 0 ? this.log[name] : ''));
		this.log[name] = 0
	}
};

function RenderHandler(main) {
	this.mapSize = 200;
	this.mapX = this.mapSize / main.levelWidth;
	this.mapY = this.mapSize / main.levelHeight;
	this.main = main;
	this.canvas = main.canvas;
	this.context = main.context
}
RenderHandler.prototype.init = function(main) {
	this.drawList = [{
		color: 'rgba(0,255,0,0.75)',
		handler: main.playerHandler
	}, {
		color: 'rgba(0,147,169,0.8)',
		handler: main.pickupHandler
	}, {
		color: 'rgba(255,128,51,0.5)',
		handler: main.wallHandler
	}, {
		color: 'rgba(90,31,31,0.6)',
		handler: main.turretHandler
	}, {
		color: 'rgba(255,51,0,0.8)',
		handler: main.baseHandler
	}, {
		color: '#66ffff',
		handler: main.enemyHandler
	}, {
		color: 'rgba(0,0,255,0.8)',//D
		handler: main.playerShotHandler
	}, {
		color: 'rgba(255,51,204)',//D
		handler: main.enemyShotHandler
	}];
	this.baseHandler = main.baseHandler;
	this.playerHandler = main.playerHandler;
	this.controlHandler = main.controlHandler;
	this.viewHandler = main.viewHandler;
	this.bgCanvas = document.createElement('canvas');
	this.bgCanvas.width = main.levelWidth;
	this.bgCanvas.height = main.levelHeight;
	this.bgContext = this.bgCanvas.getContext('2d');
	for (var i = 0; i < 500; i++) {
		this.bgContext.fillStyle = 'rgba(0,0,0,' + (Math.random() * 0.1) + ')';
		this.bgContext.beginPath();
		this.bgContext.arc(Math.random() * main.levelWidth, Math.random() * main.levelHeight, Math.random() * 100, 0, 6.2832);
		this.bgContext.fill();
		this.bgContext.closePath()
	}
	this.bgContext.fillStyle = 'rgba(70,70,70,0.15)'
};
RenderHandler.prototype.enterFrame = function() {
	var context = this.context;
	var obj, x, y, i, j;
	var offsetX = this.canvas.width * 0.5 - this.viewHandler.x;
	var offsetY = this.canvas.height * 0.5 - this.viewHandler.y;
	context.clearRect(0, 0, this.canvas.width, this.canvas.height);
	context.drawImage(this.bgCanvas, offsetX, offsetY);
	for (i = 0; i < this.drawList.length; i++) {
		context.fillStyle = this.drawList[i].color;
		for (j = this.drawList[i].handler.list.length - 1; j >= 0; j--) {
			obj = this.drawList[i].handler.list[j];
			x = obj.x + offsetX;
			y = obj.y + offsetY;
			if (x > -obj.radius && x < this.canvas.width + obj.radius && y > -obj.radius && y < this.canvas.height + obj.radius) {
				if (i > 5) {
					context.fillRect(x - obj.radius, y - obj.radius, obj.radius * 2, obj.radius * 2);
					if (Math.random() < 0.2 && typeof this.drawList[i].paint !== 'undefined') {
						this.bgContext.fillRect(obj.x, obj.y, 2, 2)
					}
				} else {
					context.beginPath();
					context.arc(x, y, obj.radius, 0, 6.2832);
					context.fill();
					context.closePath()
				}
			}
		}
	}
	context.fillStyle = '#444444';
	context.fillRect(0, 0, this.canvas.width, 20);
	context.textAlign = 'left';
	context.font = 'bold 11px/1 Arial';
	context.fillStyle = '#AAAAAA';
	context.fillText('Health', 5, 10);
	context.fillText('Damage', 145, 10);
	context.fillText('Fire Rate', 230, 10);
	context.fillText('Kills', 345, 10);
	context.fillText('DPS', 420, 10);
  context.fillText('Drones Left', 490, 10);
	context.font = 'bold 15px/1 Arial';
	context.fillStyle = '#DDDDDD';
	context.fillText(Math.round(this.playerHandler.hp) + '/' + this.playerHandler.maxHp, 43, 10);
	context.fillText(Math.round(this.playerHandler.damage * 10) / 10, 193, 10);
	context.fillText((Math.round(60 / this.playerHandler.reloadRate * 10) / 10) + '/s', 282, 10);
	context.fillText(this.playerHandler.kills, 372, 10);
	context.fillText((Math.round(60 / this.playerHandler.reloadRate * this.playerHandler.damage * 10) / 10), 446, 10);
  context.fillText(this.playerHandler.eleft, 556, 10)
	if (this.controlHandler.tab || this.controlHandler.m) {
		context.fillStyle = 'rgba(255,255,255,0.85)';
		context.fillRect(0, 20, this.mapSize, this.mapSize);
		context.fillStyle = 'rgba(158,0,0,0.5)';
		for (i = this.baseHandler.list.length - 1; i >= 0; i--) {
			obj = this.baseHandler.list[i];
			j = 3 + obj.level * 2;
			x = Math.round(obj.x * this.mapX - j * 0.5);
			y = 20 + Math.round(obj.y * this.mapY - j * 0.5);
			context.fillRect(x, y, j, j)
		}
		context.fillStyle = 'rgba(0,0,0,0.7)';
		x = Math.round(this.playerHandler.x * this.mapX - 3);
		y = 20 + Math.round(this.playerHandler.y * this.mapY - 3);
		context.fillRect(x, y, 6, 6)
	}
};

function Text(context, text, x, y, font, style, align, baseline) {
	context.font = typeof font === 'undefined' ? 'normal 16px/1 Arial' : font;
	context.fillStyle = typeof style === 'undefined' ? '#000000' : style;
	context.textAlign = typeof align === 'undefined' ? 'center' : align;
	context.textBaseline = typeof baseline === 'undefined' ? 'middle' : baseline;
	context.fillText(text, x, y)
}

function TurretHandler(main) {
	this.speed = 0;
	this.shotSpeed = 2.5;
	this.list = [];
	this.pool = []
}
TurretHandler.prototype.init = function(main) {
	this.list.length = 0;
	this.playerHandler = main.playerHandler;
	this.playerShotHandler = main.playerShotHandler;
	this.enemyShotHandler = main.enemyShotHandler;
	this.pickupHandler = main.pickupHandler
};
TurretHandler.prototype.enterFrame = function() {
	var player = this.playerHandler;
	var i, j, turret, shot, dist, dist2, vX, vY;
	for (i = this.list.length - 1; i >= 0; i--) {
		turret = this.list[i];
		turret.reload--;
		turret.delay--;
		if (turret.delay <= 0) {
			vX = player.x - turret.x;
			vY = player.y - turret.y;
			dist2 = vX * vX + vY * vY;
			if (dist2 < 144) {
				dist = 8
			} else if (dist2 < 576) {
				dist = 16
			} else if (dist2 < 2304) {
				dist = 32
			} else if (dist2 < 9216) {
				dist = 64
			} else if (dist2 < 36864) {
				dist = 128
			} else if (dist2 < 147456) {
				dist = 256
			} else if (dist2 < 589824) {
				dist = 512
			} else if (dist2 < 2359296) {
				dist = 1024
			} else {
				dist = 2048
			}
			dist = 0.5 * (dist2 / dist + dist);
			dist = 0.5 * (dist2 / dist + dist);
			if (dist - player.radius - turret.radius > Math.max(250 + turret.level * 50, 350)) {
				turret.delay = Math.floor((dist - player.radius - turret.radius - Math.max(250 + turret.level * 50, 350)) / player.speed)
			}
			if (dist - player.radius - turret.radius <= 250 + turret.level * 50) {
				if (turret.reload <= 0) {
					this.enemyShotHandler.create(turret.x, turret.y, vX / dist * this.shotSpeed + Math.random() * 4 - 2, vY / dist * this.shotSpeed + Math.random() * 4 - 2, turret.shotRadius, turret.shotDamage);
					turret.reload = turret.reloadRate
				}
			}
			if (dist - player.radius - turret.radius <= 0) {
				player.vX = vX * 0.06;
				player.vY = vY * 0.06
			}
			if (dist - player.radius - turret.radius <= 350) {
				for (j = this.playerShotHandler.list.length - 1; j >= 0; j--) {
					shot = this.playerShotHandler.list[j];
					dist2 = (shot.x - turret.x) * (shot.x - turret.x) + (shot.y - turret.y) * (shot.y - turret.y);
					if (dist2 < 144) {
						dist = 8
					} else if (dist2 < 576) {
						dist = 16
					} else if (dist2 < 2304) {
						dist = 32
					} else if (dist2 < 9216) {
						dist = 64
					} else if (dist2 < 36864) {
						dist = 128
					} else if (dist2 < 147456) {
						dist = 256
					} else if (dist2 < 589824) {
						dist = 512
					} else if (dist2 < 2359296) {
						dist = 1024
					} else {
						dist = 2048
					}
					dist = 0.5 * (dist2 / dist + dist);
					dist = 0.5 * (dist2 / dist + dist) - shot.radius - turret.radius;
					if (dist <= 0) {
						this.playerShotHandler.hit(j);
						this.damage(i, player.damage);
					}
				}
			}
		}
	}
};
TurretHandler.prototype.create = function(x, y, level) {
	var turret = this.pool.length > 0 ? this.pool.pop() : new Object();
	turret.x = x;
	turret.y = y;
	turret.level = level;
	turret.reload = 0;
	turret.delay = Math.ceil(Math.random() * 60);
	turret.radius = Math.min(12 + level * 3, 15);
	turret.hp = 30 + level * 45;
	turret.reloadRate = 17 - level * 2 + Math.random() * 10;
	turret.shotRadius = 3.5 + level * 0.5;
	turret.shotDamage = 3 + level * 2;
	this.list.push(turret)
};
TurretHandler.prototype.damage = function(i, dmg) {
	this.list[i].hp -= dmg;
	if (this.list[i].hp <= 0) {
		var turret = this.list[i];
		this.playerHandler.kills++;
		this.pickupHandler.create(turret.x, turret.y);
		for (var j = 0; j < 30; j++) {
		}
		this.pool.push(turret);
		this.list.splice(i, 1)
	}
};

function ViewHandler(main) {
	this.x;
	this.y
}
ViewHandler.prototype.init = function(main) {
	this.x = main.levelWidth * 0.5;
	this.y = main.levelHeight * 0.5;
	this.canvas = main.canvas;
	this.playerHandler = main.playerHandler;
	this.levelWidth = main.levelWidth;
	this.levelHeight = main.levelHeight
};
ViewHandler.prototype.enterFrame = function() {
	this.x += (this.playerHandler.x - this.x) * 0.05;
	if (this.x < this.playerHandler.x + 1 && this.x > this.playerHandler.x - 1) {
		this.x = this.playerHandler.x
	}
	this.y += (this.playerHandler.y - this.y) * 0.05;
	if (this.y < this.playerHandler.y + 1 && this.y > this.playerHandler.y - 1) {
		this.y = this.playerHandler.y
	}
	if (this.x < this.canvas.width * 0.5) {
		this.x = this.canvas.width * 0.5
	} else if (this.x > this.levelWidth - this.canvas.width * 0.5) {
		this.x = this.levelWidth - this.canvas.width * 0.5
	}
	if (this.y < this.canvas.height * 0.5) {
		this.y = this.canvas.height * 0.5
	} else if (this.y > this.levelHeight - this.canvas.height * 0.5) {
		this.y = this.levelHeight - this.canvas.height * 0.5
	}
};

function WallHandler(main) {
	this.speed = 0;
	this.list = [];
	this.pool = []
}
WallHandler.prototype.init = function(main) {
	this.list.length = 0;
	this.playerHandler = main.playerHandler;
	this.playerShotHandler = main.playerShotHandler;
	this.pickupHandler = main.pickupHandler
};
WallHandler.prototype.enterFrame = function() {
	var player = this.playerHandler;
	var i, j, wall, shot, dist, dist2, vX, vY;
	for (i = this.list.length - 1; i >= 0; i--) {
		wall = this.list[i];
		wall.delay--;
		if (wall.delay <= 0) {
			vX = player.x - wall.x;
			vY = player.y - wall.y;
			dist2 = vX * vX + vY * vY;
			if (dist2 < 144) {
				dist = 8
			} else if (dist2 < 576) {
				dist = 16
			} else if (dist2 < 2304) {
				dist = 32
			} else if (dist2 < 9216) {
				dist = 64
			} else if (dist2 < 36864) {
				dist = 128
			} else if (dist2 < 147456) {
				dist = 256
			} else if (dist2 < 589824) {
				dist = 512
			} else if (dist2 < 2359296) {
				dist = 1024
			} else {
				dist = 2048
			}
			dist = 0.5 * (dist2 / dist + dist);
			dist = 0.5 * (dist2 / dist + dist);
			if (dist - player.radius - wall.radius > 350) {
				wall.delay = Math.floor((dist - player.radius - wall.radius - 350) / player.speed)
			}
			if (dist - player.radius - wall.radius <= 0) {
				player.vX = vX * 0.06;
				player.vY = vY * 0.06
			}
			if (dist - player.radius - wall.radius <= 350) {
				for (j = this.playerShotHandler.list.length - 1; j >= 0; j--) {
					shot = this.playerShotHandler.list[j];
					dist2 = (shot.x - wall.x) * (shot.x - wall.x) + (shot.y - wall.y) * (shot.y - wall.y);
					if (dist2 < 144) {
						dist = 8
					} else if (dist2 < 576) {
						dist = 16
					} else if (dist2 < 2304) {
						dist = 32
					} else if (dist2 < 9216) {
						dist = 64
					} else if (dist2 < 36864) {
						dist = 128
					} else if (dist2 < 147456) {
						dist = 256
					} else if (dist2 < 589824) {
						dist = 512
					} else if (dist2 < 2359296) {
						dist = 1024
					} else {
						dist = 2048
					}
					dist = 0.5 * (dist2 / dist + dist);
					dist = 0.5 * (dist2 / dist + dist) - shot.radius - wall.radius;
					if (dist <= 0) {
						this.playerShotHandler.hit(j);
						this.damage(i, player.damage);
					}
				}
			}
		}
	}
};
WallHandler.prototype.create = function(x, y, level, radius) {
	var wall = this.pool.length > 0 ? this.pool.pop() : new Object();
	wall.x = x;
	wall.y = y;
	wall.delay = Math.round(Math.random() * 30);
	wall.radius = typeof radius === 'undefined' ? 9 : radius;
	wall.hp = 25 + level * 45;
	this.list.push(wall)
};
WallHandler.prototype.clearRadius = function(x, y, radius) {
	var i, wall, dist;
	for (i = this.list.length - 1; i >= 0; i--) {
		wall = this.list[i];
		dist = Math.sqrt((x - wall.x) * (x - wall.x) + (y - wall.y) * (y - wall.y));
		if (dist <= radius) {
			this.list.splice(i, 1)
		}
	}
};
WallHandler.prototype.damage = function(i, dmg) {
	this.list[i].hp -= dmg;
	if (this.list[i].hp <= 0) {
		var wall = this.list[i];
		if (Math.random() < 0.01) {
			this.pickupHandler.create(wall.x, wall.y)
		}
		for (var j = 0; j < 10; j++) {
		}
		this.pool.push(wall);
		this.list.splice(i, 1)
	}
};
window.onload = function() {
	new Main()
};
</script>
</body></html>
result
console