@sammybrown/

Tower Heist

Pygame

Game Jam project

fork
loading
Files
  • main.py
  • images
  • experimental.py
  • nohup.out
  • requirements.txt
  • rooms.py

This Plugin Crashed!

Error: Error: must not create an existing file {"type":"CREATE_FILE","wid":"0.7233546877454362","path":"main.py","file":{"path":"main.py","content":{"asEncoding":{"base64":"Iy0tSU1QT1JUUy0tCmltcG9ydCBhcmNhZGUKaW1wb3J0IG9zCmltcG9ydCByYW5kb20KaW1wb3J0IHRpbWUKaW1wb3J0IG1hdGgKaW1wb3J0IHJvb21zCiMtLS0tLS0tLS0tLQojRGljdGlvbmFyeSBjb250YWluaW5nIGRpcmVjdG9yaWVzIG9mIHRpbGVzIHRoYXQgZG9uJ3QgaGF2ZSBjb2xsaXNpb24Kc3RhdGljX25vX2NvbGxpc2lvbiA9IHsiZjEiOiJpbWFnZXMvZmxvb3JzL2Zsb29yIDEucG5nIiwgImYyIjoiaW1hZ2VzL2Zsb29ycy9mbG9vciAyLnBuZyIsICJmMyI6ImltYWdlcy9mbG9vcnMvZmxvb3IgMy5wbmciLCAiZjQiOiJpbWFnZXMvZmxvb3JzL2Zsb29yIDQucG5nIiwgImY1IjoiaW1hZ2VzL2Zsb29ycy9mbG9vciA1LnBuZyJ9CiNEaWN0aW9uYXJ5IGNvbnRhaW5pbmcgZGlyZWN0b3JpZXMgb2YgdGlsZXMgdGhhdCBoYXZlIGNvbGxpc2lvbgpzdGF0aWNfY29sbGlzaW9uID0geyJ3aDEiOiJpbWFnZXMvd2FsbHMvd2FsbCBob3Jpem9udGFsIDEucG5nIiwgInd2MSI6ImltYWdlcy93YWxscy93YWxsIHZlcnRpY2FsIDEucG5nIiwgImNibDEiOiJpbWFnZXMvd2FsbHMvY29ybmVyIGJvdHRvbSBsZWZ0IDEucG5nIiwgImNicjEiOiJpbWFnZXMvd2FsbHMvY29ybmVyIGJvdHRvbSByaWdodCAxLnBuZyIsICJjdGwxIjoiaW1hZ2VzL3dhbGxzL2Nvcm5lciB0b3AgbGVmdCAxLnBuZyIsICJjdHIxIjoiaW1hZ2VzL3dhbGxzL2Nvcm5lciB0b3AgcmlnaHQgMS5wbmciLCJjMSI6ImltYWdlcy93YWxscy9jb25uZWN0b3IgMS5wbmcifQojRGljdGlvbmFyeSBjb250YWluaW5nIGRpcmVjdG9yaWVzIG9mIGV4aXRzCmV4aXRzID0geyJleDEiOiJpbWFnZXMvbWlzYy9leGl0IDEucG5nIn0KI0RpY3Rpb25hcnkgY29udGFpbmluZyBkaXJlY3RvcmllcyBvZiBlbnRyYW5jZXMKZW50cmFuY2VzID0geyJlbjEiOiJpbWFnZXMvbWlzYy9lbnRyYW5jZSAxLnBuZyJ9CiNMaXN0IG9mIHRpbGUgY29ycmVzcG9uZGluZyBzdHJpbmdzIGluIG9yZGVyIG9mIHJlbmRlciBwcmlvcml0eSwgZm9yIGV4YW1wbGUgJ3doMScgd2lsbCBiZSByZW5kZXJlZCBvbiB0b3Agb2YgdGhlIGZvbGxvd2luZyBpdGVtcwpzdGF0aWNfcmVuZGVyX3ByaW9yaXRpZXMgPSBbIndoMSIsICJ3djEiLCAiY2JsMSIsICJjYnIxIiwgImN0bDEiLCAiY3RyMSIsICJjMSIsICJmMSIsICJmMiIsICJmMyIsICJmNCIsICJmNSIsICJleDEiLCAiZW4xIiwgIiJdCiNMaXN0IGNvbnRhaW5pbmcgYWxsIHRoZSBkaXJlY3RvcmllcyBmb3IgcGxheWVyIDEgdGV4dHVyZXMsIGluIHRoZSBmb2xsb3dpbmcgb3JkZXI7CiNzdGFuZGluZyBsZWZ0IGZvbGRlciwgc3RhbmRpbmcgcmlnaHQgZm9sZGVyLCB3YWxraW5nIGxlZnQgZm9sZGVyLCB3YWxraW5nIHJpZ2h0IGZvbGRlciwgd2Fsa2luZyB1cCBmb2xkZXIsIHdhbGtpbmcgZG93biBmb2xkZXIuCiNJdCBhdXRvbWF0aWNhbGx5IGluY29ycGVyYXRlcyB0aGUgZmlsZXMgaW4gdGhlc2UgZm9sZGVycyBmb3IgcGxheWVyIDEgYW5pbWF0aW9ucy4KcGxheWVyXzFfdGV4dHVyZV9kaXJlY3RvcmllcyA9IFsiaW1hZ2VzL3BsYXllcl8xX2FuaW1zL3N0YW5kIGxlZnQgdGV4dHVyZXMiLCAiaW1hZ2VzL3BsYXllcl8xX2FuaW1zL3N0YW5kIHJpZ2h0IHRleHR1cmVzIiwgImltYWdlcy9wbGF5ZXJfMV9hbmltcy93YWxrIGxlZnQgdGV4dHVyZXMiLCAiaW1hZ2VzL3BsYXllcl8xX2FuaW1zL3dhbGsgcmlnaHQgdGV4dHVyZXMiLCAiaW1hZ2VzL3BsYXllcl8xX2FuaW1zL3dhbGsgdXAgdGV4dHVyZXMiLCAiaW1hZ2VzL3BsYXllcl8xX2FuaW1zL3dhbGsgZG93biB0ZXh0dXJlcyJdCgojTGlzdCBjb250YWluaW5nIGFsbCB0aGUgZGlyZWN0b3JpZXMgZm9yIHBsYXllciAyIHRleHR1cmVzLCBpbiB0aGUgZm9sbG93aW5nIG9yZGVyOyAKI3N0YW5kaW5nIGxlZnQgZm9sZGVyLCBzdGFuZGluZyByaWdodCBmb2xkZXIsIHdhbGtpbmcgbGVmdCBmb2xkZXIsIHdhbGtpbmcgcmlnaHQgZm9sZGVyLCB3YWxraW5nIHVwIGZvbGRlciwgd2Fsa2luZyBkb3duIGZvbGRlci4KI0l0IGF1dG9tYXRpY2FsbHkgaW5jb3JwZXJhdGVzIHRoZSBmaWxlcyBpbiB0aGVzZSBmb2xkZXJzIGZvciBwbGF5ZXIgMiBhbmltYXRpb25zCnBsYXllcl8yX3RleHR1cmVfZGlyZWN0b3JpZXMgPSBbImltYWdlcy9wbGF5ZXJfMl9hbmltcy9zdGFuZCBsZWZ0IHRleHR1cmVzIiwgImltYWdlcy9wbGF5ZXJfMl9hbmltcy9zdGFuZCByaWdodCB0ZXh0dXJlcyIsICJpbWFnZXMvcGxheWVyXzJfYW5pbXMvd2FsayBsZWZ0IHRleHR1cmVzIiwgImltYWdlcy9wbGF5ZXJfMl9hbmltcy93YWxrIHJpZ2h0IHRleHR1cmVzIiwgImltYWdlcy9wbGF5ZXJfMl9hbmltcy93YWxrIHVwIHRleHR1cmVzIiwgImltYWdlcy9wbGF5ZXJfMl9hbmltcy93YWxrIGRvd24gdGV4dHVyZXMiXQoKI0xpc3QgY29udGFpbmluZyBhbGwgdGhlIGRpcmVjdG9yaWVzIGZvciB0aGUgZ3VhcmQgdGV4dHVyZXMsIGluIHRoZSBmb2xsb3dpbmcgb3JkZXI7CiNzdGFuZGluZyBsZWZ0IGZvbGRlciwgc3RhbmRpbmcgcmlnaHQgZm9sZGVyLCB3YWxraW5nIGxlZnQgZm9sZGVyLCB3YWxraW5nIHJpZ2h0IGZvbGRlciwgd2Fsa2luZyB1cCBmb2xkZXIsIHdhbGtpbmcgZG93biBmb2xkZXIsIGFsZXJ0ZWQgc3RhbmRpbmcgbGVmdCBmb2xkZXIsIGFsZXJ0ZWQgc3RhbmRpbmcgcmlnaHQgZm9sZGVyLCBhbGVydGVkIHdhbGtpbmcgbGVmdCBmb2xkZXIsIGFsZXJ0ZWQgd2Fsa2luZyByaWdodCBmb2xkZXIsIGFsZXJ0ZWQgd2Fsa2luZyB1cCBmb2xkZXIsIGFsZXJ0ZWQgd2Fsa2luZyBkb3duIGZvbGRlci4KI0l0IGF1dG9tYXRpY2FsbHkgaW5jb3JwZXJhdGVzIHRoZSBmaWxlcyBpbiB0aGVzZSBmb2xkZXJzIGZvciB0aGUgZ3VhcmQgYW5pbWF0aW9ucwpndWFyZF90ZXh0dXJlX2RpcmVjdG9yaWVzID0gWyJpbWFnZXMvZ3VhcmQvd2FsayBsZWZ0IHRleHR1cmVzIiwgImltYWdlcy9ndWFyZC93YWxrIHJpZ2h0IHRleHR1cmVzIiwgImltYWdlcy9ndWFyZC93YWxrIGxlZnQgdGV4dHVyZXMiLCAiaW1hZ2VzL2d1YXJkL3dhbGsgcmlnaHQgdGV4dHVyZXMiLCAiaW1hZ2VzL2d1YXJkL3dhbGsgdXAgdGV4dHVyZXMiLCAiaW1hZ2VzL2d1YXJkL3dhbGsgZG93biB0ZXh0dXJlcyIsICJpbWFnZXMvZ3VhcmQvYWxlcnRlZCB3YWxrIGxlZnQgdGV4dHVyZXMiLCAiaW1hZ2VzL2d1YXJkL2FsZXJ0ZWQgd2FsayByaWdodCB0ZXh0dXJlcyIsICJpbWFnZXMvZ3VhcmQvYWxlcnRlZCB3YWxrIGxlZnQgdGV4dHVyZXMiLCAiaW1hZ2VzL2d1YXJkL2FsZXJ0ZWQgd2FsayByaWdodCB0ZXh0dXJlcyIsICJpbWFnZXMvZ3VhcmQvYWxlcnRlZCB3YWxrIHVwIHRleHR1cmVzIiwgImltYWdlcy9ndWFyZC9hbGVydGVkIHdhbGsgZG93biB0ZXh0dXJlcyJdCgojRGljdGlvbmFyeSBjb250YWluaW5nIGRpcmVjdG9yaWVzIG9mIGNvaW5zCnNwZWNpYWwgPSB7ImNvaW4gMSI6ImltYWdlcy9taXNjL2NvaW4gMS5wbmcifQoKI0EgcGF0cm9sIGNvbnRyb2xzIGEgZ3VhcmQsIGVhY2ggaXRlbSBpcyBhIGluc3RydWN0aW9uLCB3aXRoIHRoZSBpdGVtcyB3aXRoaW4gcmVwcmVzZW50aW5nOwojWCBkaXJlY3Rpb24sIFkgZGlyZWN0aW9uLCB0aW1lIHVudGlsIG5leHQgaW5zdHJ1Y3Rpb24sCiNJdCBsb29wcyB0aHJvdWdoIHRoZSBwYXRyb2wKI0ZvciBleGFtcGxlIHRoZSBmaXJzdCBwYXRyb2wgbWFrZXMgaGltIHdhbGsgdXAgZm9yIDMgc2Vjb25kcywgd2FsayByaWdodCBmb3IgMyBzZWNvbmRzLCB3YWxrIGRvd24gZm9yIDMgc2Vjb25kcywgd2FsayBsZWZ0IGZvciAzIHNlY29uZHMsIGFuZCB0aGVuIGJhY2sgdG8gdGhlIGJlZ2luaW5nIGFuZCBzbyBvbi4KcGF0cm9sXzEgPSBbWzAsIDEsIDAuOF0sIFsxLCAwLCAxMl0sIFswLCAtMSwgMC44XSwgWy0xLCAwLCAxMl1dCnBhdHJvbF8yID0gW1sxLCAwLCAxLjVdLCBbMCwxLCAxLjVdLFstMSwgMCwxLjVdLFswLC0xLCAxLjVdXQpwYXRyb2xfMyA9IFtbMSwwLCA0XSwgWy0xLCAwLCA0XV0KcGF0cm9sXzQgPSBbWzAsIDEsIDRdLCBbMCwgLTEsIDRdXQpwYXRyb2xfNSA9IFtbMCwgMSwgMl0sIFswLCAtMSwgMl1dCnBhdHJvbF82ID0gW1stMSwgMCwgMTJdLFsxLDAsIDEyXV0KcGF0cm9sXzcgPSBbWzEsIDAsIDEyXSwgWy0xLCAwLCAxMl1dCgojTG9hZHMgdGhlIHRleHR1cmVzIGludG8gYSAyRCBsaXN0IGZyb20gdGhlIGRpcmVjdG9yaWVzIGluIHRoZSBsaXN0IG9uIGxpbmUgMzAgaW4gdGhlIHNhbWUgb3JkZXIKcGxheWVyXzFfdGV4dHVyZXMgPSBbXQpmb3IgYSBpbiByYW5nZShsZW4ocGxheWVyXzFfdGV4dHVyZV9kaXJlY3RvcmllcykpOgogICNHZXRzIHRoZSBmaWxlbmFtZXMgb2YgdGhlIGZpbGVzIGluIHRoZSBkaXJlY3RvcnkKICBmaWxlcyA9IG9zLmxpc3RkaXIocGxheWVyXzFfdGV4dHVyZV9kaXJlY3Rvcmllc1thXSkKICB0ZXh0dXJlcyA9IFtdICNUaGlzIHdpbGwgYmUgdGhlIHNlY29uZCBkaW1lbnNpb24gdG8gdGhlIDJEIGxpc3QKICAjTG9vcHMgdGhyb3VnaCBlYWNoIGZpbGVuYW1lIGluIHRoZSBkaXJlY3RvcnkKICBmb3IgYiBpbiByYW5nZShsZW4oZmlsZXMpKToKICAgICNBZGRzIGEgbG9hZGVkIGZyb20gdGhlIGRpcmVjdG9yeSBtYWRlIGJ5IGNvbmNhdGluYXRpbmcgIi8iIGFuZCB0aGUgZmlsZW5hbWUgdG8gdGhlIG9yaWdpbmFsIGRpcmVjdG9yeQogICAgdGV4dHVyZXMuYXBwZW5kKGFyY2FkZS5sb2FkX3RleHR1cmUocGxheWVyXzFfdGV4dHVyZV9kaXJlY3Rvcmllc1thXSArICIvIiArIGZpbGVzW2JdKSkKICAjQWRkcyBhbGwgdGhlIGRpcmVjdG9yaWVzIHRleHR1cmVzIHRvIHRoZSBvcmlnaW5hbCBsaXN0IGhlbmNlIGEgMkQgbGlzdAogIHBsYXllcl8xX3RleHR1cmVzLmFwcGVuZCh0ZXh0dXJlcykKCiNMb2FkcyB0aGUgdGV4dHVyZXMgaW50byBhIDJEIGxpc3QgZnJvbSB0aGUgZGlyZWN0b3JpZXMgaW4gdGhlIHNhbWUgd2F5IGFzIGZvciBwbGF5ZXIgMQpwbGF5ZXJfMl90ZXh0dXJlcyA9IFtdCmZvciBhIGluIHJhbmdlKGxlbihwbGF5ZXJfMl90ZXh0dXJlX2RpcmVjdG9yaWVzKSk6CiAgZmlsZXMgPSBvcy5saXN0ZGlyKHBsYXllcl8yX3RleHR1cmVfZGlyZWN0b3JpZXNbYV0pCiAgdGV4dHVyZXMgPSBbXQogIGZvciBiIGluIHJhbmdlKGxlbihmaWxlcykpOgogICAgdGV4dHVyZXMuYXBwZW5kKGFyY2FkZS5sb2FkX3RleHR1cmUocGxheWVyXzJfdGV4dHVyZV9kaXJlY3Rvcmllc1thXSArICIvIiArIGZpbGVzW2JdKSkKICBwbGF5ZXJfMl90ZXh0dXJlcy5hcHBlbmQodGV4dHVyZXMpCgojTG9hZHMgdGhlIHRleHR1cmVzIGludG8gYSAyRCBsaXN0IGZyb20gdGhlIGRpcmVjdG9yaWVzIGluIHRoZSBzYW1lIHdheSBhcyBmb3IgcGxheWVyIDEgYW5kIHBsYXllciAyCmd1YXJkX3RleHR1cmVzID0gW10KZm9yIGEgaW4gcmFuZ2UobGVuKGd1YXJkX3RleHR1cmVfZGlyZWN0b3JpZXMpKToKICBmaWxlcyA9IG9zLmxpc3RkaXIoZ3VhcmRfdGV4dHVyZV9kaXJlY3Rvcmllc1thXSkKICB0ZXh0dXJlcyA9IFtdCiAgZm9yIGIgaW4gcmFuZ2UobGVuKGZpbGVzKSk6CiAgICB0ZXh0dXJlcy5hcHBlbmQoYXJjYWRlLmxvYWRfdGV4dHVyZShndWFyZF90ZXh0dXJlX2RpcmVjdG9yaWVzW2FdICsgIi8iICsgZmlsZXNbYl0pKQogIGd1YXJkX3RleHR1cmVzLmFwcGVuZCh0ZXh0dXJlcykKCiNDbGFzcyBmb3IgYW55IGNoYXJhY3RlciB3aXRoIGFuaW1hdGlvbnMgc3VjaCBhcyB0aGUgcGxheWVycyBhbmQgZ3VhcmRzCmNsYXNzIENoYXJhY3RlcihhcmNhZGUuQW5pbWF0ZWRXYWxraW5nU3ByaXRlKToKICBkZWYgX19pbml0X18oc2VsZiwgc2NhbGUsIHN0YW5kX2xlZnRfdGV4dHVyZXMsIHN0YW5kX3JpZ2h0X3RleHR1cmVzLCB3YWxrX2xlZnRfdGV4dHVyZXMsIHdhbGtfcmlnaHRfdGV4dHVyZXMsIHdhbGtfdXBfdGV4dHVyZXMsIHdhbGtfZG93bl90ZXh0dXJlcywgdGV4dHVyZV9jaGFuZ2VfZGlzdGFuY2UsIGNvbGxpc2lvbnMsIHNwZWVkKToKICAgIHN1cGVyKCkuX19pbml0X18oc2NhbGUpCiAgICAjRm9yIHNvbWUgcmVhc29uIGFsdGhvdWdoIGluIGFyY2FkZSBpdCBzZXRzIHRoZSBfdGV4dHVyZSBpbiBpbml0aWFsaXphdGlvbiBzb21ldGltZXMgaXQgcmVxdWlyZXMgc29tZSBoZWxwCiAgICBzZWxmLl90ZXh0dXJlID0gc3RhbmRfcmlnaHRfdGV4dHVyZXNbMF0KICAgICNTZXQgdGhlIHBhcmVudCBjbGFzc2VzIHRleHR1cmVzIGFsbG93aW5nIGl0IHRvIHByb2NjZXNzIGFuaW1hdGlvbnMKICAgIHNlbGYuc3RhbmRfbGVmdF90ZXh0dXJlcyA9IHN0YW5kX2xlZnRfdGV4dHVyZXMKICAgIHNlbGYuc3RhbmRfcmlnaHRfdGV4dHVyZXMgPSBzdGFuZF9yaWdodF90ZXh0dXJlcwogICAgc2VsZi53YWxrX2xlZnRfdGV4dHVyZXMgPSB3YWxrX2xlZnRfdGV4dHVyZXMKICAgIHNlbGYud2Fsa19yaWdodF90ZXh0dXJlcyA9IHdhbGtfcmlnaHRfdGV4dHVyZXMKICAgIHNlbGYud2Fsa191cF90ZXh0dXJlcyA9IHdhbGtfdXBfdGV4dHVyZXMKICAgIHNlbGYud2Fsa19kb3duX3RleHR1cmVzID0gd2Fsa19kb3duX3RleHR1cmVzCiAgICAjU2V0IHRoZSBwYXJlbnQgY2xhc3NlcyB0ZXh0dXJlIGNoYW5nZSBkaXN0YW5jZSwgdGhpcyBkZXRlcm1pbnMgaG93IG11Y2ggZGlzdGFuY2UgYmVmb3JlIGEgdGhlIGN1cnJlbnQgdGV4dHVyZSBzaG91bGQgYmUgc3dpdGNoZWQKICAgIHNlbGYudGV4dHVyZV9jaGFuZ2VfZGlzdGFuY2UgPSB0ZXh0dXJlX2NoYW5nZV9kaXN0YW5jZQogICAgI0NyZWF0ZSBwaHlzaWNzIChjb2xsaXNpb24gYW5kIG1vdmVtZW50KSBmb3IgdGhlIGNoYXJhY3RlcgogICAgc2VsZi5waHlzaWNzID0gYXJjYWRlLlBoeXNpY3NFbmdpbmVTaW1wbGUoc2VsZiwgY29sbGlzaW9ucykKICAgICNTZXQgdGhlIGNsYXNzZXMgc3BlZWQKICAgIHNlbGYuc3BlZWQgPSBzcGVlZAogICAgc2VsZi5nYW1lX292ZXJfY29sbGlzaW9uID0gRmFsc2UKICAgIHNlbGYuZ2FtZV9vdmVyX3RpbWUgPSAwCiAgZGVmIHNldHVwKHNlbGYsIHgsIHkpOgogICAgI1BsYWNlIHRoZSBjaGFyYWN0ZXIgYXQgc3BlY2lmaWVkIGNvb3JkaW5hdGVzCiAgICBzZWxmLmNlbnRlcl94ID0geAogICAgc2VsZi5jZW50ZXJfeSA9IHkKICAjVXBkYXRlcyB0aGUgY2hhcmFjdGVyIGhvd2V2ZXIgbmVlZHMgdG8gYmUgZXh0ZXJuYWxseSBjYWxsZWQKICBkZWYgdXBkYXRlKHNlbGYpOgogICAgc2VsZi51cGRhdGVfYW5pbWF0aW9uKCkKICAgIHNlbGYucGh5c2ljcy51cGRhdGUoKQogICAKCiNDbGFzcyBmb3IgYSBndWFyZCwgYSBmYWlybHkgY29tcGxleCAnQUknIGFsdGhvdWdoIGl0IGlzIGp1c3QgYSBhbGdvcml0aG0sIG5vIGRlZXAgbGVhcm5pbmcKY2xhc3MgR3VhcmQoQ2hhcmFjdGVyKToKICBkZWYgX19pbml0X18oc2VsZiwgc2NhbGUsIHN0YW5kX2xlZnRfdGV4dHVyZXMsIHN0YW5kX3JpZ2h0X3RleHR1cmVzLCB3YWxrX2xlZnRfdGV4dHVyZXMsIHdhbGtfcmlnaHRfdGV4dHVyZXMsIHdhbGtfdXBfdGV4dHVyZXMsIHdhbGtfZG93bl90ZXh0dXJlcywgYWxlcnRlZF9zdGFuZF9sZWZ0X3RleHR1cmVzLCBhbGVydGVkX3N0YW5kX3JpZ2h0X3RleHR1cmVzLCBhbGVydGVkX3dhbGtfbGVmdF90ZXh0dXJlcywgYWxlcnRlZF93YWxrX3JpZ2h0X3RleHR1cmVzLCBhbGVydGVkX3dhbGtfdXBfdGV4dHVyZXMsIGFsZXJ0ZWRfd2Fsa19kb3duX3RleHR1cmVzLCB0ZXh0dXJlX2NoYW5nZV9kaXN0YW5jZSwgY29sbGlzaW9ucywgc3BlZWQsIHBhdHJvbCwgYWxlcnRfdGltZXIpOgogICAgc3VwZXIoKS5fX2luaXRfXyhzY2FsZSwgc3RhbmRfbGVmdF90ZXh0dXJlcywgc3RhbmRfcmlnaHRfdGV4dHVyZXMsIHdhbGtfbGVmdF90ZXh0dXJlcywgd2Fsa19yaWdodF90ZXh0dXJlcywgd2Fsa191cF90ZXh0dXJlcywgd2Fsa19kb3duX3RleHR1cmVzLCB0ZXh0dXJlX2NoYW5nZV9kaXN0YW5jZSwgY29sbGlzaW9ucywgc3BlZWQpCiAgICAjU3RvcmUgdGV4dHVyZXMgYXMgdGhleSB3aWxsIG5lZWQgdG8gYmUgdXNlZCBhZ2FpbiwgdGhlIHVuZGVyc2NvcmUgKF8pIGlzIHJlcXVpcmVkIHRvIGRpZmZlcmVudGlhdGUgaXQgZnJvbSB0aGUgcGFyZW50IGNsYXNzZXMgdGV4dHVyZXMKICAgIHNlbGYuX3N0YW5kX2xlZnRfdGV4dHVyZXMgPSBzdGFuZF9sZWZ0X3RleHR1cmVzCiAgICBzZWxmLl9zdGFuZF9yaWdodF90ZXh0dXJlcyA9IHN0YW5kX3JpZ2h0X3RleHR1cmVzCiAgICBzZWxmLl93YWxrX2xlZnRfdGV4dHVyZXMgPSB3YWxrX2xlZnRfdGV4dHVyZXMKICAgIHNlbGYuX3dhbGtfcmlnaHRfdGV4dHVyZXMgPSB3YWxrX3JpZ2h0X3RleHR1cmVzCiAgICBzZWxmLl93YWxrX3VwX3RleHR1cmVzID0gd2Fsa191cF90ZXh0dXJlcwogICAgc2VsZi5fd2Fsa19kb3duX3RleHR1cmVzID0gd2Fsa19kb3duX3RleHR1cmVzCiAgICAjU3RvcmUgYWxlcnRlZCB0ZXh0dXJlcyBhcyB0aGV5IHdpbGwgbmVlZCB0byBiZSB1c2VkIGFnYWluCiAgICBzZWxmLmFsZXJ0ZWRfc3RhbmRfbGVmdF90ZXh0dXJlcyA9IGFsZXJ0ZWRfc3RhbmRfbGVmdF90ZXh0dXJlcwogICAgc2VsZi5hbGVydGVkX3N0YW5kX3JpZ2h0X3RleHR1cmVzID0gYWxlcnRlZF9zdGFuZF9yaWdodF90ZXh0dXJlcwogICAgc2VsZi5hbGVydGVkX3dhbGtfbGVmdF90ZXh0dXJlcyA9IGFsZXJ0ZWRfd2Fsa19sZWZ0X3RleHR1cmVzCiAgICBzZWxmLmFsZXJ0ZWRfd2Fsa19yaWdodF90ZXh0dXJlcyA9IGFsZXJ0ZWRfd2Fsa19yaWdodF90ZXh0dXJlcwogICAgc2VsZi5hbGVydGVkX3dhbGtfdXBfdGV4dHVyZXMgPSBhbGVydGVkX3dhbGtfdXBfdGV4dHVyZXMKICAgIHNlbGYuYWxlcnRlZF93YWxrX2Rvd25fdGV4dHVyZXMgPSBhbGVydGVkX3dhbGtfZG93bl90ZXh0dXJlcwogICAgI1NldCB0aGUgY2xhc3NlcyBwYXRyb2wKICAgIHNlbGYucGF0cm9sID0gcGF0cm9sCiAgICAjU2V0IHRoZSBjbGFzc2VzIGFsZXJ0X3RpbWVyLCB0aGlzIGlzIGhvdyBsb25nIHRoZSBndWFyZCB3aWxsIG1haW50YWluIGFsZXJ0ZWQgYmVmb3JlIGxvc2luZyBpbnRlcmVzdAogICAgc2VsZi5hbGVydF90aW1lciA9IGFsZXJ0X3RpbWVyCgogIGRlZiBndWFyZF9zZXR1cChzZWxmLCB4LCB5KToKICAgICNDYWxsIHRoZSBwYXJlbnQgY2xhc3NlcyBzZXR1cCB0byBwbGFjZSB0aGUgZ3VhcmQKICAgIHNlbGYuc2V0dXAoeCwgeSkKICAgICNTZXQgdGhlIGRpcmVjdGlvbiBvZiBtb3ZlbWVudCB0byBiZSBzdGlsbAogICAgc2VsZi5kaXJfeCA9IDAKICAgIHNlbGYuZGlyX3kgPSAwCiAgICAjU2V0IHRoZSBwYXRyb2wgaW5kZXgsIHRoZSBwYXRyb2wgaW5kZXggaXMgdGhlIGluZGV4IGRldGVybWluaW5nIHdoaWNoIGluc3RydWN0aW9uIHdpdGhpbiB0aGUgcGF0cm9sIGlzIGluIHVzZQogICAgc2VsZi5wYXRyb2xfaW5kZXggPSAwCiAgICAjU2V0IHRoZSBjaGFuZ2UgdGltZSwgY2hhbmdlIHRpbWUgaXMgdGhlIGV4YWN0IHRpbWUgYXQgd2hpY2ggdGhlIGd1YXJkIHNob3VsZCBzd2l0Y2ggaW5zdHJ1Y3Rpb24gd2l0aGluIHRoZSBwYXRyb2wKICAgIHNlbGYuY2hhbmdlX3RpbWUgPSB0aW1lLnRpbWUoKSArIHNlbGYucGF0cm9sWzBdWzJdCiAgICAjU2V0IHRoZSBhbGVydCwgZGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBndWFyZCBpcyBhbGVydGVkCiAgICBzZWxmLmFsZXJ0ZWQgPSBGYWxzZQogICAgI0FsZXJ0IHRpbWUgaXMgdGhlIGV4YWN0IHRpbWUgaW4gd2hpY2ggdGhlIGd1YXJkIHNob3VsZCBiZWNvbWUgdW4tYWxlcnQKICAgIHNlbGYuYWxlcnRfdGltZSA9IDAKICAgICNTZXQgdGhlIHRhcmdldCwgdGFyZ2V0IGlzIHRoZSBwb2ludCB0aGUgZ3VhcmQgd2lsbCB0YXJnZXQgd2hlbiBhbHRlcnRlZCwgdGhpcyBpcyBtb3N0IGxpa2VseSBhIHBsYXllcnMgcG9zaXRpb24KICAgIHNlbGYudGFyZ2V0ID0gWzAsIDBdCiAgCiAgZGVmIGd1YXJkX3VwZGF0ZShzZWxmKToKICAgICNJZiBhbGVydGVkIHRoZW4gY2hlY2sgd2hldGhlciBhbGVydCBpcyBzdGlsbCB2YWxpZCwgaWYgdHJ1ZSBmb2xsb3cgdGFyZ2V0LCBpZiBmYWxzZSB0aGVtIGJlY29tZSB1bi1hbGVydAogICAgaWYoc2VsZi5hbGVydGVkKToKICAgICAgaWYodGltZS50aW1lKCkgPj0gc2VsZi5hbGVydF90aW1lKToKICAgICAgICBzZWxmLnVuX2FsZXJ0KCkKICAgICAgZWxzZToKICAgICAgICAjVGFyZ2V0IGlzIHNldCBleHRlcm5hbGx5IHRvIHRoZSBuZWFyZXN0IHBsYXllcgogICAgICAgIGRlc3RfeCA9IHNlbGYudGFyZ2V0WzBdCiAgICAgICAgZGVzdF95ID0gc2VsZi50YXJnZXRbMV0KICAgICAgICAjQ2FsY3VsYXRlIHRoZSBhbmdsZSB0aGUgZnJvbSB0aGUgZnJvbSB0aGUgdGFyZ2V0IHRvIHRoZSBndWFyZCAKICAgICAgICB4X2RpZmYgPSBkZXN0X3ggLSBzZWxmLmNlbnRlcl94CiAgICAgICAgeV9kaWZmID0gZGVzdF95IC0gc2VsZi5jZW50ZXJfeQogICAgICAgIGFuZ2xlID0gbWF0aC5hdGFuMih5X2RpZmYsIHhfZGlmZikKICAgICAgICAjVGhlbiB1c2luZyB0aGUgYW5nbGUgd2UgY2FuIGNhbGN1bGF0ZSB0aGUgbmVjY2VzYXJ5IGRpcmVjdGlvbgogICAgICAgIHNlbGYuY2hhbmdlX3ggPSBtYXRoLmNvcyhhbmdsZSkgKiBzZWxmLnNwZWVkCiAgICAgICAgc2VsZi5jaGFuZ2VfeSA9IG1hdGguc2luKGFuZ2xlKSAqIHNlbGYuc3BlZWQKICAgICNJZiBub3QgYWxlcnQgdGhlbiBmb2xsb3cgdGhlIHBhdHJvbAogICAgZWxzZToKICAgICAgI0lmIHBhdHJvbCBpbnN0cnVjdGlvbiB0aW1lIGhhcyBiZWVuIHJlYWNoZWQgdGhlbiBzd2l0Y2ggdG8gbmV4dCBpbnN0cnVjdGlvbgogICAgICBpZih0aW1lLnRpbWUoKSA+PSBzZWxmLmNoYW5nZV90aW1lKToKICAgICAgICBpZihzZWxmLnBhdHJvbF9pbmRleCA9PSBsZW4oc2VsZi5wYXRyb2wpIC0gMSk6CiAgICAgICAgICBzZWxmLnBhdHJvbF9pbmRleCA9IDAKICAgICAgICBlbHNlOiAKICAgICAgICAgIHNlbGYucGF0cm9sX2luZGV4ICs9IDEKICAgICAgICBzZWxmLmRpcl94ID0gc2VsZi5wYXRyb2xbc2VsZi5wYXRyb2xfaW5kZXhdWzBdCiAgICAgICAgc2VsZi5kaXJfeSA9IHNlbGYucGF0cm9sW3NlbGYucGF0cm9sX2luZGV4XVsxXQogICAgICAgIHNlbGYuY2hhbmdlX3RpbWUgPSB0aW1lLnRpbWUoKSArIHNlbGYucGF0cm9sW3NlbGYucGF0cm9sX2luZGV4XVsyXQogICAgICAjTW92ZSB0aGUgZ3VhcmQKICAgICAgc2VsZi5jaGFuZ2VfeCA9IHNlbGYuZGlyX3ggKiBzZWxmLnNwZWVkCiAgICAgIHNlbGYuY2hhbmdlX3kgPSBzZWxmLmRpcl95ICogc2VsZi5zcGVlZAogICAgI0luIHRoZSBjaGFyYWN0ZXIgY2xhc3MsIHRoaXMgdXBkYXRlcyB0aGUgY2hhcmFjdGVycyBhbmltYXRpb25zIGFuZCBwaHlzaWNzCiAgICBzZWxmLnVwZGF0ZSgpCiAgCiAgZGVmIGFsZXJ0KHNlbGYpOgogICAgI1NldCB0byBiZSBhbGVydAogICAgc2VsZi5hbGVydGVkID0gVHJ1ZQogICAgI1NldCBhbGVydCB0ZXJtaW5hdGlvbiB0aW1lCiAgICBzZWxmLmFsZXJ0X3RpbWUgPSB0aW1lLnRpbWUoKSArIHNlbGYuYWxlcnRfdGltZXIKICAgICNTd2l0Y2ggdGV4dHVyZXMgdG8gdGhlIGFsZXJ0IHZhcmlhdGlvbgogICAgc2VsZi5zdGFuZF9sZWZ0X3RleHR1cmVzID0gc2VsZi5hbGVydGVkX3N0YW5kX2xlZnRfdGV4dHVyZXMKICAgIHNlbGYuc3RhbmRfcmlnaHRfdGV4dHVyZXMgPSBzZWxmLmFsZXJ0ZWRfc3RhbmRfcmlnaHRfdGV4dHVyZXMKICAgIHNlbGYud2Fsa19sZWZ0X3RleHR1cmVzID0gc2VsZi5hbGVydGVkX3dhbGtfbGVmdF90ZXh0dXJlcwogICAgc2VsZi53YWxrX3JpZ2h0X3RleHR1cmVzID0gc2VsZi5hbGVydGVkX3dhbGtfcmlnaHRfdGV4dHVyZXMKICAgIHNlbGYud2Fsa191cF90ZXh0dXJlcyA9IHNlbGYuYWxlcnRlZF93YWxrX3VwX3RleHR1cmVzCiAgICBzZWxmLndhbGtfZG93bl90ZXh0dXJlcyA9IHNlbGYuYWxlcnRlZF93YWxrX2Rvd25fdGV4dHVyZXMKICAKICBkZWYgdW5fYWxlcnQoc2VsZik6CiAgICAjU2V0IHRvIGJlIHVuLWFsZXJ0CiAgICBzZWxmLmFsZXJ0ZWQgPSBGYWxzZQogICAgI1NldCB0ZXh0dXJlcyB0byB0aGUgdW4tYWxlcnQgdmFyaWF0aW9uCiAgICBzZWxmLnN0YW5kX2xlZnRfdGV4dHVyZXMgPSBzZWxmLl9zdGFuZF9sZWZ0X3RleHR1cmVzCiAgICBzZWxmLnN0YW5kX3JpZ2h0X3RleHR1cmVzID0gc2VsZi5fc3RhbmRfcmlnaHRfdGV4dHVyZXMKICAgIHNlbGYud2Fsa19sZWZ0X3RleHR1cmVzID0gc2VsZi5fd2Fsa19sZWZ0X3RleHR1cmVzCiAgICBzZWxmLndhbGtfcmlnaHRfdGV4dHVyZXMgPSBzZWxmLl93YWxrX3JpZ2h0X3RleHR1cmVzCiAgICBzZWxmLndhbGtfdXBfdGV4dHVyZXMgPSBzZWxmLl93YWxrX3VwX3RleHR1cmVzCiAgICBzZWxmLndhbGtfZG93bl90ZXh0dXJlcyA9IHNlbGYuX3dhbGtfZG93bl90ZXh0dXJlcwoKI1RoaXMgaXMgdGhlIG1haW4gY2xhc3MsIGl0IGNvbnRyb2xscyB0aGUgbGV2ZWxzLCByb29tIGdlbmVyYXRpb24sIGNvaW5zLCBjb250cm9sbHMgdGhlIHBsYXllcnMgYW5kIGhhbmRsZXMgaW5wdXQsIGxvZ2ljLCByZW5kZXJpbmcgZm9yIHRoZSBnYW1lIGxvb3AKY2xhc3MgR2FtZShhcmNhZGUuV2luZG93KToKICAjU2V0dXAgcmVxdWlyZWQgZm9yIGFsbCBsZXZlbHMKICBkZWYgc2V0dXAoc2VsZik6CiAgICAjQW4gYXJjYWRlLlNwcml0ZUxpc3QoKSBpcyBhIGxpc3Qgb2Ygc3ByaXRlcyB0aGF0IGhhcyBleHRyYSBmdW5jdGlvbmFsaXR5IGFuZCBjYW4gYmUgcmVuZGVyZWQgZWFzaWx5IGFuZCBwZXJmb3JtYW50bHkKICAgICNTZXR1cCBhbGwgdGlsZXMgdGhhdCB0aGUgY2hhcmFjdGVycyBjYW4gbW92ZSB0aHJvdWdoCiAgICBzZWxmLnN0YXRpY19ub19jb2xsaXNpb24gPSBhcmNhZGUuU3ByaXRlTGlzdCgpCiAgICAjU2V0dXAgYWxsIHRpbGVzIHRoYXQgdGhlIGNoYXJhY3RlcnMgY2Fubm90IG1vdmUgdGhyb3VnaAogICAgc2VsZi5zdGF0aWNfY29sbGlzaW9uID0gYXJjYWRlLlNwcml0ZUxpc3QoKQogICAgI1NldHVwIGFsbCB0aWxlcyB0aGF0IG1vdmVzIHRoZSBjaGFyYWN0ZXJzIHRvIHRoZSBuZXh0IHJvb20vbGV2ZWwKICAgIHNlbGYuZXhpdHMgPSBhcmNhZGUuU3ByaXRlTGlzdCgpCiAgICAjU2V0dXAgYWxsIHRpbGVzIHRoYXQgbW92ZXMgdGhlIGNoYXJhY3RlcnMgdG8gdGhlIHByZXZpb3VzIHJvb20KICAgIHNlbGYuZW50cmFuY2VzID0gYXJjYWRlLlNwcml0ZUxpc3QoKQoKICAgIHNlbGYuY29pbnMgPSBhcmNhZGUuU3ByaXRlTGlzdCgpCgogICAgI0NyZWF0ZSBhIGd1YXJkIGZvciBlYWNoIHBvc2l0aW9uIHBhc3NlZCBpbiBpbml0aWFsaXphdGlvbiBhbmQgYXNzaWduIHRoZW0gdGhlIGNvcnJlc3BvbmRpbmcgcGF0cm9sIHBhc3NlZCBpbiBpbml0aWFsaXphdGlvbgogICAgc2VsZi5ndWFyZHMgPSBbXQogICAgZm9yIGkgaW4gcmFuZ2UobGVuKHNlbGYubGV2ZWxfZ3VhcmRfcG9zaXRpb25zW3NlbGYubGV2ZWxfaW5kZXhdKSk6CiAgICAgICBndWFyZCA9IEd1YXJkKDEsIGd1YXJkX3RleHR1cmVzWzBdLCBndWFyZF90ZXh0dXJlc1sxXSwgZ3VhcmRfdGV4dHVyZXNbMl0sIGd1YXJkX3RleHR1cmVzWzNdLCBndWFyZF90ZXh0dXJlc1s0XSwgZ3VhcmRfdGV4dHVyZXNbNV0sIGd1YXJkX3RleHR1cmVzWzZdLCBndWFyZF90ZXh0dXJlc1s3XSwgZ3VhcmRfdGV4dHVyZXNbOF0sIGd1YXJkX3RleHR1cmVzWzldLCBndWFyZF90ZXh0dXJlc1sxMF0sIGd1YXJkX3RleHR1cmVzWzExXSwgNSwgc2VsZi5zdGF0aWNfY29sbGlzaW9uLCAxLjI1LCBzZWxmLmxldmVsX2d1YXJkX3BhdHJvbHNbc2VsZi5sZXZlbF9pbmRleF1baV0sIDYpCiAgICAgICBndWFyZC5ndWFyZF9zZXR1cChzZWxmLmxldmVsX2d1YXJkX3Bvc2l0aW9uc1tzZWxmLmxldmVsX2luZGV4XVtpXVswXSwgc2VsZi5sZXZlbF9ndWFyZF9wb3NpdGlvbnNbc2VsZi5sZXZlbF9pbmRleF1baV1bMV0pCiAgICAgICBzZWxmLmd1YXJkcy5hcHBlbmQoZ3VhcmQpCiAgICAjQ3JlYXRlIGEgY29pbnMgCiAgICBmb3IgaSBpbiByYW5nZShsZW4oc2VsZi5sZXZlbF9jb2luX3Bvc2l0aW9uc1tzZWxmLmxldmVsX2luZGV4XSkpOgogICAgICBzZWxmLmNvaW5zLmFwcGVuZChhcmNhZGUuU3ByaXRlKHNwZWNpYWxbImNvaW4gMSJdLCBjZW50ZXJfeCA9IHNlbGYubGV2ZWxfY29pbl9wb3NpdGlvbnNbc2VsZi5sZXZlbF9pbmRleF1baV1bMF0sIGNlbnRlcl95ID0gc2VsZi5sZXZlbF9jb2luX3Bvc2l0aW9uc1tzZWxmLmxldmVsX2luZGV4XVtpXVsxXSkpCiAgICAjc2V0cyB1cCBhbGwgdGhlIHRleHR1cmVzIGZvciBwbGF5ZXIxCiAgICBzZWxmLnBsYXllcl8xID0gQ2hhcmFjdGVyKDEsIHBsYXllcl8xX3RleHR1cmVzWzBdLCBwbGF5ZXJfMV90ZXh0dXJlc1sxXSwgcGxheWVyXzFfdGV4dHVyZXNbMl0sIHBsYXllcl8xX3RleHR1cmVzWzNdLCBwbGF5ZXJfMV90ZXh0dXJlc1s0XSwgcGxheWVyXzFfdGV4dHVyZXNbNV0sIDUsIHNlbGYuc3RhdGljX2NvbGxpc2lvbiwgMikKICAgICNzZXRzIHVwIGFsbCB0aGUgdGV4dHVyZXMgZm9yIHBsYXllcjEKICAgIHNlbGYucGxheWVyXzIgPSBDaGFyYWN0ZXIoMSwgcGxheWVyXzJfdGV4dHVyZXNbMF0sIHBsYXllcl8yX3RleHR1cmVzWzFdLCBwbGF5ZXJfMl90ZXh0dXJlc1syXSwgcGxheWVyXzJfdGV4dHVyZXNbM10sIHBsYXllcl8yX3RleHR1cmVzWzRdLCBwbGF5ZXJfMl90ZXh0dXJlc1s1XSwgNSwgc2VsZi5zdGF0aWNfY29sbGlzaW9uLCAyKQoKICAjVXNpbmcgZnVjdGlvbnMgdG8gc2V0dXAgbGV2ZWxzIGFzIGEgcG9zZSB0byBjbGFzc2VzIGFsdGhvdWdoIGxlbmd0aHksIGl0cyBzaW1wbGVyIGFuZCBlYXNpZXIgdG8gY2F0b3IgdG8gYSBzcGVjaWZpYyBsZXZlbAogIGRlZiBsZXZlbF8xKHNlbGYpOgogICAgI1NldHMgdGhlIGxldmVsIGluZGV4IHRvIGFsbG93IHRoZSBjbGFzcyB0aGUga25vdyB0aGUgY3VycmVudCBsZXZlbCwKICAgICNJdHMgYmVpbmcgc2V0IGhlcmUgaW5zdGVhZCBvZiBiZWluZyBhZGRlZCBhbmQgc3VidHJhY3RlZCB0byB3aGVuIGNvbGxpZGluZyB3aXRoIGVudHJhbmNlcyBhbmQgZXhpdHMgdG8gYXZvaWQgbWlzYWxpZ25tZW50CiAgICBzZWxmLmxldmVsX2luZGV4ID0gMAogICAgI0NhbGxzIHRoZSBkZWZhdWx0IHNldHVwCiAgICBzZWxmLnNldHVwKCkKICAgICNTZXRzIHVwIHRoZSBzcHJpdGVzIGZvciB0aGUgcm9vbQogICAgc2VsZi5jcmVhdGVfcm9vbShyb29tcy5yb29tXzEsIDAsIDAsIDI0KQogICAgI1NldHMgdXAgdGhlIHBsYXllcnMgYXQgc3BlY2lmaWVkIGNvb3JkaW5hdGVzCiAgICBzZWxmLnBsYXllcl8xLnNldHVwKDEwMCwgMTAwKQogICAgc2VsZi5wbGF5ZXJfMi5zZXR1cCgxMDAsIDEwMCkKCiAgZGVmIGxldmVsXzIoc2VsZik6CiAgICBzZWxmLmxldmVsX2luZGV4ID0gMQogICAgc2VsZi5zZXR1cCgpCiAgICBzZWxmLmNyZWF0ZV9yb29tKHJvb21zLnJvb21fMiwgMCwgMCwgMjQpCiAgICBzZWxmLnBsYXllcl8xLnNldHVwKDEwMCwgMTAwKQogICAgc2VsZi5wbGF5ZXJfMi5zZXR1cCgxMDAsIDEwMCkKCiAgZGVmIGxldmVsXzMoc2VsZik6CiAgICBzZWxmLmxldmVsX2luZGV4ID0gMgogICAgc2VsZi5zZXR1cCgpCiAgICBzZWxmLmNyZWF0ZV9yb29tKHJvb21zLnJvb21fMywgMCwgMCwgMjQpCiAgICBzZWxmLnBsYXllcl8xLnNldHVwKDEwMCwgMTAwKQogICAgc2VsZi5wbGF5ZXJfMi5zZXR1cCgxMDAsIDEwMCkKIAogIGRlZiBsZXZlbF80KHNlbGYpOgogICAgc2VsZi5sZXZlbF9pbmRleCA9IDMKICAgIHNlbGYuc2V0dXAoKQogICAgc2VsZi5jcmVhdGVfcm9vbShyb29tcy5yb29tXzQsIDAsIDAsIDI0KQogICAgc2VsZi5wbGF5ZXJfMS5zZXR1cCgxMDAsIDEwMCkKICAgIHNlbGYucGxheWVyXzIuc2V0dXAoMTAwLCAxMDApCgogIGRlZiBsZXZlbF81KHNlbGYpOgogICAgc2VsZi5sZXZlbF9pbmRleCA9IDQKICAgIHNlbGYuc2V0dXAoKQogICAgc2VsZi5jcmVhdGVfcm9vbShyb29tcy5yb29tXzUsIDAsIDAsIDI0KQogICAgc2VsZi5wbGF5ZXJfMS5zZXR1cCgxMDAsIDEwMCkKICAgIHNlbGYucGxheWVyXzIuc2V0dXAoMTAwLCAxMDApCgogIGRlZiBsZXZlbF82KHNlbGYpOgogICAgc2VsZi5sZXZlbF9pbmRleCA9IDUKICAgIHNlbGYuc2V0dXAoKQogICAgc2VsZi5jcmVhdGVfcm9vbShyb29tcy5yb29tXzYsIDAsIDAsIDI0KQogICAgc2VsZi5wbGF5ZXJfMS5zZXR1cCgxMDAsIDEwMCkKICAgIHNlbGYucGxheWVyXzIuc2V0dXAoMTAwLCAxMDApCgogIGRlZiBsZXZlbF83KHNlbGYpOgogICAgc2VsZi5sZXZlbF9pbmRleCA9IDYKICAgIHNlbGYuc2V0dXAoKQogICAgc2VsZi5jcmVhdGVfcm9vbShyb29tcy5yb29tXzcsIDAsIDAsIDI0KQogICAgc2VsZi5wbGF5ZXJfMS5zZXR1cCgxMDAsIDEwMCkKICAgIHNlbGYucGxheWVyXzIuc2V0dXAoMTAwLCAxMDApCgoKCiAgZGVmIGdhbWVfb3ZlcihzZWxmKToKICAgICNTZXQgYWxsIHRoZSB2YXJpYWJsZXMgdG8gdGhlaXIgbnVsbCBzdGF0ZXMKICAgIHNlbGYuc3RhdGljX25vX2NvbGxpc2lvbiA9IGFyY2FkZS5TcHJpdGVMaXN0KCkKICAgIHNlbGYuc3RhdGljX2NvbGxpc2lvbiA9IGFyY2FkZS5TcHJpdGVMaXN0KCkKICAgIHNlbGYuZXhpdHMgPSBhcmNhZGUuU3ByaXRlTGlzdCgpCiAgICBzZWxmLmVudHJhbmNlcyA9IGFyY2FkZS5TcHJpdGVMaXN0KCkKICAgIHNlbGYuY29pbnMgPSBhcmNhZGUuU3ByaXRlTGlzdCgpCiAgICBzZWxmLmd1YXJkcyA9IFtdCgogIGRlZiBfX2luaXRfXyhzZWxmLCB3aWR0aCwgaGVpZ2h0LCB0aXRsZSwgdmlldywgbGV2ZWxfZ3VhcmRfcG9zaXRpb25zLCBsZXZlbF9ndWFyZF9wYXRyb2xzLCBjb2luX2NvdW50cywgbGV2ZWxfZGltZW5zaW9ucyk6CiAgICAjSW5pdGlhbGl6ZSB0aGUgcGFyZW50IGNsYXNzIChhIHdpbmRvdykKICAgIHN1cGVyKCkuX19pbml0X18od2lkdGgsIGhlaWdodCwgdGl0bGUpCiAgICAjTGlzdCBvZiBvdXIgbGV2ZWwgZnVuY3Rpb25zCiAgICBzZWxmLmxldmVscyA9IFtzZWxmLmxldmVsXzEsIHNlbGYubGV2ZWxfMiwgc2VsZi5sZXZlbF8zLCBzZWxmLmxldmVsXzQsIHNlbGYubGV2ZWxfNSwgc2VsZi5sZXZlbF82LCBzZWxmLmxldmVsXzddCiAgICAjTGV2ZWwgaW5kZXggYWxsb3dzIHRoZSBjbGFzcyB0byBkZXRlcm1pbmUgdGhlIGN1cnJlbnQgbGV2ZWwKICAgIHNlbGYubGV2ZWxfaW5kZXggPSAwCiAgICAjVGhlIEZPViBhcm91bmQgdGhlIG1pZHBvaW50IG9mIHRoZSBwbGF5ZXJzIG9udG9wIG9mIGl0IGJlaW5nIHNjYWxlZCB0byB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0aGVtCiAgICBzZWxmLnZpZXcgPSB2aWV3CiAgICAjM0QgTGlzdCBjb250YWluaW5nIHBvc2lzdGlvbnMgb2YgZ3VhcmRzIGZvciBzcGVjaWZpYyBsZXZlbHMKICAgIHNlbGYubGV2ZWxfZ3VhcmRfcG9zaXRpb25zID0gbGV2ZWxfZ3VhcmRfcG9zaXRpb25zCiAgICAjMkQgTGlzdCBjb250YWluaW5nIHBhdHJvbHMgb2YgZ3VhcmRzIGZvciBzcGVjaWZpYyBsZXZlbHMKICAgIHNlbGYubGV2ZWxfZ3VhcmRfcGF0cm9scyA9IGxldmVsX2d1YXJkX3BhdHJvbHMKICAgICMzRCBMaXN0IGNvbnRhaW5pbmcgcG9zaXRpb25zIG9mIGNvaW5zIGZvciBzcGVjaWZpYyBsZXZlbHMKICAgICNUaGUgbGV2ZWwgY29pbiBwb3NpdGlvbnMgYXJlIHJhbmRvbWx5IGdlbmVyYXRlZCBoZXJlCiAgICBzZWxmLmxldmVsX2NvaW5fcG9zaXRpb25zID0gW10KICAgIGZvciBhIGluIHJhbmdlKGxlbihjb2luX2NvdW50cykpOgogICAgICBjb2luX3Bvc2l0aW9ucyA9IFtdCiAgICAgIGZvciBiIGluIHJhbmdlKGNvaW5fY291bnRzW2FdKToKICAgICAgICBjb2luX3Bvc2l0aW9ucy5hcHBlbmQoW3JhbmRvbS5yYW5kaW50KDAsIGxldmVsX2RpbWVuc2lvbnNbYV1bMF0pLCByYW5kb20ucmFuZGludCgwLCBsZXZlbF9kaW1lbnNpb25zW2FdWzFdKV0pCiAgICAgIHNlbGYubGV2ZWxfY29pbl9wb3NpdGlvbnMuYXBwZW5kKGNvaW5fcG9zaXRpb25zKQogICAgI1RoaXMgaXMgZWFjaCBwbGF5ZXJzIGNhc2gsIG1lYXN1cmUgb2YgeW91ciBzdWNjZXNzIQogICAgc2VsZi5wbGF5ZXJfMV9jYXNoID0gMAogICAgc2VsZi5wbGF5ZXJfMl9jYXNoID0gMAogICAgI1N0b3JlZCBndWFyZCBjb2xsaXNpb25zIHVzZWQgZm9yIGdhbWUgb3ZlciBmdW5jdGlvbmFsaXR5CiAgICBzZWxmLmd1YXJkX2NvbGxpc2lvbnMgPSAwCiAgICAjUXVldWVkIHRpbWUgZm9yIGdhbWUgb3ZlciBpZiB0aGUgcGxheWVyIGRvZXMgbm90IGVzY2FwZSBoaXMgZ3Jhc3AhCiAgICBzZWxmLmdhbWVfb3Zlcl90aW1lID0gMAogIAogIGRlZiBjcmVhdGVfcm9vbShzZWxmLCByb29tLCByb29tX3gsIHJvb21feSwgdGlsZV9zaXplKTogI3Jvb21feCBhbmQgcm9vbV95IHNob3VsZCByZXByZXNlbnQgdGhlIGJvdHRvbSBsZWZ0IG9mIHRoZSByb29tCiAgICAjQ3JlYXRlIHRoZSB0aWxlbWFwc3RlIAogICAgZm9yIHkgaW4gcmFuZ2UoMCwgbGVuKHJvb20pKToKICAgICAgZm9yIHggaW4gcmFuZ2UoMCwgbGVuKHJvb21bMF0pKToKICAgICAgICBmb3IgaSBpbiByYW5nZShsZW4oc3RhdGljX3JlbmRlcl9wcmlvcml0aWVzKSk6CiAgICAgICAgICBpZihzdGF0aWNfcmVuZGVyX3ByaW9yaXRpZXMuaW5kZXgocm9vbVsteSAtIDFdW3hdKSA9PSBpKToKICAgICAgICAgICAgaWYocm9vbVsteSAtIDFdW3hdIGluIHN0YXRpY19ub19jb2xsaXNpb24pOgogICAgICAgICAgICAgIHNlbGYuc3RhdGljX25vX2NvbGxpc2lvbi5hcHBlbmQoYXJjYWRlLlNwcml0ZShzdGF0aWNfbm9fY29sbGlzaW9uW3Jvb21bLXkgLSAxXVt4XV0sIDEsIGNlbnRlcl94ID0geCAqIHRpbGVfc2l6ZSArIHJvb21feCwgY2VudGVyX3kgPSB5ICogdGlsZV9zaXplICsgcm9vbV95KSkKICAgICAgICAgICAgZWxpZihyb29tWy15IC0gMV1beF0gaW4gc3RhdGljX2NvbGxpc2lvbik6CiAgICAgICAgICAgICAgc2VsZi5zdGF0aWNfY29sbGlzaW9uLmFwcGVuZChhcmNhZGUuU3ByaXRlKHN0YXRpY19jb2xsaXNpb25bcm9vbVsteSAtIDFdW3hdXSwgMSwgY2VudGVyX3ggPSB4ICogdGlsZV9zaXplICsgcm9vbV94LCBjZW50ZXJfeSA9IHkgKiB0aWxlX3NpemUgKyByb29tX3kpKQogICAgICAgICAgICBlbGlmKHJvb21bLXkgLSAxXVt4XSBpbiBleGl0cyk6CiAgICAgICAgICAgICAgICBzZWxmLmV4aXRzLmFwcGVuZChhcmNhZGUuU3ByaXRlKGV4aXRzW3Jvb21bLXkgLSAxXVt4XV0sIDEsIGNlbnRlcl94ID0geCAqIHRpbGVfc2l6ZSArIHJvb21feCwgY2VudGVyX3kgPSB5ICogdGlsZV9zaXplICsgcm9vbV95KSkKICAgICAgICAgICAgZWxpZihyb29tWy15IC0gMV1beF0gaW4gZW50cmFuY2VzKToKICAgICAgICAgICAgICBzZWxmLmVudHJhbmNlcy5hcHBlbmQoYXJjYWRlLlNwcml0ZShlbnRyYW5jZXNbcm9vbVsteSAtIDFdW3hdXSwgMSwgY2VudGVyX3ggPSB4ICogdGlsZV9zaXplICsgcm9vbV94LCBjZW50ZXJfeSA9IHkgKiB0aWxlX3NpemUgKyByb29tX3kpKQoKIy0tSU5QVVQtLQogIGRlZiBvbl9rZXlfcHJlc3Moc2VsZiwga2V5LCBtb2RpZmllcnMpOgogICAgI1NldHMgcGxheWVycyBkaXJlY3Rpb24gYW5kIHNwZWVkIHRvIGl0cyBzZXQgc3BlZWQgaW4gaW5pdGlhbGl6YXRpb24gZGVwZW5kaW5nIG9uIGlucHV0CiAgICAjUExBWUVSIDEKICAgIGlmKGtleSA9PSBhcmNhZGUua2V5LlcpOgogICAgICBzZWxmLnBsYXllcl8xLmNoYW5nZV95ID0gc2VsZi5wbGF5ZXJfMS5zcGVlZAogICAgZWxpZihrZXkgPT0gYXJjYWRlLmtleS5BKToKICAgICAgc2VsZi5wbGF5ZXJfMS5jaGFuZ2VfeCA9IC1zZWxmLnBsYXllcl8xLnNwZWVkCiAgICBlbGlmKGtleSA9PSBhcmNhZGUua2V5LlMpOgogICAgICBzZWxmLnBsYXllcl8xLmNoYW5nZV95ID0gLXNlbGYucGxheWVyXzEuc3BlZWQKICAgIGVsaWYoa2V5ID09IGFyY2FkZS5rZXkuRCk6CiAgICAgIHNlbGYucGxheWVyXzEuY2hhbmdlX3ggPSBzZWxmLnBsYXllcl8xLnNwZWVkCiAgICAjUExBWUVSIDIKICAgIGlmKGtleSA9PSBhcmNhZGUua2V5LlVQKToKICAgICAgc2VsZi5wbGF5ZXJfMi5jaGFuZ2VfeSA9IHNlbGYucGxheWVyXzEuc3BlZWQKICAgIGVsaWYoa2V5ID09IGFyY2FkZS5rZXkuTEVGVCk6CiAgICAgIHNlbGYucGxheWVyXzIuY2hhbmdlX3ggPSAtc2VsZi5wbGF5ZXJfMS5zcGVlZAogICAgZWxpZihrZXkgPT0gYXJjYWRlLmtleS5ET1dOKToKICAgICAgc2VsZi5wbGF5ZXJfMi5jaGFuZ2VfeSA9IC1zZWxmLnBsYXllcl8xLnNwZWVkCiAgICBlbGlmKGtleSA9PSBhcmNhZGUua2V5LlJJR0hUKToKICAgICAgc2VsZi5wbGF5ZXJfMi5jaGFuZ2VfeCA9IHNlbGYucGxheWVyXzEuc3BlZWQKCiAgZGVmIG9uX2tleV9yZWxlYXNlKHNlbGYsIGtleSwgbW9kaWZpZXJzKToKICAgICNTdG9wcyB0aGUgcGxheWVycyBkZXBlbmRpbmcgb24ga2V5cyByZWxlYXNlZAogICAgI1BMQVlFUiAxCiAgICBpZihrZXkgPT0gYXJjYWRlLmtleS5XIG9yIGtleSA9PSBhcmNhZGUua2V5LlMpOgogICAgICBzZWxmLnBsYXllcl8xLmNoYW5nZV95ID0gMAogICAgZWxpZihrZXkgPT0gYXJjYWRlLmtleS5BIG9yIGtleSA9PSBhcmNhZGUua2V5LkQpOgogICAgICBzZWxmLnBsYXllcl8xLmNoYW5nZV94ID0gMAogICAgI1BMQVlFUiAyCiAgICBpZihrZXkgPT0gYXJjYWRlLmtleS5VUCBvciBrZXkgPT0gYXJjYWRlLmtleS5ET1dOKToKICAgICAgc2VsZi5wbGF5ZXJfMi5jaGFuZ2VfeSA9IDAKICAgIGVsaWYoa2V5ID09IGFyY2FkZS5rZXkuTEVGVCBvciBrZXkgPT0gYXJjYWRlLmtleS5SSUdIVCk6CiAgICAgIHNlbGYucGxheWVyXzIuY2hhbmdlX3ggPSAwCiMtLS0tLS0tLS0KCiMtLUxPR0lDLS0KICBkZWYgdXBkYXRlKHNlbGYsIGRlbHRhX3RpbWUpOgoKICAgICNVcGRhdGVzIHRoZSBjaGFyYWN0ZXJzCiAgICBzZWxmLnBsYXllcl8xLnVwZGF0ZSgpCiAgICBzZWxmLnBsYXllcl8yLnVwZGF0ZSgpCiAgICAKICAgICNTZXRzIHRoZSBjZW50ZXIgb2YgdGhlIHZpZXdwb3J0IHRvIGJlIGluYmV0d2VlbiB0aGUgcGxheWVycyBhbmQgc2NhbGUgdG8gdGhlIGRpc3RhbmNlIGJldHdlZW4gdGhlbSBjcmVhdGluZyBhIHpvb20gZWZmZWN0CiAgICAKICAgIG1pZHBvaW50ID0gKChzZWxmLnBsYXllcl8xLmNlbnRlcl94ICsgc2VsZi5wbGF5ZXJfMi5jZW50ZXJfeCkgLyAyLCAoc2VsZi5wbGF5ZXJfMS5jZW50ZXJfeSArIHNlbGYucGxheWVyXzIuY2VudGVyX3kpIC8gMikKICAgIGRpc3RhbmNlID0gYXJjYWRlLmdldF9kaXN0YW5jZV9iZXR3ZWVuX3Nwcml0ZXMoc2VsZi5wbGF5ZXJfMSwgc2VsZi5wbGF5ZXJfMikKICAgIGFyY2FkZS5zZXRfdmlld3BvcnQobWlkcG9pbnRbMF0gLSBkaXN0YW5jZSAtIHNlbGYudmlldywgbWlkcG9pbnRbMF0gKyBkaXN0YW5jZSArIHNlbGYudmlldywgbWlkcG9pbnRbMV0gLSBkaXN0YW5jZSAtIHNlbGYudmlldywgbWlkcG9pbnRbMV0gKyBkaXN0YW5jZSArIHNlbGYudmlldykKICAgIAogICAgCiAgICAjLS1DT0xMSVNJT05TLS0KICAgICNDaGVja3MgaWYgYm90aCBwbGF5ZXJzIGFyZSBjb2xsaWRpbmcgd2l0aCBhbnkgZXhpdHMsIGlmIHNvLCBzZXR1cCB0aGUgbmV4dCBsZXZlbAogICAgaWYoYXJjYWRlLmNoZWNrX2Zvcl9jb2xsaXNpb25fd2l0aF9saXN0KHNlbGYucGxheWVyXzEsIHNlbGYuZXhpdHMpIGFuZCBhcmNhZGUuY2hlY2tfZm9yX2NvbGxpc2lvbl93aXRoX2xpc3Qoc2VsZi5wbGF5ZXJfMiwgc2VsZi5leGl0cykpOgogICAgICBwcmludCgiUGxheWVyIDEgQ2FzaDoiICsgc3RyKHNlbGYucGxheWVyXzFfY2FzaCkgKyAiXG4iICsgIlBsYXllciAyIENhc2g6Iisgc3RyKHNlbGYucGxheWVyXzJfY2FzaCkgKyAiXG4iKQogICAgICBzZWxmLmxldmVsc1tzZWxmLmxldmVsX2luZGV4ICsgMV0oKQogICAgI0NoZWNrcyBpZiBib3RoIHBsYXllcnMgYXJlIGNvbGxpZGluZyB3aXRoIGFueSBlbnRyYW5jZXMsIGlmIHNvIHNldHVwIHRoZSBwcmV2aW91cyBsZXZlbAogICAgaWYoYXJjYWRlLmNoZWNrX2Zvcl9jb2xsaXNpb25fd2l0aF9saXN0KHNlbGYucGxheWVyXzEsIHNlbGYuZW50cmFuY2VzKSBhbmQgYXJjYWRlLmNoZWNrX2Zvcl9jb2xsaXNpb25fd2l0aF9saXN0KHNlbGYucGxheWVyXzIsIHNlbGYuZW50cmFuY2VzKSk6CiAgICAgIHByaW50KCJQbGF5ZXIgMSBDYXNoOiIgKyBzdHIoc2VsZi5wbGF5ZXJfMV9jYXNoLTEpICsiXG4iLCJQbGF5ZXIgMiBDYXNoOiIrIHN0cihzZWxmLnBsYXllcl8yX2Nhc2gpICsiXG4iKQogICAgICBzZWxmLmxldmVsc1tzZWxmLmxldmVsX2luZGV4IC0gMV0oKQogICAgI0Rlc3Ryb3lzIGFueSBjb2lucyBjb2xsaWRpbmcgd2l0aCBwbGF5ZXJfMSBhcyB3ZWxsIGFzIGFkZGluZyB0byBwbGF5ZXJfMSdzIGNhc2gKICAgIHBsYXllcl8xX2NvaW5fY29sbGlzaW9ucyA9IGFyY2FkZS5jaGVja19mb3JfY29sbGlzaW9uX3dpdGhfbGlzdChzZWxmLnBsYXllcl8xLCBzZWxmLmNvaW5zKQogICAgZm9yIGkgaW4gcGxheWVyXzFfY29pbl9jb2xsaXNpb25zOgogICAgICBzZWxmLmxldmVsX2NvaW5fcG9zaXRpb25zW3NlbGYubGV2ZWxfaW5kZXhdLnJlbW92ZShbaS5jZW50ZXJfeCwgaS5jZW50ZXJfeV0pCiAgICAgIHNlbGYuY29pbnMucmVtb3ZlKGkpCiAgICAgIHNlbGYucGxheWVyXzFfY2FzaCArPSAxCiAgICAjRGVzdHJveXMgYW55IGNvaW5zIGNvbGxpZGluZyB3aXRoIHBsYXllcl8yIGFzIHdlbGwgYXMgYWRkaW5nIHRvIHBsYXllcl8yJ3MgY2FzaAogICAgcGxheWVyXzJfY29pbl9jb2xsaXNpb25zID0gYXJjYWRlLmNoZWNrX2Zvcl9jb2xsaXNpb25fd2l0aF9saXN0KHNlbGYucGxheWVyXzIsIHNlbGYuY29pbnMpCiAgICBmb3IgaSBpbiBwbGF5ZXJfMl9jb2luX2NvbGxpc2lvbnM6CiAgICAgIHNlbGYubGV2ZWxfY29pbl9wb3NpdGlvbnNbc2VsZi5sZXZlbF9pbmRleF0ucmVtb3ZlKFtpLmNlbnRlcl94LCBpLmNlbnRlcl95XSkKICAgICAgc2VsZi5jb2lucy5yZW1vdmUoaSkKICAgICAgc2VsZi5wbGF5ZXJfMl9jYXNoICs9IDEKICAgICNVcGRhdGUgR3VhcmRzIGFuZCBkZXRlY3QgY29sbGlzaW9ucwogICAgY29sbGlzaW9uID0gRmFsc2UKICAgIGZvciBpIGluIHNlbGYuZ3VhcmRzOgogICAgICBpLmd1YXJkX3VwZGF0ZSgpCiAgICAgIGlmKGkuYWxlcnRlZCA9PSBUcnVlKToKICAgICAgICBpZihhcmNhZGUuZ2V0X2Rpc3RhbmNlX2JldHdlZW5fc3ByaXRlcyhzZWxmLnBsYXllcl8xLCBpKSA8IGFyY2FkZS5nZXRfZGlzdGFuY2VfYmV0d2Vlbl9zcHJpdGVzKHNlbGYucGxheWVyXzIsIGkpKToKICAgICAgICAgIGkudGFyZ2V0ID0gW3NlbGYucGxheWVyXzEuY2VudGVyX3gsIHNlbGYucGxheWVyXzEuY2VudGVyX3ldCiAgICAgICAgZWxzZToKICAgICAgICAgIGkudGFyZ2V0ID0gW3NlbGYucGxheWVyXzIuY2VudGVyX3gsIHNlbGYucGxheWVyXzIuY2VudGVyX3ldCgogICAgICBpZihhcmNhZGUuY2hlY2tfZm9yX2NvbGxpc2lvbihzZWxmLnBsYXllcl8xLCBpKSk6CiAgICAgICAgaS5hbGVydCgpCiAgICAgICAgY29sbGlzaW9uID0gVHJ1ZQogICAgICBpZihhcmNhZGUuY2hlY2tfZm9yX2NvbGxpc2lvbihzZWxmLnBsYXllcl8yLCBpKSk6CiAgICAgICAgaS5hbGVydCgpCiAgICAgICAgY29sbGlzaW9uID0gVHJ1ZQoKICAgIGlmKGNvbGxpc2lvbiA9PSBUcnVlKToKICAgICAgc2VsZi5ndWFyZF9jb2xsaXNpb25zICs9IDEKICAgICAgaWYoc2VsZi5ndWFyZF9jb2xsaXNpb25zID09IDEpOgogICAgICAgIHNlbGYuZ2FtZV9vdmVyX3RpbWUgPSB0aW1lLnRpbWUoKSArIDIKICAgIGVsc2U6CiAgICAgIHNlbGYuZ3VhcmRfY29sbGlzaW9ucyA9IDAKICAgICAgc2VsZi5nYW1lX292ZXJfdGltZSA9IDAKCiAgICBpZihzZWxmLmdhbWVfb3Zlcl90aW1lICE9IDApOgogICAgICBpZih0aW1lLnRpbWUoKSA+PSBzZWxmLmdhbWVfb3Zlcl90aW1lKToKICAgICAgICBzZWxmLmdhbWVfb3ZlcigpCiMtLS0tLS0tLS0KIy0tUkVOREVSSU5HLS0KICBkZWYgb25fZHJhdyhzZWxmKToKICAgIGFyY2FkZS5zdGFydF9yZW5kZXIoKQogICAgc2VsZi5zdGF0aWNfbm9fY29sbGlzaW9uLmRyYXcoKQogICAgc2VsZi5zdGF0aWNfY29sbGlzaW9uLmRyYXcoKQogICAgc2VsZi5leGl0cy5kcmF3KCkKICAgIHNlbGYuZW50cmFuY2VzLmRyYXcoKQogICAgc2VsZi5jb2lucy5kcmF3KCkKICAgIGZvciBpIGluIHNlbGYuZ3VhcmRzOgogICAgICBpLmRyYXcoKQogICAgc2VsZi5wbGF5ZXJfMS5kcmF3KCkKICAgIHNlbGYucGxheWVyXzIuZHJhdygpCiAgICAKIy0tLS0tLS0tLS0tLS0KI0NyZWF0aW5nIHRoZSBnYW1lLCBwYXJhbWV0ZXJzOiAKI3dpbmRvdyB3aWR0aCwgd2luZG93IGhlaWdodCwgd2luZG93IHRpdGxlLCB2aWV3IGFyb3VuZCBwbGF5ZXJzLCAzRCBsaXN0ICgxc3QgZGltZW5zaW9uOiBsZXZlbHMsIDJuZCBkaW1lbnNpb246IGd1YXJkIHBvc2l0aW9ucyBmb3IgdGhlIGNvcnJyZXNwb25kaW5nIGxldmVsLCAzcmQgZGltZW5zaW9uOiB0aGUgeCBhbmQgeSBjb21wb25lbnQgb2YgdGhlIHBvc2lzdGlvbiksIDJEIGxpc3QgKDFzdCBkaW1lbnNpb246IGxldmVscywgZ3VhcmQgcGF0cm9scyBmb3IgdGhlIGNvcnJlc3BvbmRpbmcgbGV2ZWwpLCBsaXN0IChjb2luIGNvaW50IGZvciBlYWNoIGxldmVsKSwgMkQgbGlzdCAoMXN0IGRpbWVuc2lvbjogbGV2ZWwsIDJuZCBkaW1lbnNpb246IGxldmVsIHggYW5kIHkgYm91bmRhcmllcyBmb3IgdGhlIHJhbmRvbSBjb2luIHBvc2l0aW9uaW5nKQpnYW1lID0gR2FtZSg4MDAsIDgwMCwgIlRvd2VyIEhlaXN0IiwgMTAwLCAKW1tbNjIsIDI2OF1dLAogW1szMTEsIDM4NF0sIFs3MS41LCA0NTZdLCBbMzk2LCAzMDJdXSwgW1syNTkuNSwgMTQ2XSwgWzUwMS41LCAxNzhdLCBbMzU3LjUsIDI2Nl0sIFs1NzUuNSwgMzQ0XSwgWzY3Ny41LCAyOTZdLCBbNTcxLjUsIDUyMF1dLApbWzc3LjUsIDMyXSwgWzI2MCwgNTIwXSwgWzI1MS41LCAzMl0sIFszNDkuNSw1MjBdLCBbNDQ1LjUsIDMyXSwgWzU0MC41LDUyMF0sIFs2MzguNSwgMzJdLFs3MzIuNSwgNTIwXV0sIFtbMTkyLjUsIDUyXSwgWzcxLjUsIDY4XSwgWzcxLjUsMTgwXSwgWzU1MSwgNDRdLCBbODQwLjUsIDIwOF1dLCBbWzE0MCwgNDhdLFsxNDAsIDcyXSwgWzE0MCwgOTZdLCBbMTQwLCAxMjBdLCBbODIwLCA0OF0sIFs4MjAsIDcyXSwgWzgyMCwgOTZdLCBbODIwLCAxMjBdXSwgW1sxMzIsIDQwXSxbMTMyLCA4OF0sIFsxMzIsIDEzNl0sIFsxMzIsMjMwXSwgWzEzMiwyNzhdLCBbMTMyLDMyNl1dXSwKW1twYXRyb2xfMV0sIApbcGF0cm9sXzMsIHBhdHJvbF8yLCBwYXRyb2xfM10sIApbcGF0cm9sXzIsIHBhdHJvbF8yLCBwYXRyb2xfMiwgcGF0cm9sXzIsIHBhdHJvbF8yLCBwYXRyb2xfMl0sIApbcGF0cm9sXzMsIHBhdHJvbF8zLCBwYXRyb2xfMywgcGF0cm9sXzMsIHBhdHJvbF8zLCBwYXRyb2xfMywgcGF0cm9sXzMsIHBhdHJvbF8zXSwgCltwYXRyb2xfMSwgcGF0cm9sXzQsIHBhdHJvbF80LCBwYXRyb2xfNCwgcGF0cm9sXzVdLCAKW3BhdHJvbF82LCBwYXRyb2xfNiwgcGF0cm9sXzYsIHBhdHJvbF82LCBwYXRyb2xfNywgcGF0cm9sXzcsIHBhdHJvbF83LCBwYXRyb2xfN10sIApbcGF0cm9sXzYsIHBhdHJvbF82LCBwYXRyb2xfNiwgcGF0cm9sXzYsIHBhdHJvbF82LCBwYXRyb2xfNl1dLApbMTAsIDEwLCAxMCwgMTAsIDEwLCAxMCwgMTBdLCAKW1s5MjUsIDU1MF0sIFs5MjUsIDU1MF0sIFs5MjUsIDU1MF0sIFs5MjUsIDU1MF0sIFs5MjUsIDU1MF0sIFs5MjUsIDU1MF0sIFs5MjUsIDU1MF1dKQpnYW1lLmxldmVsc1swXSgpCmFyY2FkZS5ydW4oKQ=="},"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
#--IMPORTS--
import arcade
import os
import random
import time
import math
import rooms
#-----------
#Dictionary containing directories of tiles that don't have collision
static_no_collision = {"f1":"images/floors/floor 1.png", "f2":"images/floors/floor 2.png", "f3":"images/floors/floor 3.png", "f4":"images/floors/floor 4.png", "f5":"images/floors/floor 5.png"}
#Dictionary containing directories of tiles that have collision
static_collision = {"wh1":"images/walls/wall horizontal 1.png", "wv1":"images/walls/wall vertical 1.png", "cbl1":"images/walls/corner bottom left 1.png", "cbr1":"images/walls/corner bottom right 1.png", "ctl1":"images/walls/corner top left 1.png", "ctr1":"images/walls/corner top right 1.png","c1":"images/walls/connector 1.png"}
#Dictionary containing directories of exits
exits = {"ex1":"images/misc/exit 1.png"}
#Dictionary containing directories of entrances
entrances = {"en1":"images/misc/entrance 1.png"}
#List of tile corresponding strings in order of render priority, for example 'wh1' will be rendered on top of the following items
static_render_priorities = ["wh1", "wv1", "cbl1", "cbr1", "ctl1", "ctr1", "c1", "f1", "f2", "f3", "f4", "f5", "ex1", "en1", ""]
#List containing all the directories for player 1 textures, in the following order;
#standing left folder, standing right folder, walking left folder, walking right folder, walking up folder, walking down folder.
#It automatically incorperates the files in these folders for player 1 animations.
player_1_texture_directories = ["images/player_1_anims/stand left textures", "images/player_1_anims/stand right textures", "images/player_1_anims/walk left textures", "images/player_1_anims/walk right textures", "images/player_1_anims/walk up textures", "images/player_1_anims/walk down textures"]

#List containing all the directories for player 2 textures, in the following order; 
#standing left folder, standing right folder, walking left folder, walking right folder, walking up folder, walking down folder.
#It automatically incorperates the files in these folders for player 2 animations
player_2_texture_directories = ["images/player_2_anims/stand left textures", "images/player_2_anims/stand right textures", "images/player_2_anims/walk left textures", "images/player_2_anims/walk right textures", "images/player_2_anims/walk up textures", "images/player_2_anims/walk down textures"]

#List containing all the directories for the guard textures, in the following order;
#standing left folder, standing right folder, walking left folder, walking right folder, walking up folder, walking down folder, alerted standing left folder, alerted standing right folder, alerted walking left folder, alerted walking right folder, alerted walking up folder, alerted walking down folder.
#It automatically incorperates the files in these folders for the guard animations
guard_texture_directories = ["images/guard/walk left textures", "images/guard/walk right textures", "images/guard/walk left textures", "images/guard/walk right textures", "images/guard/walk up textures", "images/guard/walk down textures", "images/guard/alerted walk left textures", "images/guard/alerted walk right textures", "images/guard/alerted walk left textures", "images/guard/alerted walk right textures", "images/guard/alerted walk up textures", "images/guard/alerted walk down textures"]

#Dictionary containing directories of coins
special = {"coin 1":"images/misc/coin 1.png"}

#A patrol controls a guard, each item is a instruction, with the items within representing;
#X direction, Y direction, time until next instruction,
#It loops through the patrol
#For example the first patrol makes him walk up for 3 seconds, walk right for 3 seconds, walk down for 3 seconds, walk left for 3 seconds, and then back to the begining and so on.
patrol_1 = [[0, 1, 0.8], [1, 0, 12], [0, -1, 0.8], [-1, 0, 12]]
patrol_2 = [[1, 0, 1.5], [0,1, 1.5],[-1, 0,1.5],[0,-1, 1.5]]
patrol_3 = [[1,0, 4], [-1, 0, 4]]
patrol_4 = [[0, 1, 4], [0, -1, 4]]
patrol_5 = [[0, 1, 2], [0, -1, 2]]
patrol_6 = [[-1, 0, 12],[1,0, 12]]
patrol_7 = [[1, 0, 12], [-1, 0, 12]]

#Loads the textures into a 2D list from the directories in the list on line 30 in the same order
player_1_textures = []
for a in range(len(player_1_texture_directories)):
  #Gets the filenames of the files in the directory
  files = os.listdir(player_1_texture_directories[a])
  textures = [] #This will be the second dimension to the 2D list
  #Loops through each filename in the directory
  for b in range(len(files)):
    #Adds a loaded from the directory made by concatinating "/" and the filename to the original directory
    textures.append(arcade.load_texture(player_1_texture_directories[a] + "/" + files[b]))
  #Adds all the directories textures to the original list hence a 2D list
  player_1_textures.append(textures)

#Loads the textures into a 2D list from the directories in the same way as for player 1
player_2_textures = []
for a in range(len(player_2_texture_directories)):
  files = os.listdir(player_2_texture_directories[a])
  textures = []
  for b in range(len(files)):
    textures.append(arcade.load_texture(player_2_texture_directories[a] + "/" + files[b]))
  player_2_textures.append(textures)

#Loads the textures into a 2D list from the directories in the same way as for player 1 and player 2
guard_textures = []
for a in range(len(guard_texture_directories)):
  files = os.listdir(guard_texture_directories[a])
  textures = []
  for b in range(len(files)):
    textures.append(arcade.load_texture(guard_texture_directories[a] + "/" + files[b]))
  guard_textures.append(textures)

#Class for any character with animations such as the players and guards
class Character(arcade.AnimatedWalkingSprite):
  def __init__(self, scale, stand_left_textures, stand_right_textures, walk_left_textures, walk_right_textures, walk_up_textures, walk_down_textures, texture_change_distance, collisions, speed):
    super().__init__(scale)
    #For some reason although in arcade it sets the _texture in initialization sometimes it requires some help
    self._texture = stand_right_textures[0]
    #Set the parent classes textures allowing it to proccess animations
    self.stand_left_textures = stand_left_textures
    self.stand_right_textures = stand_right_textures
    self.walk_left_textures = walk_left_textures
    self.walk_right_textures = walk_right_textures
    self.walk_up_textures = walk_up_textures
    self.walk_down_textures = walk_down_textures
    #Set the parent classes texture change distance, this determins how much distance before a the current texture should be switched
    self.texture_change_distance = texture_change_distance
    #Create physics (collision and movement) for the character
    self.physics = arcade.PhysicsEngineSimple(self, collisions)
    #Set the classes speed
    self.speed = speed
    self.game_over_collision = False
    self.game_over_time = 0
  def setup(self, x, y):
    #Place the character at specified coordinates
    self.center_x = x
    self.center_y = y
  #Updates the character however needs to be externally called
  def update(self):
    self.update_animation()
    self.physics.update()
   

#Class for a guard, a fairly complex 'AI' although it is just a algorithm, no deep learning
class Guard(Character):
  def __init__(self, scale, stand_left_textures, stand_right_textures, walk_left_textures, walk_right_textures, walk_up_textures, walk_down_textures, alerted_stand_left_textures, alerted_stand_right_textures, alerted_walk_left_textures, alerted_walk_right_textures, alerted_walk_up_textures, alerted_walk_down_textures, texture_change_distance, collisions, speed, patrol, alert_timer):
    super().__init__(scale, stand_left_textures, stand_right_textures, walk_left_textures, walk_right_textures, walk_up_textures, walk_down_textures, texture_change_distance, collisions, speed)
    #Store textures as they will need to be used again, the underscore (_) is required to differentiate it from the parent classes textures
    self._stand_left_textures = stand_left_textures
    self._stand_right_textures = stand_right_textures
    self._walk_left_textures = walk_left_textures
    self._walk_right_textures = walk_right_textures
    self._walk_up_textures = walk_up_textures
    self._walk_down_textures = walk_down_textures
    #Store alerted textures as they will need to be used again
    self.alerted_stand_left_textures = alerted_stand_left_textures
    self.alerted_stand_right_textures = alerted_stand_right_textures
    self.alerted_walk_left_textures = alerted_walk_left_textures
    self.alerted_walk_right_textures = alerted_walk_right_textures
    self.alerted_walk_up_textures = alerted_walk_up_textures
    self.alerted_walk_down_textures = alerted_walk_down_textures
    #Set the classes patrol
    self.patrol = patrol
    #Set the classes alert_timer, this is how long the guard will maintain alerted before losing interest
    self.alert_timer = alert_timer

  def guard_setup(self, x, y):
    #Call the parent classes setup to place the guard
    self.setup(x, y)
    #Set the direction of movement to be still
    self.dir_x = 0
    self.dir_y = 0
    #Set the patrol index, the patrol index is the index determining which instruction within the patrol is in use
    self.patrol_index = 0
    #Set the change time, change time is the exact time at which the guard should switch instruction within the patrol
    self.change_time = time.time() + self.patrol[0][2]
    #Set the alert, determines whether the guard is alerted
    self.alerted = False
    #Alert time is the exact time in which the guard should become un-alert
    self.alert_time = 0
    #Set the target, target is the point the guard will target when alterted, this is most likely a players position
    self.target = [0, 0]
  
  def guard_update(self):
    #If alerted then check whether alert is still valid, if true follow target, if false them become un-alert
    if(self.alerted):
      if(time.time() >= self.alert_time):
        self.un_alert()
      else:
        #Target is set externally to the nearest player
        dest_x = self.target[0]
        dest_y = self.target[1]
        #Calculate the angle the from the from the target to the guard 
        x_diff = dest_x - self.center_x
        y_diff = dest_y - self.center_y
        angle = math.atan2(y_diff, x_diff)
        #Then using the angle we can calculate the neccesary direction
        self.change_x = math.cos(angle) * self.speed
        self.change_y = math.sin(angle) * self.speed
    #If not alert then follow the patrol
    else:
      #If patrol instruction time has been reached then switch to next instruction
      if(time.time() >= self.change_time):
        if(self.patrol_index == len(self.patrol) - 1):
          self.patrol_index = 0
        else: 
          self.patrol_index += 1
        self.dir_x = self.patrol[self.patrol_index][0]
        self.dir_y = self.patrol[self.patrol_index][1]
        self.change_time = time.time() + self.patrol[self.patrol_index][2]
      #Move the guard
      self.change_x = self.dir_x * self.speed
      self.change_y = self.dir_y * self.speed
    #In the character class, this updates the characters animations and physics
    self.update()
  
  def alert(self):
    #Set to be alert
    self.alerted = True
    #Set alert termination time
    self.alert_time = time.time() + self.alert_timer
    #Switch textures to the alert variation
    self.stand_left_textures = self.alerted_stand_left_textures
    self.stand_right_textures = self.alerted_stand_right_textures
    self.walk_left_textures = self.alerted_walk_left_textures
    self.walk_right_textures = self.alerted_walk_right_textures
    self.walk_up_textures = self.alerted_walk_up_textures
    self.walk_down_textures = self.alerted_walk_down_textures
  
  def un_alert(self):
    #Set to be un-alert
    self.alerted = False
    #Set textures to the un-alert variation
    self.stand_left_textures = self._stand_left_textures
    self.stand_right_textures = self._stand_right_textures
    self.walk_left_textures = self._walk_left_textures
    self.walk_right_textures = self._walk_right_textures
    self.walk_up_textures = self._walk_up_textures
    self.walk_down_textures = self._walk_down_textures

#This is the main class, it controlls the levels, room generation, coins, controlls the players and handles input, logic, rendering for the game loop
class Game(arcade.Window):
  #Setup required for all levels
  def setup(self):
    #An arcade.SpriteList() is a list of sprites that has extra functionality and can be rendered easily and performantly
    #Setup all tiles that the characters can move through
    self.static_no_collision = arcade.SpriteList()
    #Setup all tiles that the characters cannot move through
    self.static_collision = arcade.SpriteList()
    #Setup all tiles that moves the characters to the next room/level
    self.exits = arcade.SpriteList()
    #Setup all tiles that moves the characters to the previous room
    self.entrances = arcade.SpriteList()

    self.coins = arcade.SpriteList()

    #Create a guard for each position passed in initialization and assign them the corresponding patrol passed in initialization
    self.guards = []
    for i in range(len(self.level_guard_positions[self.level_index])):
       guard = Guard(1, guard_textures[0], guard_textures[1], guard_textures[2], guard_textures[3], guard_textures[4], guard_textures[5], guard_textures[6], guard_textures[7], guard_textures[8], guard_textures[9], guard_textures[10], guard_textures[11], 5, self.static_collision, 1.25, self.level_guard_patrols[self.level_index][i], 6)
       guard.guard_setup(self.level_guard_positions[self.level_index][i][0], self.level_guard_positions[self.level_index][i][1])
       self.guards.append(guard)
    #Create a coins 
    for i in range(len(self.level_coin_positions[self.level_index])):
      self.coins.append(arcade.Sprite(special["coin 1"], center_x = self.level_coin_positions[self.level_index][i][0], center_y = self.level_coin_positions[self.level_index][i][1]))
    #sets up all the textures for player1
    self.player_1 = Character(1, player_1_textures[0], player_1_textures[1], player_1_textures[2], player_1_textures[3], player_1_textures[4], player_1_textures[5], 5, self.static_collision, 2)
    #sets up all the textures for player1
    self.player_2 = Character(1, player_2_textures[0], player_2_textures[1], player_2_textures[2], player_2_textures[3], player_2_textures[4], player_2_textures[5], 5, self.static_collision, 2)

  #Using fuctions to setup levels as a pose to classes although lengthy, its simpler and easier to cator to a specific level
  def level_1(self):
    #Sets the level index to allow the class the know the current level,
    #Its being set here instead of being added and subtracted to when colliding with entrances and exits to avoid misalignment
    self.level_index = 0
    #Calls the default setup
    self.setup()
    #Sets up the sprites for the room
    self.create_room(rooms.room_1, 0, 0, 24)
    #Sets up the players at specified coordinates
    self.player_1.setup(100, 100)
    self.player_2.setup(100, 100)

  def level_2(self):
    self.level_index = 1
    self.setup()
    self.create_room(rooms.room_2, 0, 0, 24)
    self.player_1.setup(100, 100)
    self.player_2.setup(100, 100)

  def level_3(self):
    self.level_index = 2
    self.setup()
    self.create_room(rooms.room_3, 0, 0, 24)
    self.player_1.setup(100, 100)
    self.player_2.setup(100, 100)
 
  def level_4(self):
    self.level_index = 3
    self.setup()
    self.create_room(rooms.room_4, 0, 0, 24)
    self.player_1.setup(100, 100)
    self.player_2.setup(100, 100)

  def level_5(self):
    self.level_index = 4
    self.setup()
    self.create_room(rooms.room_5, 0, 0, 24)
    self.player_1.setup(100, 100)
    self.player_2.setup(100, 100)

  def level_6(self):
    self.level_index = 5
    self.setup()
    self.create_room(rooms.room_6, 0, 0, 24)
    self.player_1.setup(100, 100)
    self.player_2.setup(100, 100)

  def level_7(self):
    self.level_index = 6
    self.setup()
    self.create_room(rooms.room_7, 0, 0, 24)
    self.player_1.setup(100, 100)
    self.player_2.setup(100, 100)



  def game_over(self):
    #Set all the variables to their null states
    self.static_no_collision = arcade.SpriteList()
    self.static_collision = arcade.SpriteList()
    self.exits = arcade.SpriteList()
    self.entrances = arcade.SpriteList()
    self.coins = arcade.SpriteList()
    self.guards = []

  def __init__(self, width, height, title, view, level_guard_positions, level_guard_patrols, coin_counts, level_dimensions):
    #Initialize the parent class (a window)
    super().__init__(width, height, title)
    #List of our level functions
    self.levels = [self.level_1, self.level_2, self.level_3, self.level_4, self.level_5, self.level_6, self.level_7]
    #Level index allows the class to determine the current level
    self.level_index = 0
    #The FOV around the midpoint of the players ontop of it being scaled to the distance between them
    self.view = view
    #3D List containing posistions of guards for specific levels
    self.level_guard_positions = level_guard_positions
    #2D List containing patrols of guards for specific levels
    self.level_guard_patrols = level_guard_patrols
    #3D List containing positions of coins for specific levels
    #The level coin positions are randomly generated here
    self.level_coin_positions = []
    for a in range(len(coin_counts)):
      coin_positions = []
      for b in range(coin_counts[a]):
        coin_positions.append([random.randint(0, level_dimensions[a][0]), random.randint(0, level_dimensions[a][1])])
      self.level_coin_positions.append(coin_positions)
    #This is each players cash, measure of your success!
    self.player_1_cash = 0
    self.player_2_cash = 0
    #Stored guard collisions used for game over functionality
    self.guard_collisions = 0
    #Queued time for game over if the player does not escape his grasp!
    self.game_over_time = 0
  
  def create_room(self, room, room_x, room_y, tile_size): #room_x and room_y should represent the bottom left of the room
    #Create the tilemapste 
    for y in range(0, len(room)):
      for x in range(0, len(room[0])):
        for i in range(len(static_render_priorities)):
          if(static_render_priorities.index(room[-y - 1][x]) == i):
            if(room[-y - 1][x] in static_no_collision):
              self.static_no_collision.append(arcade.Sprite(static_no_collision[room[-y - 1][x]], 1, center_x = x * tile_size + room_x, center_y = y * tile_size + room_y))
            elif(room[-y - 1][x] in static_collision):
              self.static_collision.append(arcade.Sprite(static_collision[room[-y - 1][x]], 1, center_x = x * tile_size + room_x, center_y = y * tile_size + room_y))
            elif(room[-y - 1][x] in exits):
                self.exits.append(arcade.Sprite(exits[room[-y - 1][x]], 1, center_x = x * tile_size + room_x, center_y = y * tile_size + room_y))
            elif(room[-y - 1][x] in entrances):
              self.entrances.append(arcade.Sprite(entrances[room[-y - 1][x]], 1, center_x = x * tile_size + room_x, center_y = y * tile_size + room_y))

#--INPUT--
  def on_key_press(self, key, modifiers):
    #Sets players direction and speed to its set speed in initialization depending on input
    #PLAYER 1
    if(key == arcade.key.W):
      self.player_1.change_y = self.player_1.speed
    elif(key == arcade.key.A):
      self.player_1.change_x = -self.player_1.speed
    elif(key == arcade.key.S):
      self.player_1.change_y = -self.player_1.speed
    elif(key == arcade.key.D):
      self.player_1.change_x = self.player_1.speed
    #PLAYER 2
    if(key == arcade.key.UP):
      self.player_2.change_y = self.player_1.speed
    elif(key == arcade.key.LEFT):
      self.player_2.change_x = -self.player_1.speed
    elif(key == arcade.key.DOWN):
      self.player_2.change_y = -self.player_1.speed
    elif(key == arcade.key.RIGHT):
      self.player_2.change_x = self.player_1.speed

  def on_key_release(self, key, modifiers):
    #Stops the players depending on keys released
    #PLAYER 1
    if(key == arcade.key.W or key == arcade.key.S):
      self.player_1.change_y = 0
    elif(key == arcade.key.A or key == arcade.key.D):
      self.player_1.change_x = 0
    #PLAYER 2
    if(key == arcade.key.UP or key == arcade.key.DOWN):
      self.player_2.change_y = 0
    elif(key == arcade.key.LEFT or key == arcade.key.RIGHT):
      self.player_2.change_x = 0
#---------

#--LOGIC--
  def update(self, delta_time):

    #Updates the characters
    self.player_1.update()
    self.player_2.update()
    
    #Sets the center of the viewport to be inbetween the players and scale to the distance between them creating a zoom effect
    
    midpoint = ((self.player_1.center_x + self.player_2.center_x) / 2, (self.player_1.center_y + self.player_2.center_y) / 2)
    distance = arcade.get_distance_between_sprites(self.player_1, self.player_2)
    arcade.set_viewport(midpoint[0] - distance - self.view, midpoint[0] + distance + self.view, midpoint[1] - distance - self.view, midpoint[1] + distance + self.view)
    
    
    #--COLLISIONS--
    #Checks if both players are colliding with any exits, if so, setup the next level
    if(arcade.check_for_collision_with_list(self.player_1, self.exits) and arcade.check_for_collision_with_list(self.player_2, self.exits)):
      print("Player 1 Cash:" + str(self.player_1_cash) + "\n" + "Player 2 Cash:"+ str(self.player_2_cash) + "\n")
      self.levels[self.level_index + 1]()
    #Checks if both players are colliding with any entrances, if so setup the previous level
    if(arcade.check_for_collision_with_list(self.player_1, self.entrances) and arcade.check_for_collision_with_list(self.player_2, self.entrances)):
      print("Player 1 Cash:" + str(self.player_1_cash-1) +"\n","Player 2 Cash:"+ str(self.player_2_cash) +"\n")
      self.levels[self.level_index - 1]()
    #Destroys any coins colliding with player_1 as well as adding to player_1's cash
    player_1_coin_collisions = arcade.check_for_collision_with_list(self.player_1, self.coins)
    for i in player_1_coin_collisions:
      self.level_coin_positions[self.level_index].remove([i.center_x, i.center_y])
      self.coins.remove(i)
      self.player_1_cash += 1
    #Destroys any coins colliding with player_2 as well as adding to player_2's cash
    player_2_coin_collisions = arcade.check_for_collision_with_list(self.player_2, self.coins)
    for i in player_2_coin_collisions:
      self.level_coin_positions[self.level_index].remove([i.center_x, i.center_y])
      self.coins.remove(i)
      self.player_2_cash += 1
    #Update Guards and detect collisions
    collision = False
    for i in self.guards:
      i.guard_update()
      if(i.alerted == True):
        if(arcade.get_distance_between_sprites(self.player_1, i) < arcade.get_distance_between_sprites(self.player_2, i)):
          i.target = [self.player_1.center_x, self.player_1.center_y]
        else:
          i.target = [self.player_2.center_x, self.player_2.center_y]

      if(arcade.check_for_collision(self.player_1, i)):
        i.alert()
        collision = True
      if(arcade.check_for_collision(self.player_2, i)):
        i.alert()
        collision = True

    if(collision == True):
      self.guard_collisions += 1
      if(self.guard_collisions == 1):
        self.game_over_time = time.time() + 2
    else:
      self.guard_collisions = 0
      self.game_over_time = 0

    if(self.game_over_time != 0):
      if(time.time() >= self.game_over_time):
        self.game_over()
#---------
#--RENDERING--
  def on_draw(self):
    arcade.start_render()
    self.static_no_collision.draw()
    self.static_collision.draw()
    self.exits.draw()
    self.entrances.draw()
    self.coins.draw()
    for i in self.guards:
      i.draw()
    self.player_1.draw()
    self.player_2.draw()
    
#-------------
#Creating the game, parameters: 
#window width, window height, window title, view around players, 3D list (1st dimension: levels, 2nd dimension: guard positions for the corrresponding level, 3rd dimension: the x and y component of the posistion), 2D list (1st dimension: levels, guard patrols for the corresponding level), list (coin coint for each level), 2D list (1st dimension: level, 2nd dimension: level x and y boundaries for the random coin positioning)
game = Game(800, 800, "Tower Heist", 100, 
[[[62, 268]],
 [[311, 384], [71.5, 456], [396, 302]], [[259.5, 146], [501.5, 178], [357.5, 266], [575.5, 344], [677.5, 296], [571.5, 520]],
[[77.5, 32], [260, 520], [251.5, 32], [349.5,520], [445.5, 32], [540.5,520], [638.5, 32],[732.5, 520]], [[192.5, 52], [71.5, 68], [71.5,180], [551, 44], [840.5, 208]], [[140, 48],[140, 72], [140, 96], [140, 120], [820, 48], [820, 72], [820, 96], [820, 120]], [[132, 40],[132, 88], [132, 136], [132,230], [132,278], [132,326]]],
[[patrol_1], 
[patrol_3, patrol_2, patrol_3], 
[patrol_2, patrol_2, patrol_2, patrol_2, patrol_2, patrol_2], 
[patrol_3, patrol_3, patrol_3, patrol_3, patrol_3, patrol_3, patrol_3, patrol_3], 
[patrol_1, patrol_4, patrol_4, patrol_4, patrol_5], 
[patrol_6, patrol_6, patrol_6, patrol_6, patrol_7, patrol_7, patrol_7, patrol_7], 
[patrol_6, patrol_6, patrol_6, patrol_6, patrol_6, patrol_6]],
[10, 10, 10, 10, 10, 10, 10], 
[[925, 550], [925, 550], [925, 550], [925, 550], [925, 550], [925, 550], [925, 550]])
game.levels[0]()
arcade.run()