From f2d41cba557b210dc8bfbac08300badf2019e959 Mon Sep 17 00:00:00 2001 From: Dustin Updyke Date: Mon, 3 Jun 2024 22:21:07 -0400 Subject: [PATCH 1/3] v8.1 work, but mostly api clean up --- .../0ce681936ddabb94/7398dfcbefca0a95 | Bin 0 -> 53 bytes .../0ce681936ddabb94/8f2f7530d70d1af2 | Bin 0 -> 56 bytes .../0ce681936ddabb94/ac6f37185ea662aa | Bin 0 -> 10 bytes .../0ce681936ddabb94/b3fbceeac7edc940 | Bin 0 -> 52 bytes .../0ce681936ddabb94/d038791dc8d55304 | Bin 0 -> 46 bytes .../0e55623b35aed0bd/38b060a751ac9638 | 0 .../1b1484081ed3fd25/01aba940d630ab75 | Bin 0 -> 57 bytes .../1b1484081ed3fd25/0890d05451f4164c | Bin 0 -> 56 bytes .../1b1484081ed3fd25/134770466275ea58 | Bin 0 -> 56 bytes .../1b1484081ed3fd25/1511dcc1d964032c | Bin 0 -> 51 bytes .../1b1484081ed3fd25/19aa13ac8d7428e9 | Bin 0 -> 57 bytes .../1b1484081ed3fd25/1f82eaae236e5fe4 | Bin 0 -> 57 bytes .../1b1484081ed3fd25/20c05b2dbed35c25 | Bin 0 -> 57 bytes .../1b1484081ed3fd25/32447b50dc7f43c4 | Bin 0 -> 56 bytes .../1b1484081ed3fd25/41ecafa23e5a93f3 | Bin 0 -> 57 bytes .../1b1484081ed3fd25/430b057bc1b3b61d | Bin 0 -> 104 bytes .../1b1484081ed3fd25/589ccc28f750849e | Bin 0 -> 56 bytes .../1b1484081ed3fd25/5ca364d046e168aa | Bin 0 -> 16 bytes .../1b1484081ed3fd25/6b2c9168d6a2ad16 | Bin 0 -> 57 bytes .../1b1484081ed3fd25/6bf47176b6c4a57f | Bin 0 -> 128 bytes .../1b1484081ed3fd25/6f2e79924fa0146d | Bin 0 -> 57 bytes .../1b1484081ed3fd25/71b277a5410e9db9 | Bin 0 -> 51 bytes .../1b1484081ed3fd25/83012edca4c9b642 | Bin 0 -> 63 bytes .../1b1484081ed3fd25/833a81447c0132d8 | Bin 0 -> 60 bytes .../1b1484081ed3fd25/966efb8e8f125fa7 | Bin 0 -> 10 bytes .../1b1484081ed3fd25/9bb4524b97454320 | Bin 0 -> 75 bytes .../1b1484081ed3fd25/9cfbc2eace8f4fc9 | Bin 0 -> 56 bytes .../1b1484081ed3fd25/a2330994dc316cc7 | Bin 0 -> 128 bytes .../1b1484081ed3fd25/af202c14b4e434c9 | Bin 0 -> 10 bytes .../1b1484081ed3fd25/ba46ab62ca3cd453 | Bin 0 -> 56 bytes .../1b1484081ed3fd25/beb22e8fda6d3624 | Bin 0 -> 59 bytes .../1b1484081ed3fd25/bfbaef26436147c7 | Bin 0 -> 56 bytes .../1b1484081ed3fd25/c1cc056370ebfcb9 | Bin 0 -> 56 bytes .../1b1484081ed3fd25/c3f6ed0ecc258a1d | Bin 0 -> 56 bytes .../1b1484081ed3fd25/c810786f61f8ee62 | Bin 0 -> 56 bytes .../1b1484081ed3fd25/cbbe0110b60eab1e | Bin 0 -> 56 bytes .../1b1484081ed3fd25/d0fe54bd0d08e1b1 | Bin 0 -> 79 bytes .../1b1484081ed3fd25/ddae71054bfb727a | Bin 0 -> 56 bytes .../1b1484081ed3fd25/df8a018270849f17 | Bin 0 -> 634 bytes .../1b1484081ed3fd25/e8bb8c507b565eef | Bin 0 -> 58 bytes .../1cf837658f59bc59/23a5c6304f36e515 | Bin 0 -> 8 bytes .../1cf837658f59bc59/743c063de21f6906 | Bin 0 -> 10 bytes .../1cf837658f59bc59/891be2b13cf99268 | Bin 0 -> 8 bytes .../1cf837658f59bc59/8efb8b90bc6d5d1b | Bin 0 -> 8 bytes .../1cf837658f59bc59/98b97ef23a59af65 | Bin 0 -> 17 bytes .../1cf837658f59bc59/fb7b2469c0f63dd2 | Bin 0 -> 8 bytes .../24e9e4a6a41ae1d8/00ca6898984673e8 | Bin 0 -> 26 bytes .../24e9e4a6a41ae1d8/01cfdd03c93a4bc0 | Bin 0 -> 36 bytes .../24e9e4a6a41ae1d8/0f570acf7a2d9185 | Bin 0 -> 36 bytes .../24e9e4a6a41ae1d8/1dfcb9cb2a1bed4f | Bin 0 -> 26 bytes .../24e9e4a6a41ae1d8/2af0830ff7cd2496 | Bin 0 -> 46 bytes .../24e9e4a6a41ae1d8/347a01bcef2cf694 | Bin 0 -> 27 bytes .../24e9e4a6a41ae1d8/3669298f38513558 | Bin 0 -> 43 bytes .../24e9e4a6a41ae1d8/3a02ef7ebcab2b88 | Bin 0 -> 41 bytes .../24e9e4a6a41ae1d8/430b057bc1b3b61d | Bin 0 -> 104 bytes .../24e9e4a6a41ae1d8/4abbbc53950daa66 | Bin 0 -> 27 bytes .../24e9e4a6a41ae1d8/51f2607972a60cb0 | Bin 0 -> 55 bytes .../24e9e4a6a41ae1d8/6bf47176b6c4a57f | Bin 0 -> 128 bytes .../24e9e4a6a41ae1d8/83012edca4c9b642 | Bin 0 -> 63 bytes .../24e9e4a6a41ae1d8/8d7ff9bb3c085289 | Bin 0 -> 36 bytes .../24e9e4a6a41ae1d8/8dfa16e61c04bf72 | Bin 0 -> 59 bytes .../24e9e4a6a41ae1d8/96f7e9c7d5290323 | Bin 0 -> 23 bytes .../24e9e4a6a41ae1d8/9ab01f4c4cac1750 | Bin 0 -> 36 bytes .../24e9e4a6a41ae1d8/9bb4524b97454320 | Bin 0 -> 75 bytes .../24e9e4a6a41ae1d8/9c385d2553706367 | Bin 0 -> 27 bytes .../24e9e4a6a41ae1d8/a2330994dc316cc7 | Bin 0 -> 128 bytes .../24e9e4a6a41ae1d8/a6a1177199a6df6b | Bin 0 -> 39 bytes .../24e9e4a6a41ae1d8/aad353552de021f6 | Bin 0 -> 52 bytes .../24e9e4a6a41ae1d8/b004d68338284599 | Bin 0 -> 26 bytes .../24e9e4a6a41ae1d8/b6345318ea8292a0 | Bin 0 -> 49 bytes .../24e9e4a6a41ae1d8/d0fe54bd0d08e1b1 | Bin 0 -> 79 bytes .../24e9e4a6a41ae1d8/dce91dce749f6c92 | Bin 0 -> 37 bytes .../24f3a58f3bfd9f31/38b060a751ac9638 | 0 .../3638c18229c6a7aa/38b060a751ac9638 | 0 .../3c59094c0ffd5073/526ed20c15d7d31f | Bin 0 -> 7 bytes .../4cf0e7054cf98cae/38b060a751ac9638 | 0 .../60dc7c268a9a7d12/38b060a751ac9638 | 0 .../692c48c9c3c189f9/38b060a751ac9638 | 0 .../711ef8dd1d4b67af/38b060a751ac9638 | 0 .../7cf50e557e3b6afd/38b060a751ac9638 | 0 .../7f6330c4ea890236/645f9a2740327990 | Bin 0 -> 26 bytes .../7f6330c4ea890236/e87cdf9cf213a382 | Bin 0 -> 23 bytes .../80ca7cda50842c96/38b060a751ac9638 | 0 .../8da4e8903b5c24a5/38b060a751ac9638 | 0 .../972da276db8e758a/029afea5286208fd | Bin 0 -> 368 bytes .../972da276db8e758a/02e3843ffeffe8de | Bin 0 -> 833 bytes .../972da276db8e758a/05754999ddad7b3e | Bin 0 -> 177 bytes .../972da276db8e758a/068435dbfebb1103 | Bin 0 -> 651 bytes .../972da276db8e758a/07bf2341d68a915f | Bin 0 -> 121 bytes .../972da276db8e758a/083574e6d9a050e8 | Bin 0 -> 455 bytes .../972da276db8e758a/0876196d8c1cc719 | Bin 0 -> 441 bytes .../972da276db8e758a/08ca86db03730942 | Bin 0 -> 76 bytes .../972da276db8e758a/08d1b332d42b337a | Bin 0 -> 329 bytes .../972da276db8e758a/0b467a037be792e7 | Bin 0 -> 424 bytes .../972da276db8e758a/0b7ef15d6cd32065 | Bin 0 -> 626 bytes .../972da276db8e758a/0c7012a3a39f3a8d | Bin 0 -> 51 bytes .../972da276db8e758a/0ccdeff809c50925 | Bin 0 -> 59 bytes .../972da276db8e758a/0e191b776e2c3699 | Bin 0 -> 142 bytes .../972da276db8e758a/0fa0e7e44844d62f | Bin 0 -> 645 bytes .../972da276db8e758a/0fec29ba04f4a391 | Bin 0 -> 860 bytes .../972da276db8e758a/1777dd7eb72c0eb1 | Bin 0 -> 621 bytes .../972da276db8e758a/17f113df5837a90a | Bin 0 -> 492 bytes .../972da276db8e758a/19fb647bb3ccd464 | Bin 0 -> 651 bytes .../972da276db8e758a/1a0c039784e55e57 | Bin 0 -> 427 bytes .../972da276db8e758a/1b1d129bddb55304 | Bin 0 -> 415 bytes .../972da276db8e758a/1c2783b8dc98eea8 | Bin 0 -> 586 bytes .../972da276db8e758a/1cbef7fc528c56c5 | Bin 0 -> 492 bytes .../972da276db8e758a/21b50cb21bde560d | Bin 0 -> 506 bytes .../972da276db8e758a/227c4cf1de61ec07 | Bin 0 -> 562 bytes .../972da276db8e758a/242a68d4fec6b0a7 | Bin 0 -> 811 bytes .../972da276db8e758a/257e17739921f7d4 | Bin 0 -> 458 bytes .../972da276db8e758a/25c6c63a4fadf8a5 | Bin 0 -> 651 bytes .../972da276db8e758a/260565954b6824bc | Bin 0 -> 182 bytes .../972da276db8e758a/26ae9cfe2e6f3c03 | Bin 0 -> 335 bytes .../972da276db8e758a/27558a17a64f7ddf | Bin 0 -> 51 bytes .../972da276db8e758a/287fdf02a3c5519d | Bin 0 -> 216 bytes .../972da276db8e758a/2a506e179c21fd67 | Bin 0 -> 52 bytes .../972da276db8e758a/2b466b85438b26c0 | Bin 0 -> 344 bytes .../972da276db8e758a/339d42b139b9dfbd | Bin 0 -> 164 bytes .../972da276db8e758a/34b1b27282a4adfd | Bin 0 -> 637 bytes .../972da276db8e758a/34be48d4729037f4 | Bin 0 -> 356 bytes .../972da276db8e758a/3559a9554fa8e9b4 | Bin 0 -> 881 bytes .../972da276db8e758a/357afa6b048385e4 | Bin 0 -> 526 bytes .../972da276db8e758a/359a31c9a57f03e1 | Bin 0 -> 379 bytes .../972da276db8e758a/37a64b7d9f57cfa5 | Bin 0 -> 318 bytes .../972da276db8e758a/389ff3fc8b29f9cb | Bin 0 -> 338 bytes .../972da276db8e758a/392767782dc00f6b | Bin 0 -> 651 bytes .../972da276db8e758a/3a4a41f7a5fcaed9 | Bin 0 -> 145 bytes .../972da276db8e758a/3bd6a482df088d91 | Bin 0 -> 529 bytes .../972da276db8e758a/3dade6ff2a86fdd1 | Bin 0 -> 605 bytes .../972da276db8e758a/3f95558bfd1a4200 | Bin 0 -> 133 bytes .../972da276db8e758a/3fea931248d3a3f1 | Bin 0 -> 435 bytes .../972da276db8e758a/44a5f3010f1f4dd0 | Bin 0 -> 418 bytes .../972da276db8e758a/45e13567599e8a88 | Bin 0 -> 106 bytes .../972da276db8e758a/4680e69661a2ed6c | Bin 0 -> 96 bytes .../972da276db8e758a/473055d659fe0ab3 | Bin 0 -> 996 bytes .../972da276db8e758a/474f46dd4323d3c4 | Bin 0 -> 17 bytes .../972da276db8e758a/475f9843b3de8544 | Bin 0 -> 823 bytes .../972da276db8e758a/47a605b9c09873ee | Bin 0 -> 158 bytes .../972da276db8e758a/4c269d80e5f3ea03 | Bin 0 -> 395 bytes .../972da276db8e758a/4cb886acce73eb83 | Bin 0 -> 401 bytes .../972da276db8e758a/4dbbed8d782bd9e9 | Bin 0 -> 39 bytes .../972da276db8e758a/4dec1d6eda5d2975 | Bin 0 -> 133 bytes .../972da276db8e758a/50c07dd5285c028d | Bin 0 -> 350 bytes .../972da276db8e758a/51e175f59290b93b | Bin 0 -> 194 bytes .../972da276db8e758a/527d00d01bb9fdd2 | Bin 0 -> 401 bytes .../972da276db8e758a/52e8be375458549f | Bin 0 -> 153 bytes .../972da276db8e758a/54f3dc6e211b5185 | Bin 0 -> 321 bytes .../972da276db8e758a/5548191b52bf0151 | Bin 0 -> 95 bytes .../972da276db8e758a/55dfa55b86838da2 | Bin 0 -> 200 bytes .../972da276db8e758a/56735cfb13bd9669 | Bin 0 -> 25 bytes .../972da276db8e758a/56df4e2b71c2fe39 | Bin 0 -> 51 bytes .../972da276db8e758a/57826d2867bdd132 | Bin 0 -> 948 bytes .../972da276db8e758a/580e0f1e926d6ae7 | Bin 0 -> 216 bytes .../972da276db8e758a/586417c6f7a4c41d | Bin 0 -> 517 bytes .../972da276db8e758a/5aac9ed9f1e2ef5e | Bin 0 -> 651 bytes .../972da276db8e758a/5d2a46b1404125af | Bin 0 -> 121 bytes .../972da276db8e758a/5f0f6bf95410410b | Bin 0 -> 216 bytes .../972da276db8e758a/5f66066ed6e612f2 | Bin 0 -> 813 bytes .../972da276db8e758a/61cd7c4ec836fe3e | Bin 0 -> 651 bytes .../972da276db8e758a/6361d9e05211444b | Bin 0 -> 586 bytes .../972da276db8e758a/638731351dc3bfa8 | Bin 0 -> 532 bytes .../972da276db8e758a/649c8a4e574bc328 | Bin 0 -> 430 bytes .../972da276db8e758a/653a75e9986a553a | Bin 0 -> 85 bytes .../972da276db8e758a/6752d4feae057d5f | Bin 0 -> 842 bytes .../972da276db8e758a/67f64afe878a5e65 | Bin 0 -> 873 bytes .../972da276db8e758a/68b0244d212daf6c | Bin 0 -> 200 bytes .../972da276db8e758a/691a4136d6f1b4cc | Bin 0 -> 839 bytes .../972da276db8e758a/6c3f4a9b13e2edcf | Bin 0 -> 651 bytes .../972da276db8e758a/6ca3e77a78909ea0 | Bin 0 -> 449 bytes .../972da276db8e758a/6ccc0acd42b04171 | Bin 0 -> 594 bytes .../972da276db8e758a/6e68172d082b368e | Bin 0 -> 1233 bytes .../972da276db8e758a/6f291029da3d1de1 | Bin 0 -> 827 bytes .../972da276db8e758a/6f7dff6973cd0c13 | Bin 0 -> 557 bytes .../972da276db8e758a/71d769de8a69af86 | Bin 0 -> 376 bytes .../972da276db8e758a/72f31cd1b19f26ba | Bin 0 -> 136 bytes .../972da276db8e758a/747fd61f307d1663 | Bin 0 -> 347 bytes .../972da276db8e758a/74d760c976f9b70a | Bin 0 -> 591 bytes .../972da276db8e758a/76bcb06488e394cf | Bin 0 -> 139 bytes .../972da276db8e758a/7794f93f7d176f9a | Bin 0 -> 1000 bytes .../972da276db8e758a/78a42c84bbadb163 | Bin 0 -> 188 bytes .../972da276db8e758a/7971c1191d124bb2 | Bin 0 -> 574 bytes .../972da276db8e758a/7a19079a50f5f798 | Bin 0 -> 651 bytes .../972da276db8e758a/7a8db2b908977b22 | Bin 0 -> 51 bytes .../972da276db8e758a/7c0b1af19bbbe1db | Bin 0 -> 651 bytes .../972da276db8e758a/7c1acad700f1c89f | Bin 0 -> 121 bytes .../972da276db8e758a/7c3e15783e058563 | Bin 0 -> 365 bytes .../972da276db8e758a/7c5c66ed9fb5b293 | Bin 0 -> 489 bytes .../972da276db8e758a/7c99970c2b50d45a | Bin 0 -> 520 bytes .../972da276db8e758a/7cb7e261445e95bf | Bin 0 -> 55 bytes .../972da276db8e758a/7ddcf2f81e1003b1 | Bin 0 -> 851 bytes .../972da276db8e758a/7f2932f835f293a8 | Bin 0 -> 200 bytes .../972da276db8e758a/7f397c9f5279a2fd | Bin 0 -> 51 bytes .../972da276db8e758a/80e2951e61200b3e | Bin 0 -> 869 bytes .../972da276db8e758a/8282d34037c89183 | Bin 0 -> 200 bytes .../972da276db8e758a/82f309871c5f04ec | Bin 0 -> 651 bytes .../972da276db8e758a/833c7d1e442f3a08 | Bin 0 -> 845 bytes .../972da276db8e758a/854b5ad550e6bc91 | Bin 0 -> 362 bytes .../972da276db8e758a/85aed485b42bc20d | Bin 0 -> 651 bytes .../972da276db8e758a/869db011b0b446f9 | Bin 0 -> 885 bytes .../972da276db8e758a/87acf6dd5c0e6038 | Bin 0 -> 452 bytes .../972da276db8e758a/8c91d389355572c1 | Bin 0 -> 651 bytes .../972da276db8e758a/8d53e7c7f6733ee0 | Bin 0 -> 580 bytes .../972da276db8e758a/8f0090ccacb69e75 | Bin 0 -> 648 bytes .../972da276db8e758a/8f1e185860197a10 | Bin 0 -> 42 bytes .../972da276db8e758a/8f72afddef8217ab | Bin 0 -> 817 bytes .../972da276db8e758a/8fff852a1ce8aa3f | Bin 0 -> 401 bytes .../972da276db8e758a/9302a3a7b9dedfaf | Bin 0 -> 121 bytes .../972da276db8e758a/933ac63db4c19566 | Bin 0 -> 65 bytes .../972da276db8e758a/9665e857aaa4144f | Bin 0 -> 344 bytes .../972da276db8e758a/97d0fe57dc4e9a7e | Bin 0 -> 634 bytes .../972da276db8e758a/9a5b6dafea2a0f83 | Bin 0 -> 568 bytes .../972da276db8e758a/9cb6d7ea1d28b800 | Bin 0 -> 500 bytes .../972da276db8e758a/9d1523f2ea98267e | Bin 0 -> 81 bytes .../972da276db8e758a/9d1555c8e1dc0cb4 | Bin 0 -> 509 bytes .../972da276db8e758a/9dc4570db01cac06 | Bin 0 -> 651 bytes .../972da276db8e758a/9feddd69204e2268 | Bin 0 -> 406 bytes .../972da276db8e758a/a0178c41b8d476cc | Bin 0 -> 461 bytes .../972da276db8e758a/a070f9c09b351e20 | Bin 0 -> 571 bytes .../972da276db8e758a/a2e57f240b5f4062 | Bin 0 -> 373 bytes .../972da276db8e758a/a4cc0918fa694d7b | Bin 0 -> 353 bytes .../972da276db8e758a/a5b67f40c8e5989b | Bin 0 -> 1235 bytes .../972da276db8e758a/a9a1f2bd95ad6146 | Bin 0 -> 208 bytes .../972da276db8e758a/aa28c21684eabccc | Bin 0 -> 506 bytes .../972da276db8e758a/acdce01de37b3bc0 | Bin 0 -> 586 bytes .../972da276db8e758a/af07445b8ee364a1 | Bin 0 -> 161 bytes .../972da276db8e758a/b00b258dbe043006 | Bin 0 -> 127 bytes .../972da276db8e758a/b1015f8836881e44 | Bin 0 -> 631 bytes .../972da276db8e758a/b1894fc8b294f2fc | Bin 0 -> 651 bytes .../972da276db8e758a/b1db0ee037d0d160 | Bin 0 -> 651 bytes .../972da276db8e758a/b25640052426d5bf | Bin 0 -> 191 bytes .../972da276db8e758a/b48bb62fb7b6b944 | Bin 0 -> 1010 bytes .../972da276db8e758a/b4bc0f30d70c584e | Bin 0 -> 185 bytes .../972da276db8e758a/b686d72ec3131402 | Bin 0 -> 651 bytes .../972da276db8e758a/b98009729ee2b3ff | Bin 0 -> 565 bytes .../972da276db8e758a/ba6401260165c631 | Bin 0 -> 944 bytes .../972da276db8e758a/baed6326ebc5d987 | Bin 0 -> 124 bytes .../972da276db8e758a/bbda293fec635f4d | Bin 0 -> 492 bytes .../972da276db8e758a/bdd4453cecba0e37 | Bin 0 -> 816 bytes .../972da276db8e758a/be4ead06cf5c2b11 | Bin 0 -> 53 bytes .../972da276db8e758a/bf358ef439773626 | Bin 0 -> 968 bytes .../972da276db8e758a/c32dde26c4c34be7 | Bin 0 -> 51 bytes .../972da276db8e758a/c6db75fdae76c45a | Bin 0 -> 466 bytes .../972da276db8e758a/c79e94cfbc1f2a33 | Bin 0 -> 651 bytes .../972da276db8e758a/c7dd3fa59bca5bfe | Bin 0 -> 387 bytes .../972da276db8e758a/c8446e6581ac4304 | Bin 0 -> 438 bytes .../972da276db8e758a/c8792a081899ea4f | Bin 0 -> 812 bytes .../972da276db8e758a/c8bb039bcb5e1d77 | Bin 0 -> 347 bytes .../972da276db8e758a/c9615f25e6feaea0 | Bin 0 -> 412 bytes .../972da276db8e758a/cd2715812b6bfcfe | Bin 0 -> 497 bytes .../972da276db8e758a/ce7c500a330bdb84 | Bin 0 -> 651 bytes .../972da276db8e758a/cf13b60715d4ec84 | Bin 0 -> 69 bytes .../972da276db8e758a/d0ff0d68f27dbca8 | Bin 0 -> 81 bytes .../972da276db8e758a/d1911510a996b2dc | Bin 0 -> 544 bytes .../972da276db8e758a/d2290b8bd41dd29c | Bin 0 -> 616 bytes .../972da276db8e758a/d259f24b7fef5386 | Bin 0 -> 197 bytes .../972da276db8e758a/d2f0a95fcf23f230 | Bin 0 -> 61 bytes .../972da276db8e758a/d30aed40b9030520 | Bin 0 -> 150 bytes .../972da276db8e758a/d3bf11900d341e8f | Bin 0 -> 613 bytes .../972da276db8e758a/d430e65dfacfcf78 | Bin 0 -> 651 bytes .../972da276db8e758a/d5a7ab593ebc9299 | Bin 0 -> 310 bytes .../972da276db8e758a/d6493e97a346138a | Bin 0 -> 577 bytes .../972da276db8e758a/d9e0feea82962058 | Bin 0 -> 172 bytes .../972da276db8e758a/db82ccfb54ca0f72 | Bin 0 -> 409 bytes .../972da276db8e758a/dc25925bbb5c63f5 | Bin 0 -> 854 bytes .../972da276db8e758a/dc470fa4aa25f376 | Bin 0 -> 825 bytes .../972da276db8e758a/dce8c8837f8291d9 | Bin 0 -> 547 bytes .../972da276db8e758a/dda48081e3b3c427 | Bin 0 -> 51 bytes .../972da276db8e758a/df928c770723c1c7 | Bin 0 -> 472 bytes .../972da276db8e758a/e04e0b8f3edf05dc | Bin 0 -> 469 bytes .../972da276db8e758a/e089ff603e5749bb | Bin 0 -> 384 bytes .../972da276db8e758a/e1e145c86abe97d3 | Bin 0 -> 514 bytes .../972da276db8e758a/e4158fa446c0c7a1 | Bin 0 -> 81 bytes .../972da276db8e758a/e444a7d6037fab1f | Bin 0 -> 480 bytes .../972da276db8e758a/e48d68a595f8621d | Bin 0 -> 97 bytes .../972da276db8e758a/e4b4637062bc4a66 | Bin 0 -> 815 bytes .../972da276db8e758a/e5195318a0b1d607 | Bin 0 -> 586 bytes .../972da276db8e758a/e573a130daba5963 | Bin 0 -> 830 bytes .../972da276db8e758a/e65fcba7001a3a92 | Bin 0 -> 106 bytes .../972da276db8e758a/e6b85ff31576e872 | Bin 0 -> 63 bytes .../972da276db8e758a/e6dcd643c4d59894 | Bin 0 -> 213 bytes .../972da276db8e758a/e79acfc5fe8e7e5b | Bin 0 -> 136 bytes .../972da276db8e758a/e7f1eca362155d60 | Bin 0 -> 818 bytes .../972da276db8e758a/e95fee051d70607c | Bin 0 -> 332 bytes .../972da276db8e758a/ea19679a27e4fdc1 | Bin 0 -> 914 bytes .../972da276db8e758a/eb40f7a6cfeeed80 | Bin 0 -> 42 bytes .../972da276db8e758a/ed9f39111f533b15 | Bin 0 -> 216 bytes .../972da276db8e758a/ef5ac1803b7cf8e1 | Bin 0 -> 503 bytes .../972da276db8e758a/f094d5e957c3f88a | Bin 0 -> 81 bytes .../972da276db8e758a/f3b6c580b1be5cb9 | Bin 0 -> 33 bytes .../972da276db8e758a/f3c23fa2bd571954 | Bin 0 -> 169 bytes .../972da276db8e758a/f3cf1f81bc1f9166 | Bin 0 -> 514 bytes .../972da276db8e758a/f43a83029c4f51d9 | Bin 0 -> 821 bytes .../972da276db8e758a/f46379dd712010a5 | Bin 0 -> 347 bytes .../972da276db8e758a/f5210763dcfbe2b3 | Bin 0 -> 523 bytes .../972da276db8e758a/f5b135c751cc7126 | Bin 0 -> 106 bytes .../972da276db8e758a/f6dadf7f6144d2a7 | Bin 0 -> 315 bytes .../972da276db8e758a/f7f2e0b635416af1 | Bin 0 -> 848 bytes .../972da276db8e758a/f883f1876eda84bb | Bin 0 -> 1005 bytes .../972da276db8e758a/f99e7b49d8ac77a3 | Bin 0 -> 642 bytes .../972da276db8e758a/fb2374232294ebe3 | Bin 0 -> 46 bytes .../972da276db8e758a/fe3d34cd98884603 | Bin 0 -> 483 bytes .../972da276db8e758a/ff68979d0ce29eb5 | Bin 0 -> 57 bytes .../a7082e79f930272b/38b060a751ac9638 | 0 .../a7765ca8ac786d69/38b060a751ac9638 | 0 .../c5cc8ddf7622ef8a/38b060a751ac9638 | 0 .../ceb7445d967ce5aa/38b060a751ac9638 | 0 .../f8448706e2bfab64/38b060a751ac9638 | 0 .../unicode_data/14.0.0/charmap.json.gz | Bin 0 -> 21505 bytes .../unicode_data/14.0.0/codec-utf-8.json.gz | Bin 0 -> 60 bytes src/Ghosts.Animator/Education.cs | 2 +- .../Extensions/StringExtensions.cs | 3 + src/Ghosts.Animator/Internet.cs | 41 +- src/Ghosts.Animator/MilitaryUnits.cs | 4 + .../Api/AnimationJobsController.cs | 58 -- .../Controllers/Api/NpcsGenerateController.cs | 151 ----- .../Animator/Controllers/HomeController.cs | 31 -- .../AnimationDefinitions/SocialSharingJob.cs | 213 ------- .../Models/NPCToInsiderThreatCsv.cs | 290 ---------- .../Infrastructure/Services/NpcService.cs | 110 ---- .../Areas/Animator/Views/Home/Index.cshtml | 5 - .../Areas/Animator/Views/_ViewStart.cshtml | 3 - .../Controllers/AnimationsController.cs | 5 +- .../Api/AnimationJobsController.cs | 44 ++ .../{ => Api}/ClientIdController.cs | 22 +- .../{ => Api}/ClientResultsController.cs | 70 +-- .../{ => Api}/ClientSurveyController.cs | 51 +- .../Controllers/{ => Api}/ClientTimeline.cs | 29 +- .../{ => Api}/ClientUpdatesController.cs | 6 +- .../{ => Api}/InstallController.cs | 6 +- .../{ => Api}/MachineGroupsController.cs | 89 ++- .../Api/MachineUpdatesController.cs | 179 ++++++ .../{ => Api}/MachinesController.cs | 28 +- .../Controllers/Api/NpcsController.cs | 163 +++--- .../Controllers/Api/NpcsGenerateController.cs | 90 +++ .../{ => Api}/SurveysController.cs | 7 +- .../{ => Api}/TimelinesController.cs | 27 +- .../{ => Api}/TrackablesController.cs | 5 +- .../{ => Api}/WebhooksController.cs | 50 +- src/Ghosts.Api/Controllers/HomeController.cs | 28 +- .../Controllers/MachineUpdatesController.cs | 87 --- .../Controllers/ViewActivitiesController.cs | 6 +- .../ViewRelationshipsController.cs | 6 +- .../Controllers/ViewSocialController.cs | 11 +- .../{Areas/Animator => }/Hubs/ActivityHub.cs | 0 .../Animator => }/Hubs/ConnectionMapping.cs | 0 .../AnimationDefinitions/Chat/ChatClient.cs | 28 +- .../Chat/ChatConfiguration.cs | 0 .../Chat/Mattermost/Channel.cs | 0 .../Chat/Mattermost/Post.cs | 0 .../Chat/Mattermost/Team.cs | 0 .../Chat/Mattermost/User.cs | 0 .../AnimationDefinitions/ChatJob.cs | 2 +- .../AnimationDefinitions/FullAutonomyJob.cs | 0 .../AnimationDefinitions/SocialBeliefJob.cs | 30 +- .../AnimationDefinitions/SocialGraphJob.cs | 0 .../AnimationDefinitions/SocialSharingJob.cs | 219 ++++++++ .../Animations/AnimationsManager.cs | 2 +- .../Animator => }/Infrastructure/Bayes.cs | 0 .../ContentServices/ContentCreationService.cs | 0 .../ContentServices/GenericContentHelpers.cs | 0 .../ContentServices/IContentService.cs | 0 .../ContentServices/IFormatterService.cs | 0 .../Native/NativeContentFormatterService.cs | 0 .../Ollama/OllamaConnectorService.cs | 0 .../Ollama/OllamaFormatterService.cs | 6 +- .../OpenAi/OpenAIConnectorService.cs | 0 .../OpenAi/OpenAIFormatterService.cs | 0 .../ContentServices/OpenAi/OpenAIHelpers.cs | 0 .../Shadows/ShadowsConnectorService.cs | 0 .../Shadows/ShadowsFormatterService.cs | 0 .../Data/ApplicationDbContext.cs | 3 + .../Extensions/JsonExtensions.cs | 12 + .../Extensions/StringExtensions.cs | 4 + .../Filters/CustomDocumentFilter.cs | 26 + .../Models/EnclaveReducedCsv.cs | 0 .../Models/GenerationConfiguration.cs | 0 .../InsiderThreatGenerationConfiguration.cs | 0 .../Infrastructure/Models/MachineGroup.cs | 9 +- .../Infrastructure/Models/MachineUpdate.cs | 22 +- .../Infrastructure/Models/NPC.cs | 8 +- .../Infrastructure/Models/NPCIpAddress.cs | 0 .../Infrastructure/Models/NPCNameId.cs | 0 .../Infrastructure/Models/NPCReduced.cs | 0 .../Infrastructure/Models/NPCToCsv.cs | 0 .../Models/NPCToInsiderThreatCsv.cs | 525 ++++++++++++++++++ .../Infrastructure/Models/NpcActivity.cs | 0 .../Infrastructure/Models/NpcSocialGraph.cs | 7 +- .../Models/TfVarsConfiguration.cs | 20 +- .../Services/MachineGroupService.cs | 34 +- .../Infrastructure/Services/MachineService.cs | 3 + .../Services/MachineUpdateService.cs | 7 + .../Infrastructure/Services/NpcService.cs | 185 ++++++ .../Services/QueueSyncService.cs | 3 + .../Services/TimelineService.cs | 4 +- src/Ghosts.Api/Startup.cs | 22 +- .../ViewModels/MachineUpdateViewModel.cs | 4 +- .../Views/Animations/Index.cshtml | 0 .../Views/Animations/Started.cshtml | 0 src/Ghosts.Api/Views/Shared/_Layout.cshtml | 8 +- .../Views/ViewActivities/Index.cshtml | 4 +- .../Views/ViewActivities/detail.cshtml | 0 .../Views/ViewRelationships/Index.cshtml | 0 .../Views/ViewRelationships/Profile.cshtml | 0 .../Views/ViewSocial/Detail.cshtml | 0 .../Views/ViewSocial/Index.cshtml | 0 .../Views/ViewSocial/Interactions.cshtml | 0 src/Ghosts.Api/appsettings.json | 5 +- src/Ghosts.Api/config/photos/default.png | Bin 0 -> 86914 bytes src/Ghosts.Api/ghosts.api.csproj | 40 +- src/Ghosts.Domain/Code/ApplicationDetails.cs | 16 +- .../Code/Helpers/TimeSpanConverter.cs | 80 +++ src/Ghosts.Domain/Messages/Timeline.cs | 9 +- src/ghosts.client.linux/Health/Check.cs | 2 +- 414 files changed, 1976 insertions(+), 1293 deletions(-) create mode 100644 scripts/.hypothesis/examples/0ce681936ddabb94/7398dfcbefca0a95 create mode 100644 scripts/.hypothesis/examples/0ce681936ddabb94/8f2f7530d70d1af2 create mode 100644 scripts/.hypothesis/examples/0ce681936ddabb94/ac6f37185ea662aa create mode 100644 scripts/.hypothesis/examples/0ce681936ddabb94/b3fbceeac7edc940 create mode 100644 scripts/.hypothesis/examples/0ce681936ddabb94/d038791dc8d55304 create mode 100644 scripts/.hypothesis/examples/0e55623b35aed0bd/38b060a751ac9638 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/01aba940d630ab75 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/0890d05451f4164c create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/134770466275ea58 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/1511dcc1d964032c create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/19aa13ac8d7428e9 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/1f82eaae236e5fe4 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/20c05b2dbed35c25 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/32447b50dc7f43c4 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/41ecafa23e5a93f3 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/430b057bc1b3b61d create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/589ccc28f750849e create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/5ca364d046e168aa create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/6b2c9168d6a2ad16 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/6bf47176b6c4a57f create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/6f2e79924fa0146d create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/71b277a5410e9db9 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/83012edca4c9b642 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/833a81447c0132d8 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/966efb8e8f125fa7 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/9bb4524b97454320 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/9cfbc2eace8f4fc9 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/a2330994dc316cc7 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/af202c14b4e434c9 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/ba46ab62ca3cd453 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/beb22e8fda6d3624 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/bfbaef26436147c7 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/c1cc056370ebfcb9 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/c3f6ed0ecc258a1d create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/c810786f61f8ee62 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/cbbe0110b60eab1e create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/d0fe54bd0d08e1b1 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/ddae71054bfb727a create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/df8a018270849f17 create mode 100644 scripts/.hypothesis/examples/1b1484081ed3fd25/e8bb8c507b565eef create mode 100644 scripts/.hypothesis/examples/1cf837658f59bc59/23a5c6304f36e515 create mode 100644 scripts/.hypothesis/examples/1cf837658f59bc59/743c063de21f6906 create mode 100644 scripts/.hypothesis/examples/1cf837658f59bc59/891be2b13cf99268 create mode 100644 scripts/.hypothesis/examples/1cf837658f59bc59/8efb8b90bc6d5d1b create mode 100644 scripts/.hypothesis/examples/1cf837658f59bc59/98b97ef23a59af65 create mode 100644 scripts/.hypothesis/examples/1cf837658f59bc59/fb7b2469c0f63dd2 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/00ca6898984673e8 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/01cfdd03c93a4bc0 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/0f570acf7a2d9185 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/1dfcb9cb2a1bed4f create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/2af0830ff7cd2496 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/347a01bcef2cf694 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/3669298f38513558 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/3a02ef7ebcab2b88 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/430b057bc1b3b61d create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/4abbbc53950daa66 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/51f2607972a60cb0 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/6bf47176b6c4a57f create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/83012edca4c9b642 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/8d7ff9bb3c085289 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/8dfa16e61c04bf72 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/96f7e9c7d5290323 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/9ab01f4c4cac1750 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/9bb4524b97454320 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/9c385d2553706367 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/a2330994dc316cc7 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/a6a1177199a6df6b create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/aad353552de021f6 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/b004d68338284599 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/b6345318ea8292a0 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/d0fe54bd0d08e1b1 create mode 100644 scripts/.hypothesis/examples/24e9e4a6a41ae1d8/dce91dce749f6c92 create mode 100644 scripts/.hypothesis/examples/24f3a58f3bfd9f31/38b060a751ac9638 create mode 100644 scripts/.hypothesis/examples/3638c18229c6a7aa/38b060a751ac9638 create mode 100644 scripts/.hypothesis/examples/3c59094c0ffd5073/526ed20c15d7d31f create mode 100644 scripts/.hypothesis/examples/4cf0e7054cf98cae/38b060a751ac9638 create mode 100644 scripts/.hypothesis/examples/60dc7c268a9a7d12/38b060a751ac9638 create mode 100644 scripts/.hypothesis/examples/692c48c9c3c189f9/38b060a751ac9638 create mode 100644 scripts/.hypothesis/examples/711ef8dd1d4b67af/38b060a751ac9638 create mode 100644 scripts/.hypothesis/examples/7cf50e557e3b6afd/38b060a751ac9638 create mode 100644 scripts/.hypothesis/examples/7f6330c4ea890236/645f9a2740327990 create mode 100644 scripts/.hypothesis/examples/7f6330c4ea890236/e87cdf9cf213a382 create mode 100644 scripts/.hypothesis/examples/80ca7cda50842c96/38b060a751ac9638 create mode 100644 scripts/.hypothesis/examples/8da4e8903b5c24a5/38b060a751ac9638 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/029afea5286208fd create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/02e3843ffeffe8de create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/05754999ddad7b3e create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/068435dbfebb1103 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/07bf2341d68a915f create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/083574e6d9a050e8 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/0876196d8c1cc719 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/08ca86db03730942 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/08d1b332d42b337a create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/0b467a037be792e7 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/0b7ef15d6cd32065 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/0c7012a3a39f3a8d create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/0ccdeff809c50925 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/0e191b776e2c3699 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/0fa0e7e44844d62f create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/0fec29ba04f4a391 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/1777dd7eb72c0eb1 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/17f113df5837a90a create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/19fb647bb3ccd464 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/1a0c039784e55e57 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/1b1d129bddb55304 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/1c2783b8dc98eea8 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/1cbef7fc528c56c5 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/21b50cb21bde560d create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/227c4cf1de61ec07 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/242a68d4fec6b0a7 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/257e17739921f7d4 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/25c6c63a4fadf8a5 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/260565954b6824bc create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/26ae9cfe2e6f3c03 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/27558a17a64f7ddf create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/287fdf02a3c5519d create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/2a506e179c21fd67 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/2b466b85438b26c0 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/339d42b139b9dfbd create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/34b1b27282a4adfd create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/34be48d4729037f4 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/3559a9554fa8e9b4 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/357afa6b048385e4 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/359a31c9a57f03e1 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/37a64b7d9f57cfa5 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/389ff3fc8b29f9cb create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/392767782dc00f6b create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/3a4a41f7a5fcaed9 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/3bd6a482df088d91 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/3dade6ff2a86fdd1 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/3f95558bfd1a4200 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/3fea931248d3a3f1 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/44a5f3010f1f4dd0 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/45e13567599e8a88 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/4680e69661a2ed6c create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/473055d659fe0ab3 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/474f46dd4323d3c4 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/475f9843b3de8544 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/47a605b9c09873ee create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/4c269d80e5f3ea03 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/4cb886acce73eb83 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/4dbbed8d782bd9e9 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/4dec1d6eda5d2975 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/50c07dd5285c028d create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/51e175f59290b93b create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/527d00d01bb9fdd2 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/52e8be375458549f create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/54f3dc6e211b5185 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/5548191b52bf0151 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/55dfa55b86838da2 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/56735cfb13bd9669 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/56df4e2b71c2fe39 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/57826d2867bdd132 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/580e0f1e926d6ae7 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/586417c6f7a4c41d create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/5aac9ed9f1e2ef5e create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/5d2a46b1404125af create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/5f0f6bf95410410b create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/5f66066ed6e612f2 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/61cd7c4ec836fe3e create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/6361d9e05211444b create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/638731351dc3bfa8 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/649c8a4e574bc328 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/653a75e9986a553a create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/6752d4feae057d5f create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/67f64afe878a5e65 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/68b0244d212daf6c create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/691a4136d6f1b4cc create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/6c3f4a9b13e2edcf create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/6ca3e77a78909ea0 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/6ccc0acd42b04171 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/6e68172d082b368e create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/6f291029da3d1de1 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/6f7dff6973cd0c13 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/71d769de8a69af86 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/72f31cd1b19f26ba create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/747fd61f307d1663 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/74d760c976f9b70a create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/76bcb06488e394cf create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/7794f93f7d176f9a create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/78a42c84bbadb163 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/7971c1191d124bb2 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/7a19079a50f5f798 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/7a8db2b908977b22 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/7c0b1af19bbbe1db create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/7c1acad700f1c89f create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/7c3e15783e058563 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/7c5c66ed9fb5b293 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/7c99970c2b50d45a create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/7cb7e261445e95bf create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/7ddcf2f81e1003b1 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/7f2932f835f293a8 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/7f397c9f5279a2fd create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/80e2951e61200b3e create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/8282d34037c89183 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/82f309871c5f04ec create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/833c7d1e442f3a08 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/854b5ad550e6bc91 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/85aed485b42bc20d create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/869db011b0b446f9 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/87acf6dd5c0e6038 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/8c91d389355572c1 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/8d53e7c7f6733ee0 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/8f0090ccacb69e75 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/8f1e185860197a10 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/8f72afddef8217ab create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/8fff852a1ce8aa3f create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/9302a3a7b9dedfaf create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/933ac63db4c19566 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/9665e857aaa4144f create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/97d0fe57dc4e9a7e create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/9a5b6dafea2a0f83 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/9cb6d7ea1d28b800 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/9d1523f2ea98267e create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/9d1555c8e1dc0cb4 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/9dc4570db01cac06 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/9feddd69204e2268 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/a0178c41b8d476cc create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/a070f9c09b351e20 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/a2e57f240b5f4062 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/a4cc0918fa694d7b create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/a5b67f40c8e5989b create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/a9a1f2bd95ad6146 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/aa28c21684eabccc create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/acdce01de37b3bc0 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/af07445b8ee364a1 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/b00b258dbe043006 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/b1015f8836881e44 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/b1894fc8b294f2fc create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/b1db0ee037d0d160 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/b25640052426d5bf create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/b48bb62fb7b6b944 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/b4bc0f30d70c584e create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/b686d72ec3131402 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/b98009729ee2b3ff create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/ba6401260165c631 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/baed6326ebc5d987 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/bbda293fec635f4d create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/bdd4453cecba0e37 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/be4ead06cf5c2b11 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/bf358ef439773626 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/c32dde26c4c34be7 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/c6db75fdae76c45a create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/c79e94cfbc1f2a33 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/c7dd3fa59bca5bfe create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/c8446e6581ac4304 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/c8792a081899ea4f create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/c8bb039bcb5e1d77 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/c9615f25e6feaea0 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/cd2715812b6bfcfe create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/ce7c500a330bdb84 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/cf13b60715d4ec84 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/d0ff0d68f27dbca8 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/d1911510a996b2dc create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/d2290b8bd41dd29c create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/d259f24b7fef5386 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/d2f0a95fcf23f230 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/d30aed40b9030520 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/d3bf11900d341e8f create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/d430e65dfacfcf78 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/d5a7ab593ebc9299 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/d6493e97a346138a create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/d9e0feea82962058 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/db82ccfb54ca0f72 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/dc25925bbb5c63f5 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/dc470fa4aa25f376 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/dce8c8837f8291d9 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/dda48081e3b3c427 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/df928c770723c1c7 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e04e0b8f3edf05dc create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e089ff603e5749bb create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e1e145c86abe97d3 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e4158fa446c0c7a1 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e444a7d6037fab1f create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e48d68a595f8621d create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e4b4637062bc4a66 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e5195318a0b1d607 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e573a130daba5963 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e65fcba7001a3a92 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e6b85ff31576e872 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e6dcd643c4d59894 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e79acfc5fe8e7e5b create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e7f1eca362155d60 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/e95fee051d70607c create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/ea19679a27e4fdc1 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/eb40f7a6cfeeed80 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/ed9f39111f533b15 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/ef5ac1803b7cf8e1 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/f094d5e957c3f88a create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/f3b6c580b1be5cb9 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/f3c23fa2bd571954 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/f3cf1f81bc1f9166 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/f43a83029c4f51d9 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/f46379dd712010a5 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/f5210763dcfbe2b3 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/f5b135c751cc7126 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/f6dadf7f6144d2a7 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/f7f2e0b635416af1 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/f883f1876eda84bb create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/f99e7b49d8ac77a3 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/fb2374232294ebe3 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/fe3d34cd98884603 create mode 100644 scripts/.hypothesis/examples/972da276db8e758a/ff68979d0ce29eb5 create mode 100644 scripts/.hypothesis/examples/a7082e79f930272b/38b060a751ac9638 create mode 100644 scripts/.hypothesis/examples/a7765ca8ac786d69/38b060a751ac9638 create mode 100644 scripts/.hypothesis/examples/c5cc8ddf7622ef8a/38b060a751ac9638 create mode 100644 scripts/.hypothesis/examples/ceb7445d967ce5aa/38b060a751ac9638 create mode 100644 scripts/.hypothesis/examples/f8448706e2bfab64/38b060a751ac9638 create mode 100644 scripts/.hypothesis/unicode_data/14.0.0/charmap.json.gz create mode 100644 scripts/.hypothesis/unicode_data/14.0.0/codec-utf-8.json.gz delete mode 100644 src/Ghosts.Api/Areas/Animator/Controllers/Api/AnimationJobsController.cs delete mode 100644 src/Ghosts.Api/Areas/Animator/Controllers/Api/NpcsGenerateController.cs delete mode 100644 src/Ghosts.Api/Areas/Animator/Controllers/HomeController.cs delete mode 100644 src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs delete mode 100644 src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPCToInsiderThreatCsv.cs delete mode 100644 src/Ghosts.Api/Areas/Animator/Infrastructure/Services/NpcService.cs delete mode 100644 src/Ghosts.Api/Areas/Animator/Views/Home/Index.cshtml delete mode 100644 src/Ghosts.Api/Areas/Animator/Views/_ViewStart.cshtml rename src/Ghosts.Api/{Areas/Animator => }/Controllers/AnimationsController.cs (95%) create mode 100644 src/Ghosts.Api/Controllers/Api/AnimationJobsController.cs rename src/Ghosts.Api/Controllers/{ => Api}/ClientIdController.cs (67%) rename src/Ghosts.Api/Controllers/{ => Api}/ClientResultsController.cs (60%) rename src/Ghosts.Api/Controllers/{ => Api}/ClientSurveyController.cs (64%) rename src/Ghosts.Api/Controllers/{ => Api}/ClientTimeline.cs (73%) rename src/Ghosts.Api/Controllers/{ => Api}/ClientUpdatesController.cs (94%) rename src/Ghosts.Api/Controllers/{ => Api}/InstallController.cs (83%) rename src/Ghosts.Api/Controllers/{ => Api}/MachineGroupsController.cs (60%) create mode 100755 src/Ghosts.Api/Controllers/Api/MachineUpdatesController.cs rename src/Ghosts.Api/Controllers/{ => Api}/MachinesController.cs (85%) rename src/Ghosts.Api/{Areas/Animator => }/Controllers/Api/NpcsController.cs (74%) create mode 100644 src/Ghosts.Api/Controllers/Api/NpcsGenerateController.cs rename src/Ghosts.Api/Controllers/{ => Api}/SurveysController.cs (81%) rename src/Ghosts.Api/Controllers/{ => Api}/TimelinesController.cs (70%) rename src/Ghosts.Api/Controllers/{ => Api}/TrackablesController.cs (88%) rename src/Ghosts.Api/Controllers/{ => Api}/WebhooksController.cs (78%) delete mode 100755 src/Ghosts.Api/Controllers/MachineUpdatesController.cs rename src/Ghosts.Api/{Areas/Animator => }/Controllers/ViewActivitiesController.cs (83%) rename src/Ghosts.Api/{Areas/Animator => }/Controllers/ViewRelationshipsController.cs (94%) rename src/Ghosts.Api/{Areas/Animator => }/Controllers/ViewSocialController.cs (93%) rename src/Ghosts.Api/{Areas/Animator => }/Hubs/ActivityHub.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Hubs/ConnectionMapping.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs (95%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Animations/AnimationDefinitions/Chat/ChatConfiguration.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Channel.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Post.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Team.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/User.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs (98%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Animations/AnimationDefinitions/FullAutonomyJob.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Animations/AnimationDefinitions/SocialBeliefJob.cs (80%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Animations/AnimationDefinitions/SocialGraphJob.cs (100%) create mode 100644 src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Animations/AnimationsManager.cs (99%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Bayes.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/ContentServices/ContentCreationService.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/ContentServices/GenericContentHelpers.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/ContentServices/IContentService.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/ContentServices/IFormatterService.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/ContentServices/Native/NativeContentFormatterService.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/ContentServices/Ollama/OllamaConnectorService.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs (96%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/ContentServices/OpenAi/OpenAIConnectorService.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/ContentServices/OpenAi/OpenAIFormatterService.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/ContentServices/OpenAi/OpenAIHelpers.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/ContentServices/Shadows/ShadowsConnectorService.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/ContentServices/Shadows/ShadowsFormatterService.cs (100%) create mode 100644 src/Ghosts.Api/Infrastructure/Extensions/JsonExtensions.cs create mode 100644 src/Ghosts.Api/Infrastructure/Filters/CustomDocumentFilter.cs rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Models/EnclaveReducedCsv.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Models/GenerationConfiguration.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Models/InsiderThreatGenerationConfiguration.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Models/NPC.cs (93%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Models/NPCIpAddress.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Models/NPCNameId.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Models/NPCReduced.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Models/NPCToCsv.cs (100%) create mode 100644 src/Ghosts.Api/Infrastructure/Models/NPCToInsiderThreatCsv.cs rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Models/NpcActivity.cs (100%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Models/NpcSocialGraph.cs (93%) rename src/Ghosts.Api/{Areas/Animator => }/Infrastructure/Models/TfVarsConfiguration.cs (74%) create mode 100644 src/Ghosts.Api/Infrastructure/Services/NpcService.cs rename src/Ghosts.Api/{Areas/Animator => }/Views/Animations/Index.cshtml (100%) rename src/Ghosts.Api/{Areas/Animator => }/Views/Animations/Started.cshtml (100%) rename src/Ghosts.Api/{Areas/Animator => }/Views/ViewActivities/Index.cshtml (93%) rename src/Ghosts.Api/{Areas/Animator => }/Views/ViewActivities/detail.cshtml (100%) rename src/Ghosts.Api/{Areas/Animator => }/Views/ViewRelationships/Index.cshtml (100%) rename src/Ghosts.Api/{Areas/Animator => }/Views/ViewRelationships/Profile.cshtml (100%) rename src/Ghosts.Api/{Areas/Animator => }/Views/ViewSocial/Detail.cshtml (100%) rename src/Ghosts.Api/{Areas/Animator => }/Views/ViewSocial/Index.cshtml (100%) rename src/Ghosts.Api/{Areas/Animator => }/Views/ViewSocial/Interactions.cshtml (100%) create mode 100644 src/Ghosts.Api/config/photos/default.png create mode 100644 src/Ghosts.Domain/Code/Helpers/TimeSpanConverter.cs diff --git a/scripts/.hypothesis/examples/0ce681936ddabb94/7398dfcbefca0a95 b/scripts/.hypothesis/examples/0ce681936ddabb94/7398dfcbefca0a95 new file mode 100644 index 0000000000000000000000000000000000000000..96fd13ad1d6283ca3188f61669bb842d1b6edfa7 GIT binary patch literal 53 qcmZQzU}RuqWaPfV0bu|+3?KnUMrM!%1DIj~2{AC}F#rLOW&i*#&;dLE literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/0ce681936ddabb94/8f2f7530d70d1af2 b/scripts/.hypothesis/examples/0ce681936ddabb94/8f2f7530d70d1af2 new file mode 100644 index 0000000000000000000000000000000000000000..83629a299ef906fba5604412813923d528fcc254 GIT binary patch literal 56 qcmZQzU}RuqWaPfV0bu|+3?KnUMrM!%1DIj~2{AB8F#rLG0R#XsngJ;Q literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/0ce681936ddabb94/ac6f37185ea662aa b/scripts/.hypothesis/examples/0ce681936ddabb94/ac6f37185ea662aa new file mode 100644 index 0000000000000000000000000000000000000000..418bd539cce75eabca181a5235652cac042f0a4c GIT binary patch literal 10 OcmZQzU}OLyAOQdX8UO?U literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/0ce681936ddabb94/b3fbceeac7edc940 b/scripts/.hypothesis/examples/0ce681936ddabb94/b3fbceeac7edc940 new file mode 100644 index 0000000000000000000000000000000000000000..19eb6cab1fa3edea7232c0c1f69ce27ae19f3405 GIT binary patch literal 52 ocmZQzU}RuqWaPfV0bu|+3?KnUMrM!%1DIj~2{ACP*I)nx05ZA(efq)q(3&t!!0T5zbufYHY05}){=>Px# literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/20c05b2dbed35c25 b/scripts/.hypothesis/examples/1b1484081ed3fd25/20c05b2dbed35c25 new file mode 100644 index 0000000000000000000000000000000000000000..9213da4c4bfece40db5bcab640c7754c4452d91d GIT binary patch literal 57 scmZQzU}RuqWaPfV0bu|+3?KnUMrM!%1DIj~2{ACP*I)nwkOCk806ahe=Kufz literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/32447b50dc7f43c4 b/scripts/.hypothesis/examples/1b1484081ed3fd25/32447b50dc7f43c4 new file mode 100644 index 0000000000000000000000000000000000000000..2fb1e02815a658c8edb69ded0b127274d162706c GIT binary patch literal 56 rcmZQzU}RuqWaPfV0bu|+3?KnUMrNP{kO`t#Ktc=*dJI4SVgLaEGH?Mr literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/41ecafa23e5a93f3 b/scripts/.hypothesis/examples/1b1484081ed3fd25/41ecafa23e5a93f3 new file mode 100644 index 0000000000000000000000000000000000000000..3d9dbfa352e5ca6764fa4648dcc3c4ebec252b9c GIT binary patch literal 57 ocmZQzU}RuqWaPfV0bzhR3_t>efq)q#%K)ZWz`~5{H5kAE05|gi=l}o! literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/430b057bc1b3b61d b/scripts/.hypothesis/examples/1b1484081ed3fd25/430b057bc1b3b61d new file mode 100644 index 0000000000000000000000000000000000000000..fc3889f79c89e30ae1a39e0bb8c204640a4d34e5 GIT binary patch literal 104 zcmZQzU}RuqWaPfV0bzhRAk4@BBKbGUFfyD5F~M9$MrNQS2!kjV21X{JFbFZO*MMmH a!N|y30n{iUU&qL>nUUcI0}ud}FaQ8Fwg+Ya literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/589ccc28f750849e b/scripts/.hypothesis/examples/1b1484081ed3fd25/589ccc28f750849e new file mode 100644 index 0000000000000000000000000000000000000000..9c3b6827cb89e7ef1d64eee3d8def0bc2333d196 GIT binary patch literal 56 qcmZQzU}RuqWaPfV0bu|+3?KnUMrM!%1DIj~2{AA*GXMdI0R#Xrh5-@) literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/5ca364d046e168aa b/scripts/.hypothesis/examples/1b1484081ed3fd25/5ca364d046e168aa new file mode 100644 index 0000000000000000000000000000000000000000..cd95bfe047a1b93b33b43aa8580aea503a75f0de GIT binary patch literal 16 VcmZQzU}RuqWaPfV0b(#P000M~0P+9; literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/6b2c9168d6a2ad16 b/scripts/.hypothesis/examples/1b1484081ed3fd25/6b2c9168d6a2ad16 new file mode 100644 index 0000000000000000000000000000000000000000..79c06158f872bda04afa1e3d6fa72ecf244951f6 GIT binary patch literal 57 ocmZQzU}RuqWaPfV0bzhR3_t>efq)q(3&KFe0v2XmufYHY05|#p=l}o! literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/6bf47176b6c4a57f b/scripts/.hypothesis/examples/1b1484081ed3fd25/6bf47176b6c4a57f new file mode 100644 index 0000000000000000000000000000000000000000..14ecdd7691b644005aed30e513b5c160f6f8edcd GIT binary patch literal 128 zcmW-Zu?@md5JP=;|ISDhP^3iq>B5Lq%)$myM8N=*EWidZ0%c5GJxk993>M7(nD*}- zLd`1N-NXuDZv8VJmQ(plO@S=JS7E_!U{h?U@(d9Q!qKZ}BA* GhIFi+@(ZK@ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/6f2e79924fa0146d b/scripts/.hypothesis/examples/1b1484081ed3fd25/6f2e79924fa0146d new file mode 100644 index 0000000000000000000000000000000000000000..b86e113f4fc6be3ae4c5c6aa23f1594659de4719 GIT binary patch literal 57 qcmZQzU}RuqWaPfV0bu|+3?KnUMrM!%1DIj~2?0?Y0}y}|0096s@&RuE literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/71b277a5410e9db9 b/scripts/.hypothesis/examples/1b1484081ed3fd25/71b277a5410e9db9 new file mode 100644 index 0000000000000000000000000000000000000000..e33b16200f11ab963d2fa8fdfa09d338362d2199 GIT binary patch literal 51 jcmZQzV1z(MAkD}C#6Z9dW`ijfkPrid9s>}77(f631_J<4 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/83012edca4c9b642 b/scripts/.hypothesis/examples/1b1484081ed3fd25/83012edca4c9b642 new file mode 100644 index 0000000000000000000000000000000000000000..8f43bfccdfde5ccb200ef3a75558be9a3a867c68 GIT binary patch literal 63 tcmZQzU}RuqWaPfV0bzhR3_t>efq)q(3&J3Zg@KU?C=5c3>opj_002I}0qy_* literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/833a81447c0132d8 b/scripts/.hypothesis/examples/1b1484081ed3fd25/833a81447c0132d8 new file mode 100644 index 0000000000000000000000000000000000000000..b623b5858790cf16d0b95edd6bb58c848cb3d7b2 GIT binary patch literal 60 qcmZQzU}RuqWaPfV0bzhR3_t>efq)q(3&J3Z1tda literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/9bb4524b97454320 b/scripts/.hypothesis/examples/1b1484081ed3fd25/9bb4524b97454320 new file mode 100644 index 0000000000000000000000000000000000000000..cef449748a68767c4424e4e8c9ee97902fa0f4fa GIT binary patch literal 75 zcmZQzU}RuqWaPfV0bzhR5ElPN8AgWF3_t-81_EZF1PFsD76wKppfCtAuGe4y0|1w2 B1DXH; literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/9cfbc2eace8f4fc9 b/scripts/.hypothesis/examples/1b1484081ed3fd25/9cfbc2eace8f4fc9 new file mode 100644 index 0000000000000000000000000000000000000000..22e252f1a769d86c5a504dcd799ec54989036f1f GIT binary patch literal 56 qcmZQzU}RuqWaPfV0bu|+3?KnUMrM!%1DIj}2{AC}0ckJ;NC5ycJ^?uZ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/a2330994dc316cc7 b/scripts/.hypothesis/examples/1b1484081ed3fd25/a2330994dc316cc7 new file mode 100644 index 0000000000000000000000000000000000000000..ca00deb3f41e0374e4f616e6c27598e366badcc9 GIT binary patch literal 128 zcmW-Zu?@md5JP=;|ISDhP^3iq>B5Lq%)$myM8N=*EWidZ0%c5G`AN?P3>M7(nD*}- zLSz;0Zt4nPZv8VJmQ(plBtwd|42Ls}+}vnL2Q`DyF`xhQ!mr30ZqK~v=Gd=^dy6lj HFr;GzpEnDo literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/af202c14b4e434c9 b/scripts/.hypothesis/examples/1b1484081ed3fd25/af202c14b4e434c9 new file mode 100644 index 0000000000000000000000000000000000000000..8feb3f7d4a6226a9c1e3ac5e8e75e3ba14f10fda GIT binary patch literal 10 PcmZQzU}RumWCRib03HAZ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/ba46ab62ca3cd453 b/scripts/.hypothesis/examples/1b1484081ed3fd25/ba46ab62ca3cd453 new file mode 100644 index 0000000000000000000000000000000000000000..a5a4f3fe150b92bba17ae095274faeab347506b0 GIT binary patch literal 56 qcmZQzU}RuqWaPfV0bu|+3?KnUMrM!%1DIj~2{ACJF#rLG0R#XtDgiYB literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/beb22e8fda6d3624 b/scripts/.hypothesis/examples/1b1484081ed3fd25/beb22e8fda6d3624 new file mode 100644 index 0000000000000000000000000000000000000000..59bf82fa0c696f7178f70b138328e71f549a09c6 GIT binary patch literal 59 rcmZQzU}RuqWaPfV0bzhR3_t>efq)q(3&Jc6j7&fw5Mo@f!2kvTIx+$2 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/bfbaef26436147c7 b/scripts/.hypothesis/examples/1b1484081ed3fd25/bfbaef26436147c7 new file mode 100644 index 0000000000000000000000000000000000000000..510411f240cc2be76c4c625f1bd9fc69c7f6269d GIT binary patch literal 56 qcmZQzU}RuqWaPfV0bu|+3?KnUMrM!%1DIj~2{AA@F#rLG0R#XudI3=Y literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/c1cc056370ebfcb9 b/scripts/.hypothesis/examples/1b1484081ed3fd25/c1cc056370ebfcb9 new file mode 100644 index 0000000000000000000000000000000000000000..62bba953302de884d2bb603c15ad2d0d27d09092 GIT binary patch literal 56 qcmZQzU}RuqWaPfV0bu|+3?KnUMrM!%1DIj~2{AAPF#rLG0R#XvIsst- literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/c3f6ed0ecc258a1d b/scripts/.hypothesis/examples/1b1484081ed3fd25/c3f6ed0ecc258a1d new file mode 100644 index 0000000000000000000000000000000000000000..8de9b889b4009ca92cf61ea9ed6bd7a10f67c683 GIT binary patch literal 56 qcmZQzU}RuqWaPfV0bu|+3?KnUMrM!%1DIj~2{AB)F#rLG0R#XvY5`>c literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/c810786f61f8ee62 b/scripts/.hypothesis/examples/1b1484081ed3fd25/c810786f61f8ee62 new file mode 100644 index 0000000000000000000000000000000000000000..cc84cd37e7438938bc300efa90f0bf94e7f0dc18 GIT binary patch literal 56 qcmZQzU}RuqWaPfV0bu|+3?KnUMrM!%1DIj~2{ACZF#rLG0R#XussU91 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/cbbe0110b60eab1e b/scripts/.hypothesis/examples/1b1484081ed3fd25/cbbe0110b60eab1e new file mode 100644 index 0000000000000000000000000000000000000000..6544d0a7eff80d73cbedd0369817c1ed7b7019a3 GIT binary patch literal 56 qcmZQzU}RuqWaPfV0bu|+3?KnUMrM!%1DIj~2{ABuF#rLG0R#Xu+5uSr literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/d0fe54bd0d08e1b1 b/scripts/.hypothesis/examples/1b1484081ed3fd25/d0fe54bd0d08e1b1 new file mode 100644 index 0000000000000000000000000000000000000000..bc10a154a148bbebfe864e83bee5fb4ff77b8935 GIT binary patch literal 79 zcmZQzU}RuqWaPfV0bzhRAk4@BBKbGUFfyD5F~M9$MrNQS2!kjV21X{JFbFZO*I)nx E0Gsavod5s; literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/ddae71054bfb727a b/scripts/.hypothesis/examples/1b1484081ed3fd25/ddae71054bfb727a new file mode 100644 index 0000000000000000000000000000000000000000..c0a5e95b0c6ef24c0fdaf61c9dde5307b11ae910 GIT binary patch literal 56 qcmZQzU}RuqWaPfV0bu|+3?KnUMrM!%1DIj~2{ACNV*mmW0|)>(iUGX< literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/df8a018270849f17 b/scripts/.hypothesis/examples/1b1484081ed3fd25/df8a018270849f17 new file mode 100644 index 0000000000000000000000000000000000000000..fa9ea2ebe543e820873b50427d247782c769eb91 GIT binary patch literal 634 zcma)4JxEqz7=6z33w>W%X(j#8lweRvgSZ6oMdT0>%_l$ubtq8en0m9-_F zr1&&Ug_^A4>+^ILII#J(fAqtyh08mK&(WiR#~Fl4G`n&Vc8v^=q>-<`WOXxm1sQ+d zqaUGbc%BFJ%Z2o_p?51`*H;yLpDy)pJl}D;SDH-V^NKPisc<8TfvPb#YMrK7W*AI? zY14)2>&4||^H!?0?bznj3rR3Qys9J`MWMnBoI5Z{MQ7_0$)04zo^Idat?G>2P`?xQ z7}&kAZ~yeELvxGUXIC>O-TTP3e!~1J8*p&#c4uh>Ws~X~komBQj0q~vmJ%z{_c-5< lN;nm?#eraQ-@SZb=J(+2nf%xdbT@`LS*BM?g+tSt{0FB9Mi2l1 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1b1484081ed3fd25/e8bb8c507b565eef b/scripts/.hypothesis/examples/1b1484081ed3fd25/e8bb8c507b565eef new file mode 100644 index 0000000000000000000000000000000000000000..8cd5e1d371b257dddee9aa19d517e59bdcd77a0c GIT binary patch literal 58 ocmZQzU}RuqWaPfV0bzhR3_t>efq)q(3&J3Z1uV|EUV{M)068=P>i_@% literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1cf837658f59bc59/23a5c6304f36e515 b/scripts/.hypothesis/examples/1cf837658f59bc59/23a5c6304f36e515 new file mode 100644 index 0000000000000000000000000000000000000000..d3b180a4a078f14eb3ab75ed35c4af3e8f5debe0 GIT binary patch literal 8 PcmZQzymO9`fq?-42|)p^ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1cf837658f59bc59/743c063de21f6906 b/scripts/.hypothesis/examples/1cf837658f59bc59/743c063de21f6906 new file mode 100644 index 0000000000000000000000000000000000000000..09c846c311031d9568eae68d0444f0b8f070b214 GIT binary patch literal 10 RcmZQ%l$#ZCnU#f+0RRh>0q_6- literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1cf837658f59bc59/891be2b13cf99268 b/scripts/.hypothesis/examples/1cf837658f59bc59/891be2b13cf99268 new file mode 100644 index 0000000000000000000000000000000000000000..ec99ca5b0058a81e5d5b37bfc94ae3300487604e GIT binary patch literal 8 PcmZQzymOwBfq?-42}S{~ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1cf837658f59bc59/8efb8b90bc6d5d1b b/scripts/.hypothesis/examples/1cf837658f59bc59/8efb8b90bc6d5d1b new file mode 100644 index 0000000000000000000000000000000000000000..3debc3aaf845d4e0031a8a69802c023ae1a92d8b GIT binary patch literal 8 PcmZQ!xpSVGiIo8W36lZ7 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/1cf837658f59bc59/98b97ef23a59af65 b/scripts/.hypothesis/examples/1cf837658f59bc59/98b97ef23a59af65 new file mode 100644 index 0000000000000000000000000000000000000000..4a473781b192e680cfd612978cb994f757c59d15 GIT binary patch literal 17 WcmZQ(_&SS~X(0$P++t#Q!Tk6 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/0f570acf7a2d9185 b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/0f570acf7a2d9185 new file mode 100644 index 0000000000000000000000000000000000000000..bd060c06a429230ba799bf25a4800fb788ea6046 GIT binary patch literal 36 fcmZQzU}RuqWaPfV0iqy)nUMj=VPIs}U;qOE9L51J literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/1dfcb9cb2a1bed4f b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/1dfcb9cb2a1bed4f new file mode 100644 index 0000000000000000000000000000000000000000..e03a9f8ca3878015fc626d46442516a1bc191210 GIT binary patch literal 26 VcmZQzV1xl?Mg|~nUUcI0}ud}FaQ8Fwg+Ya literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/4abbbc53950daa66 b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/4abbbc53950daa66 new file mode 100644 index 0000000000000000000000000000000000000000..94697724fa55e68bbdf305fef1623096457bd37a GIT binary patch literal 27 VcmZQzV1xl?Mg|}Uh%^|$0007406G8w literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/51f2607972a60cb0 b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/51f2607972a60cb0 new file mode 100644 index 0000000000000000000000000000000000000000..ab744c500e293e723a47a171c4d6424ff4d701b2 GIT binary patch literal 55 qcmZQzU}RuqWaPfV0bzhR3_t>efq)q(%gn&Y1muDc<9ZDSFaQ8Go&nB5Lq%)$myM8N=*EWidZ0%c5GJxk993>M7(nD*}- zLd`1N-NXuDZv8VJmQ(plO@S=JS7E_!U{h?U@(d9Q!qKZ}BA* GhIFi+@(ZK@ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/83012edca4c9b642 b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/83012edca4c9b642 new file mode 100644 index 0000000000000000000000000000000000000000..8f43bfccdfde5ccb200ef3a75558be9a3a867c68 GIT binary patch literal 63 tcmZQzU}RuqWaPfV0bzhR3_t>efq)q(3&J3Zg@KU?C=5c3>opj_002I}0qy_* literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/8d7ff9bb3c085289 b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/8d7ff9bb3c085289 new file mode 100644 index 0000000000000000000000000000000000000000..0068e1142e417b2a23746c2df95dbe0238637ec5 GIT binary patch literal 36 fcmZQzU}RuqWaPfV0iqy)nUMj=VPIUZ!2kvTA_f81 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/8dfa16e61c04bf72 b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/8dfa16e61c04bf72 new file mode 100644 index 0000000000000000000000000000000000000000..78f7258cc6be5e3dff34d1bed4bab04df1baa708 GIT binary patch literal 59 scmZQzU}RuqWaPfV0bzhR3_t>efq)q(%M3&;42(=bArN9*ufYHY06JR%>i_@% literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/96f7e9c7d5290323 b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/96f7e9c7d5290323 new file mode 100644 index 0000000000000000000000000000000000000000..32829b48aef06141c86b9e366b24b5e3bd3b3e4e GIT binary patch literal 23 UcmZQzV1xl?Mn(n(76vc?009L66951J literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/9ab01f4c4cac1750 b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/9ab01f4c4cac1750 new file mode 100644 index 0000000000000000000000000000000000000000..daa0c28a224abf70916116f13761800f9ea4d065 GIT binary patch literal 36 fcmZQzU}RuqWaPfV0iqy)nUMj=VPMqPU;qOE9tHtd literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/9bb4524b97454320 b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/9bb4524b97454320 new file mode 100644 index 0000000000000000000000000000000000000000..cef449748a68767c4424e4e8c9ee97902fa0f4fa GIT binary patch literal 75 zcmZQzU}RuqWaPfV0bzhR5ElPN8AgWF3_t-81_EZF1PFsD76wKppfCtAuGe4y0|1w2 B1DXH; literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/9c385d2553706367 b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/9c385d2553706367 new file mode 100644 index 0000000000000000000000000000000000000000..73c845e92e49989849ca659a8fdc3395ed65d168 GIT binary patch literal 27 WcmZQzV1xl?Mg|~B5Lq%)$myM8N=*EWidZ0%c5G`AN?P3>M7(nD*}- zLSz;0Zt4nPZv8VJmQ(plBtwd|42Ls}+}vnL2Q`DyF`xhQ!mr30ZqK~v=Gd=^dy6lj HFr;GzpEnDo literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/a6a1177199a6df6b b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/a6a1177199a6df6b new file mode 100644 index 0000000000000000000000000000000000000000..fb6223cb23fb0df7e61660bdbe9d4ebd026b78e7 GIT binary patch literal 39 hcmZQzU}RuqWaPfV0bzhRK)}q%0Aw*RuGe4y0{|rT0oVWl literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/aad353552de021f6 b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/aad353552de021f6 new file mode 100644 index 0000000000000000000000000000000000000000..27f83a7c37c8998fbf85acf374f8e49db7bf7000 GIT binary patch literal 52 ncmZQzU}RuqWaPfV0bzhR3_t>efq)q(%M4_L5aW6c1~32sGFSoN literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/b004d68338284599 b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/b004d68338284599 new file mode 100644 index 0000000000000000000000000000000000000000..83cb88c5adace3a9ae9e45d22f01574825c25caa GIT binary patch literal 26 VcmZQzV1xl?Mg|~efq)sr03pWp8Vq0n051&z+yDRo literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/d0fe54bd0d08e1b1 b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/d0fe54bd0d08e1b1 new file mode 100644 index 0000000000000000000000000000000000000000..bc10a154a148bbebfe864e83bee5fb4ff77b8935 GIT binary patch literal 79 zcmZQzU}RuqWaPfV0bzhRAk4@BBKbGUFfyD5F~M9$MrNQS2!kjV21X{JFbFZO*I)nx E0Gsavod5s; literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/dce91dce749f6c92 b/scripts/.hypothesis/examples/24e9e4a6a41ae1d8/dce91dce749f6c92 new file mode 100644 index 0000000000000000000000000000000000000000..eceaa99af47ab7b082e89748dd46e7c0778bc444 GIT binary patch literal 37 icmZQzU}RuqWaPfV0bu~yjEu~T3_w8!#`PKuU;qFj_W{=c literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/24f3a58f3bfd9f31/38b060a751ac9638 b/scripts/.hypothesis/examples/24f3a58f3bfd9f31/38b060a751ac9638 new file mode 100644 index 00000000..e69de29b diff --git a/scripts/.hypothesis/examples/3638c18229c6a7aa/38b060a751ac9638 b/scripts/.hypothesis/examples/3638c18229c6a7aa/38b060a751ac9638 new file mode 100644 index 00000000..e69de29b diff --git a/scripts/.hypothesis/examples/3c59094c0ffd5073/526ed20c15d7d31f b/scripts/.hypothesis/examples/3c59094c0ffd5073/526ed20c15d7d31f new file mode 100644 index 0000000000000000000000000000000000000000..0d2d6d3a2243a3c6e0f31b2d745047264bc47568 GIT binary patch literal 7 OcmZQzU}9uoU;qFB6#xVP literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/4cf0e7054cf98cae/38b060a751ac9638 b/scripts/.hypothesis/examples/4cf0e7054cf98cae/38b060a751ac9638 new file mode 100644 index 00000000..e69de29b diff --git a/scripts/.hypothesis/examples/60dc7c268a9a7d12/38b060a751ac9638 b/scripts/.hypothesis/examples/60dc7c268a9a7d12/38b060a751ac9638 new file mode 100644 index 00000000..e69de29b diff --git a/scripts/.hypothesis/examples/692c48c9c3c189f9/38b060a751ac9638 b/scripts/.hypothesis/examples/692c48c9c3c189f9/38b060a751ac9638 new file mode 100644 index 00000000..e69de29b diff --git a/scripts/.hypothesis/examples/711ef8dd1d4b67af/38b060a751ac9638 b/scripts/.hypothesis/examples/711ef8dd1d4b67af/38b060a751ac9638 new file mode 100644 index 00000000..e69de29b diff --git a/scripts/.hypothesis/examples/7cf50e557e3b6afd/38b060a751ac9638 b/scripts/.hypothesis/examples/7cf50e557e3b6afd/38b060a751ac9638 new file mode 100644 index 00000000..e69de29b diff --git a/scripts/.hypothesis/examples/7f6330c4ea890236/645f9a2740327990 b/scripts/.hypothesis/examples/7f6330c4ea890236/645f9a2740327990 new file mode 100644 index 0000000000000000000000000000000000000000..53cd53428ab3447bb071034ddf89eadc13f952fe GIT binary patch literal 26 VcmZQzV1xl?Mg|~lu~SxuUOtCCiw^XlH1CW_ZA8nd%1sH zS(P{0)c!d1GuhU;*ZY<)N3t*(?#%JBoJ7W8C+732)o>#ha@tNguZ?&jYNTn168j%x zxsE^lkztBDg@SE}x|s_yeG`?4pGvLP>W b88A~TrFLc-)s^#M-6>w`A5HL<|KGwd&D|k9 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/02e3843ffeffe8de b/scripts/.hypothesis/examples/972da276db8e758a/02e3843ffeffe8de new file mode 100644 index 0000000000000000000000000000000000000000..2e7c99e41e8af0124f95bf76b645774982f8e263 GIT binary patch literal 833 zcmXw%TZm0j9LB%j-gCw{H&cU*hEY7Y#EXuM@Z>?sEs>1eB@gnTP=un1FpUV0Q!^-X z$)!m1q6jY<;=Fkb(6yJJ5FY7A-@A=!Rp1 z=TI+N=!AK1&|+w4S&|*?MkB6Foiuvp1GF9up(6T#E~BN$8M~m^c?W%yfnv@_U(pK4 zSAU~!v;oRrUODV&y?fEW4lReq36Ibgw8tG*?L||9AsQHV{_|tb`#crBLkC?}Z3-kE z50IRfM{&p-(dT?&^2T+SJ1~uNkpnzcHzWN^gW8}y?p4c;B>@e$Ptp-ZxJ3Nn3m2 z8EQj|&_;B`Wo}#-U0OnhZljA)YtQA5uaP}`?1PvFh=wDP5YxQJ1(Pu2>~z%Wm)3S~ zzi#<3n%dy&s4H_pNfcj=tI>Ox<#MUwYV$v;$o%phf6-|R$R(-j|C9J+&chD_x<=|0 z+H7BgOpFlHXZUX4Q#*Qrj-o@3Wex=38niN_IxCaoLQ#&=l;mb%Y-4$DY4zGnjzg0V zC@D>BE6=C|qL&TN+zYjL#U_vUq0dtt83rs5hT973MTN f?eOuaqQ8k&Wc~ zoI_OZMp0X;B7(+x?mUN+^#!fyl??iom0{8P{aMtbFS^3vZTyJ_IDO{AqX~7pImi12 VJ$%ObmiEQlm&nn0%-Z^AvjHsR4Cnv= literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/068435dbfebb1103 b/scripts/.hypothesis/examples/972da276db8e758a/068435dbfebb1103 new file mode 100644 index 0000000000000000000000000000000000000000..526f76ac45a71cb2d532bbf1d38489f4d9a066d5 GIT binary patch literal 651 zcmX|;O-R&X5XPV1{@W$D&4fq{41+F_bWAj?lZQa8Ac)AQpdvg(hc1C&K_NvZ1|c06 zwhRg?Qo#r>9->ZRQG4r{O zL8nunEe6`lK2fL{5BKIQIDBuCxVD11bRov;&n(NV=v)kY+zq~*u+a8fp6LBIr~@59 zr_g}w1J@kp^&E}*!d647#*Jq#bACXc;p^a!T}0Yp=iB`DDc#+ThW*jf>&KsGH9sEf z6Espojm0kXB@IIPykeWhUsYsp#ldxS$DmxMBp$Mhw!1nNTJd)qo$)A>EhD3YY3r7~ amtOP^T|@n@{onU7bR=19P4*2G_0m6Q##OKY literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/07bf2341d68a915f b/scripts/.hypothesis/examples/972da276db8e758a/07bf2341d68a915f new file mode 100644 index 0000000000000000000000000000000000000000..1baab077cfe058db703e63d8ecb5841919777997 GIT binary patch literal 121 zcmXwxK@NaG2m_~!`bh8o{|gSRHYqei10jlDIEyUPLk`iZ63Dkx&Ax0Ref^K&o@SHX Nn;-K4P7&(T9bQjH0VMzc literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/083574e6d9a050e8 b/scripts/.hypothesis/examples/972da276db8e758a/083574e6d9a050e8 new file mode 100644 index 0000000000000000000000000000000000000000..6e7e577b42195bc8dc8da78fa994527d8274b0ce GIT binary patch literal 455 zcmZ9J!7GGO6vfYP-ps`GVa1AOD|?c#vQTQ)GG&A0AF;v2&T?vGLCJ!JWMgNgh}l_C zlM)*iqU5~qW#jd_?|bK-cka3O6T(aJkYf-9f31k3p+X3OlJS`HJvbP@L0{-Ra?pE9 znJmiQe_S+pglBc!q_dEhOR-&8Cr`YpcoBxkDTVh&nQEWXcx`qj8(`Q$LK9D lWRWR!VXS$N>gdYll~U1&C+YuCj9@wER?bqWrO4&vBAX7QjIJqS+J0ue?XCDXF*L$ zY*>hrbHA63udn;wz4yFx&b>nTQyg+kqU76}D7#cjDN%7fdd`!B>$m6&T?Gcc=a#{u z>i-Xm#?dR9hg#e41GEUeFE<&Fwo!i}PJL$>HEpA@KMp-B@&1qwrOyZ{LXhd~k)6$C-} z=59fBvzeKlIrFzd_$ZVtlPGMxiJDzSN{Q0`i20o?>|diZS_FfRIb>MWeQzx4pabed zV`Kaay+Uih$~^i&PgQf8pD$?SF`fq&r)i#Hj(*TMcbP;XZRKfDS;~{p_}!qH_3(n; zom3>%qk1gkEqLs@#}c*S;d_UAv4Qjdm?F4%8m-K`6}$K+YWH}gr7AD;|D|*VVDTF0 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/0b467a037be792e7 b/scripts/.hypothesis/examples/972da276db8e758a/0b467a037be792e7 new file mode 100644 index 0000000000000000000000000000000000000000..35475d691f445196e7d25ec64c3f13b75ec91634 GIT binary patch literal 424 zcmZ9I&nv`H6vfZy`{p|_4OXmZwz4NlRu)QGPm~Q7{t+8LVrQvF7L*kW+4%<)X?7OW zq-4cHl$`s0*?7IqyYIg9&OP@E;iWiaOrmhKA!<$)DJ4qhS}}Z{XAf8C6z%6KCn2Oq*$pa7 z*$Iu0F1ql!^@FzksYt4adNkuM7@Bd78#Dp~oo6(U#!v^XqBd$-&D_cGoqt6?-)J4J zp$D{xdg#njy#sWNW=)v7M|03OYB{GiV+7Q~Q2)ebCH#V#=m{O7g-SY)x9T>)qw=6@ Q4&9A0#cUN(zW+z*7X~*gQvd(} literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/0b7ef15d6cd32065 b/scripts/.hypothesis/examples/972da276db8e758a/0b7ef15d6cd32065 new file mode 100644 index 0000000000000000000000000000000000000000..e2336c6e420e058bc227910393fe82dba8e0937e GIT binary patch literal 626 zcmXw%O-PnO6ot?8y?#>q`Lihs3|)rdQmLp`ErL)3Awr{q3ULuGS_ai3BB?|{qNQLd zBvkkVhPY`FxeAMN=OV!$!~_)zgXr9OaTsRaxpU^+bI*N+@K9{>nu&tHZi_O93R#v> zbUf~S&b&DO744zfz@VM{%3x9MxsOFB(I#qxibcbRQ72Sye97_X89J1bQ+j?J^;<@L zmzO_pa}6KR8#It-84V&W$!busC@Z02cM(l_fBX+U^`kP+WQPgp=% z2s+p}oru>^3H?Mb(S?NQhEo4~^eZJY$yqe#*zgb3h33%%bk8D^*`}hj=0dHu2`#w9 zy8~zpS;cF#8ftB~n`JvZq4Lphv=!{pqds&!y0w2^x7_WSI7NjWs6E+#BDFH1B0dSV z6ZW&_=o90IKA}@d=v8#z6~=#27i#nly>P&ZlW}f2EL=vdCOG1@-9UF-!KGf*5Qd`V LZMXjOLwWoMAq`Pu literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/0c7012a3a39f3a8d b/scripts/.hypothesis/examples/972da276db8e758a/0c7012a3a39f3a8d new file mode 100644 index 0000000000000000000000000000000000000000..9c16bfe4a39ebc687f20739da69f4dc15547afb2 GIT binary patch literal 51 fcmZQzU|<9R5XHdA1g02(JRk$gh6@7~M1dp#1hW8i literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/0ccdeff809c50925 b/scripts/.hypothesis/examples/972da276db8e758a/0ccdeff809c50925 new file mode 100644 index 0000000000000000000000000000000000000000..9a6be144d938617dce51fcc26305898e821bdd0c GIT binary patch literal 59 pcmW-X(G>sy2mwzuW%~~jc|IHvia-?VM`vipg iwm$2M$9jJWvpmSVj-}^7qjH!xB04a0PyrLXjRoHT literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/0fa0e7e44844d62f b/scripts/.hypothesis/examples/972da276db8e758a/0fa0e7e44844d62f new file mode 100644 index 0000000000000000000000000000000000000000..b7e820168b1dd3f388d058cd04c6fdcafaccfa77 GIT binary patch literal 645 zcmXw%Pe_$P6vfZ)eZEKOD}^u$3^>`w8Kp*yJ@61%F)@RSp%h zETian-1(e&ar`6tgWd!N{mQQl7A4P3ENVvI(P^lz7(R|VVEgKa9FIm&eM(OG_C7Rf z8I7G@HlF1grqL5LmS=esMEWeNLB*o1gzDcF^ve6-KQ!z|g-oSj4>NW_ZHsfvpq;R7 zVi6rjd(Z?rkJ?eA*^E6Dy7O1z=P$a1E}{i=5-p*prdqm#9-yNJ9G*wVU`vDP9J&%E zpeh7y-TyifFQYR0g6^Xe3DE=P(HH1PN@S8&^wzQQPpA{kqCV7X5vkawqP%RQR(lZ5 z+2Zvv^cY#iL-aM&y4-G-%i#$%1MBE#ut$%EPKqm{1*+OM$geb2b?$+&Mk+zbLf-_cDZdA&{aD)dkyW4 Zf}+JWxBh*jRUH5T literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/0fec29ba04f4a391 b/scripts/.hypothesis/examples/972da276db8e758a/0fec29ba04f4a391 new file mode 100644 index 0000000000000000000000000000000000000000..4f1971084ea9ee2e1f1a902f07b87a2d7a2c3456 GIT binary patch literal 860 zcmXw1U5HIl7+q_hd#-Wrxp$@p84XwQV2Br88R5x;(ijrSi1C*^$b&)=$~28IjR=oZ zGbodv{1j>-AUb;Kw!prFx*zK~on#BDNA^L`r-lt`TbqMeHZj z?t8>{D`d}d;v2D^Osao~USbm2k$2#F`rEm=I?Zi-{o>JKRIuBqZiK@yS90G6S?Nbo?TISaM!d zu4t)f7j#y;;ym$;m_Zi%MhIyaY9Fz~6_+#ODyr0+)>z4cuwO7lVPK#Bna6s`^AJT* zX1t~7_<_XUf2dLoU2^yG3!<4=MQkTdDni&fLuoW6xJz6yT-gpGz9nSiQ>QIODhFc} z1&EBXQrLvW+ao2@jhIGyVFA&tO}S0W?>nAK$nsl6kEbFSxf|9jd{9~(N3domKdXf3 zCY}F?bJ7!s2>D4)pCw`Zv2n;ao+Wn5>B&21x&~FgSDkAkUJ<8=?p3dDTk5^yLu@J-m?BA)EAc2Jnz)!DXDHr8L_;`TH!6swAnQwl7^yNuH`=haA6_< literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/1777dd7eb72c0eb1 b/scripts/.hypothesis/examples/972da276db8e758a/1777dd7eb72c0eb1 new file mode 100644 index 0000000000000000000000000000000000000000..8f9102ec5712bd6925b8d5c926a11f4e69a704ba GIT binary patch literal 621 zcmXw%Pe@il6vfZ)dwx>-m2Hv&LzhvsOe(UK3qi_2h{&+OB3wv|mO*Vqic$KALL%4H`yQ4X9s6*WgHv=^W||3n&Xg zN6$?s;tfWXME9awhv!Yp-I<9~RM?7IlKtmXD-$Z>lW^jb z{j56u!uYrI=yDQz7d>-@@n6)08jYiO4mfc#&Mk+;eWA0! zLGS66$)d^gkBbJ;E1HCS&GZVIhPIchl#kX?N0OX)qX(62qfm7CJWM^DqJ30Ov+M>T zJ;-iQE+;!7|4~E7URQt6njd8%H3juhjH{r1$T==hC$v_d&=~4QRWyU9P{C^E_6OhT zt5DB3nnSbb4o#psIhIWEVT=Ik~_W%F@ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/19fb647bb3ccd464 b/scripts/.hypothesis/examples/972da276db8e758a/19fb647bb3ccd464 new file mode 100644 index 0000000000000000000000000000000000000000..d74526b8fdba463842d5a67e72bcc9fbe15a9cff GIT binary patch literal 651 zcmX|;O-Phc6o%htzGkRtQXvcj!=OzREsY9oK>yKYbP0Vy$I&br zb9VLt8bM7iIQSVIh0XOXDRd3}F*0+}mVIx~IW&h#=sS9Zjv-fEg;M_uv>wEE}Yvx*;& zbrcO$P)}kP`j!Tvd|t85;&K_;Tk-ZP>N6;pDT#;dPupF38(Q)2E^7B2lPx2ogLl>) b@?KieM|1;qyLO}RGw4*ZxIfu9P*h24XWLb< literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/1a0c039784e55e57 b/scripts/.hypothesis/examples/972da276db8e758a/1a0c039784e55e57 new file mode 100644 index 0000000000000000000000000000000000000000..e51adf90fbc2ee05a2c3d157868cb6142367232d GIT binary patch literal 427 zcmZ9I&nv`H6vfZy`{p|_4OXmZwz4NlRu)QGPm~Q7{t+8LVrQvF7L*kW+4%<)X?7OW zq-4cHl$`s0*?7IqyYIg9&OP@E;iWiaOrmhKA!<$)DJ4qhS}}Z{XAf8C6z%6KCn2Oq*$pa7 z*$Iu0F1ql!^@FzksYt4adNkuM7@Bd78#Dp~oo6(U#!v^XqBd$-&D_cGoqt6?-)J4J zp$D{xdg#njy#sWNW=)v7M|03OYB{GiV+7Q~Q2)ebCH#V#=m{O71v4u3JmIS008h)a Rt~qo=#uVdKMEU+7rC+55E4=^! literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/1b1d129bddb55304 b/scripts/.hypothesis/examples/972da276db8e758a/1b1d129bddb55304 new file mode 100644 index 0000000000000000000000000000000000000000..4b4260ed291f960fbf24d138845b52613f670aa8 GIT binary patch literal 415 zcmZ9IPb)=H6vfx?o_k-s9!8AlO=V7!-pEWDi!#B$7cucCzJYo&po|#E%ok9kH#1Q$ zB_jqeO4hz76Q|QU`|PvM+G}qiycCCwNfeH@Md?(LQlfG`-h596=O54)x(yEc$WJDV zhW8&A&7*g;0?nT3Cuj{u-|jOX?W6I!IIV+ebZ8sxb;IB?d$>X8=qOh?3n4wrZctUp zPH2Ai(3Q{KAGGIBMN%WwqZxO>*n(@^p$Qo2zMv&Eg}P`1t)jNo%$*J2`B(JwjkeGx zdP2*nk1j0LKSrl$(S*52)PbQ%%Q>|ZBcKdJ!!y^l@GEN7ig~JalL4NP=UX~-6UG!H KRYdvzAEjRn4k?ZR literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/1c2783b8dc98eea8 b/scripts/.hypothesis/examples/972da276db8e758a/1c2783b8dc98eea8 new file mode 100644 index 0000000000000000000000000000000000000000..0b762df8869e7c4a9a00b88bc38f8e747cdb9314 GIT binary patch literal 586 zcmXw%Pe@il6vfZ)dwyd2`DarQ7;Z&rsc59D7DAAVHjNVw;N6u8mslP4vSS2Pe=Q zWEJ!1PpEad-7J^G1FD{%p`&1r9*v;B=+@X gufH_@^%`nVLLZ_bJB)WxA8PagO+}BaFgVkq{|C}Z4gdfE literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/1cbef7fc528c56c5 b/scripts/.hypothesis/examples/972da276db8e758a/1cbef7fc528c56c5 new file mode 100644 index 0000000000000000000000000000000000000000..daf70f4e55eac967e3f8307d6ed2348edfb16e53 GIT binary patch literal 492 zcmZ9JPbfrD7{$+T-i(+YR;*~YQkEoPWucU{OxYk=TUyxJU>ZBisqv>MS+J07?5u>C zodq?f#D;|^IrqJ6yk6h^?sv~U-#OnE!k@w-$4F$H&5Nu{nJ9|LxgO5Ej~raTL0{-B zV9*D6PSHLpr(Jdf zksf30k(vT~Fk=_A54pz$>V($n6B0DY2BOn_Dwe+4O#0?aqN3?~;6T||< zr6cr~G&0EuI(MydkBaCLt)OL#NQP}H;)ab{Z6CU}#icUZLsqeao`YJC+mDrXYM^5j M-bW!z_y42x3xGyA@&Et; literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/21b50cb21bde560d b/scripts/.hypothesis/examples/972da276db8e758a/21b50cb21bde560d new file mode 100644 index 0000000000000000000000000000000000000000..be7f8899e3912d2f2ce033ab2f5b55cfa1526314 GIT binary patch literal 506 zcmY+BKPZJ!7{;I9{qB`N7ZVfRRmw;bCWBIDxy68FHX1Ba@+UUqt?N%wGB8LMn@Nbf z8K_GM14WcP=le4FI=$yR?|IJiKF|9K;ZI?cV~afQv5Z{a;d3w1aD;ZyYEoq@ z5b0J{gEARe3Dxf6H%~%N;r1tz)6Hsi9rL0f-Nx#!%o&pKk-@bT1{R{H_^ISVpDS z)5Vuu!#DH^P3BqVgGf8F8dNOGN+|u^MoV5_U!ga?RLE2v>|w?(sD11l>!=>?%1eB@0<76rpG$Oe4Z_Y6e9v zxfE$Oim=fT-_F9+7=#*%DEU8UX5P+u&wF{E=YM&Q5ZMqp&|kCzZAWj>GSrW5__qHX z>P8D4Fz*do47H6*vZLMThcigg&6lXen~UE-1C%LEmJoc;=(8Xay9i ze^4jd0F^JVeC^wspwqh!Er+@ZkI)vh#}!uXMN@(y>KkqAe?UL_72v)~MRg2qF+ zs}EVbt9GGHnc}8l;tKAeK`uO$s-512wf-0>Nz>GDLm=VzJ!`ys-v|vSZR&+*s0A%T z8_^M`Sx3$U)EEME8(oZCyDe9IjqKiI9}HteFR~pn-*H}gl+I2^?Orssdis6KB%EMd zucMAkd+@j#?a+G{%I6i`Ec~n@6Dzd+L#LgTq^cPK|75O%4@Y*V&}RD>I%5R=9^-bp zFRkbWI*JbYF4G-gYtYJ!;;c-B6GbIbQ<9s-v2~TX<<)B~D$_OjfRggWmdcD~M@3|A z*prv&FxrZWXc{_?E}{Kso5?lzgx!uOtdFl(iKisVI@4W9>Wgz~pSJmURLTE9lk!P4 TDICu_6(+|ofC>#|!+QJ&=@Vet literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/257e17739921f7d4 b/scripts/.hypothesis/examples/972da276db8e758a/257e17739921f7d4 new file mode 100644 index 0000000000000000000000000000000000000000..61fadce78e61b9f47a2fff82d19db6fa3aacdc51 GIT binary patch literal 458 zcmZ9J!7GGO6vfYP-ps`GVa1AOD|?c#vQWxerfiV>6?Qh5*jY}EEGSv9kZkO%6frvs zYEojuLX@2My==T*_kHi&^Ugi@enNOD9&!w#;ICy-G*k#7P%<8Kz6S^6H|PtUM-F;V zDU(In`;Uu8(JPvTO3U;HnuqR}>%>Q!s5dW8wl#?Awo$D)d>$naXXpTJrz-nVNDs0b zR4U0%sC=~0iO=;PwBbjEpmJ1?&A1DC#$4kP^+8wj2~D8^)IVCZVI>a)wsp2q;EFokOR&@H5KLBicpNIb#K~`Z0RT n3t40WT^MWJqZ+zGYj&WNjb1!V|B7M+^Vx?u{XC!U|D*H^5~4DO literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/25c6c63a4fadf8a5 b/scripts/.hypothesis/examples/972da276db8e758a/25c6c63a4fadf8a5 new file mode 100644 index 0000000000000000000000000000000000000000..d3c368c125eddc7da10042ac91850633332b0f62 GIT binary patch literal 651 zcmX|;O-NNy6ouFKZtsz==MO|-U>G!!qG6#@jT#7&3PMCi2^P^n8aN4r3JOsyF$i%e zs0j%rYEXm|2T`N2$TxG4U{+M1K~WH{eV=%^=iGDl&suBmEkwG+F3>-81$Cj1s2Q!H zX?xcmq6u`;0Vh77)3CedOlrE0Hl3L`sO-pdbRMmv0{VnTQ4?~+H7E?tpdT_+MxoH{wBb3@w?gXBbT(7c+@IM@U8_Dn;+P_Z$6;CQtilk_xb8ocu@Ntr|`dC-2b+>IB(6|VtwIpoCKD=Jtp d@0jP(f!?CqsMo%oy4z7}D)DG4--)6^+5#^CRj>d6 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/260565954b6824bc b/scripts/.hypothesis/examples/972da276db8e758a/260565954b6824bc new file mode 100644 index 0000000000000000000000000000000000000000..5b6c66465b80e06f265fb12706cd7536891f28bf GIT binary patch literal 182 zcmXwzu?@md3`Fn6Bt?YiQqwX5Q!qeMXB(0km>>%<1QHEHASxO}#hI^I_Srt4vD2$9r6!ylV<4}=OqI5iRekX(D8?;C7!9ly6GFfze|GDTE zZP7hcjp=jr0GHqE%tz1YsvS=63ZMgEV@DIaC2t;_s# Fl#WLL8>#>R literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/27558a17a64f7ddf b/scripts/.hypothesis/examples/972da276db8e758a/27558a17a64f7ddf new file mode 100644 index 0000000000000000000000000000000000000000..1703603af72e74114077e5fad50271dd00a02d91 GIT binary patch literal 51 hcmZQzU|<9RAjJe^0V!r6W&i>Z8%dZE#ESw+000F00CoTX literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/287fdf02a3c5519d b/scripts/.hypothesis/examples/972da276db8e758a/287fdf02a3c5519d new file mode 100644 index 0000000000000000000000000000000000000000..916d08415e680b63de7290c1c5ec4a061989b58b GIT binary patch literal 216 zcmXwzD-Hrd5Jcy$lQ&=KwOl|x#jo9qU~C_AC*T6A_@e$dLiqx4J77r#Xp A4gdfE literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/2a506e179c21fd67 b/scripts/.hypothesis/examples/972da276db8e758a/2a506e179c21fd67 new file mode 100644 index 0000000000000000000000000000000000000000..e16ba629c5659132bb3a94e682aa224b61e290c7 GIT binary patch literal 52 mcmXAeu>k-u2*N`3O8-Bkpjm)`Pyq2z?R2MTyZFAy!(cuJKLCLM literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/2b466b85438b26c0 b/scripts/.hypothesis/examples/972da276db8e758a/2b466b85438b26c0 new file mode 100644 index 0000000000000000000000000000000000000000..e33265e72d1e484ba4c88ef72a328f1e6dd4d4ea GIT binary patch literal 344 zcmZ9Iu}*?P5QOLZkDr17R?-n#AHi5tQxi<=d=(mz_y{H>78X`EhK?5?p`oLpBve=! z3&ZSxK;h-GySF>DJ9|R-D4cAQC>%YCno~teiPHI~`JHT>U!h+#4-7iwlEI?xd&Z($ zv_}JItPOufBWUlI8ILCDx*AUN`36lbqjzuf^N}@tp?CC>r@TcYZDcj5EM+A$zSro} ze*A}?Oe&J<(LI*&7F^wV#sYPqHQS;->Y^EXKtt4vh1~8$DS{SHGpq0t#cKYT+NB<} KRPi$Yzm<-Ts~my= literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/339d42b139b9dfbd b/scripts/.hypothesis/examples/972da276db8e758a/339d42b139b9dfbd new file mode 100644 index 0000000000000000000000000000000000000000..20afe12a0868015d48398bbef062a5ff60634778 GIT binary patch literal 164 zcmXwyyA1+S3j}%>^+=1DpaMiP>5(L zs09fcSx|(V7E!BEDR(Y<@Uo-=3yOm1-1&IJF!RlwGv}Uj?02jP_$bZ<>ZXxt5DI<*GK~nW&MjBT5{8OyxHI zdkZDYD;3G~nnQ-Jl$yXwod`k}GK%odli?Alb;c7#X zk9-tqCyH>Q5j%5WHAARP5hd6CU!M1Q{?GIN@9Vy=>$>khLZG;Ezx`E2#X{Ob1&Kdm zhuALOie+Lz+%S0Hoahz{4Vd>vES9Ppm!z%TV%V9vL8E6r5bMRDD2or`vREpN*d>+Q z?}%?f6!(1bRjiOoeZNJg*dWz@d6mMkaQ$nZcA9B|7 zW5#`+D&C2MQdM7l@NqoK*j!xYL0g?9W{X}^?&}cOge_eW9|MvRj0s(H;-~l?$yI*5 z>806UnPFoVoDomNc&XCWFWdoF?Gl@k?x^*h@e9 zgyojn{)*G4EoM2%PiXpN3qub>!-&RHVzayb{}hI=9@BSvdadGxI4TYqTMUswxJIl@ zQfDQ1$xp3mT_d|$Gq$dFZe{h_WXGY&2goWDTWV)C2csXmPR)8L4vVd#Mobgu#U-&{ zY_q)Po|r>Y=nlp^xwn%njjg+s)z{3ae%j{kQDvW$CW`LG$SBeX9kACpDx%a-ag9hc GKmP#4$YDJI literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/357afa6b048385e4 b/scripts/.hypothesis/examples/972da276db8e758a/357afa6b048385e4 new file mode 100644 index 0000000000000000000000000000000000000000..7a4633fe359f2e41eb4f6cb4babcf68fc00b5b19 GIT binary patch literal 526 zcmXw$JxE+p5QWdT&y~1tw9-nk4T@z#5Vf)h1hlXb7h(}5SX-t@69OT+texe;`U4Sy zg#ksWU!(Hr#ICemhGiekfs+U+1ZbcqWUw1Mnm w4V{Nux7)*VJG`L%?H#%f^_bCnG!xTmo-b_oW+zTj;UtArJbbp1q2aGJHc8MY}8k=@q)gA5V26OvJpF9KoBIIjgUsH zv=9aH+x(cqWtrKXIXm;sB4$w?u?1T>?O{8iRw>0!;x(6hiAnrXzT~bl^4_EZV>kPc zl_hzTb)6UlKa)+Jetl?oIh5H^b0?1$cLQ6rrWQR2kM zKyKpqf8-#KT7_<{UWdsP&Mc?Lz0B!U|3y}1Uiz{v8`4X)u!~i9^QzACExWQKPqHRM jxk{8cmxjs%~voS;Rz@N0)-(sK0tz5#|H=s1VIq0XJ7@B zNncgnT@8YIa0gifgQ78*sT9nNx$2H7HyPE>#EUpMhqxz5WU$cxafu#rBL-wyiM}F+ zWb=ATd}2nl<8n6UU1A{_osrCQn>6f+4Y5pH);+UW@cyZow>6@_$ZuglPDZbMCnwKQlfG`YJMjh=XdA}tpkHTa>-!P^8Lf2 zTl9{G(5?-CK_j?4ZZjS|p{r&%7t_-hcni9Bp0Pna=*$mjfcj{T#<7YU{ep`i#M7K6JV&vVzob0ZgO(az I#{aj{54&L;2><{9 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/392767782dc00f6b b/scripts/.hypothesis/examples/972da276db8e758a/392767782dc00f6b new file mode 100644 index 0000000000000000000000000000000000000000..edd8098065a096cbc42e624e66cc1dcaf273bc8c GIT binary patch literal 651 zcmXAnO-NNy6ouFK?z^JTmj#g|CgCdet6ha&d zmV!b>B^c49LDVQL>dhJ?_*0aiK~W&Becs{R^Sk!mYprvIa8pe3n2CZ{7e&!Wg)Ga+ zeVzaXQRAL~3BMQpKwVI({6*vFG&FpFANaU;A~x?IK(A3FY?@d=hfoWeKxfe@)GBgg z_eADuRMFdi=mI*AKA|IM5zRQ&;s|{90UMLSeK|fO=L(9w7YclO<-V&}3qbcMf57APPv0mGerw;YEf1}k14vNoU%hTu9 z*L2rB?!Q6%&_Q$t-7uB#usQPTF&g!Ovm}Lf59UvzqfW5>1v-Z=o6GSlXh$eV3u|`q z?M>spwV}`G8q`#_qF!_>>ZcE@RS|ta_WotOSGW+@?lyg!XSed;PBi32Yqy6#kE-wM z!qaHD8Z{Yjs4q#U@?7C#=~o3=U+K;Uy62!mrX(QBu2}NgT-1tPKkBhliIyY7g;%aS dZsy(S9qL2ZjZObiusnf|C5pQfeFusL=|5-URj>d6 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/3a4a41f7a5fcaed9 b/scripts/.hypothesis/examples/972da276db8e758a/3a4a41f7a5fcaed9 new file mode 100644 index 0000000000000000000000000000000000000000..8077976e6cec7ad8351cccd3ac4cdd397e488211 GIT binary patch literal 145 zcmXwyyAgme3`3t{l9`x-0qB{ME!cyKjtc3x`23M2osE!#4BQJfqXR9bT2-l=kLJDH l%wOUaXFTHhC7aQ3POn(SEjF=FOKvn*Zu=9CZkRb-0Uz5l1}*>q literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/3bd6a482df088d91 b/scripts/.hypothesis/examples/972da276db8e758a/3bd6a482df088d91 new file mode 100644 index 0000000000000000000000000000000000000000..6ecb1e7155b6ad9b47e797ecf0797dfc76a22241 GIT binary patch literal 529 zcmXw$JxE+p5QWdT&y~1tw9-nk4T@z#5Vf)h1hlXb7h(}5SX-t@69OT+texe;`U4Sy zg#ksWU!(Hr#ICemhGiekfs+U+1ZbcqWUw1Mnm y4V{Nux7)*VJG`L%?H#%f^_bCnG!xTmo-b_oW+zTj;Ut{zUbQ3Bz4WCB0;oQNO9FLx$^C>x{r}b#uGU~d$ z{GH1+ETh+GBG2+Nh_ofELB*o1go@vr=&kohN9eI16*83vdlcg;sJ!YNAJGLkJF|nX zp;|P9dQcatGn=uOLwEiv>iLiQQ6E}I?PwRhG1cxQdVyLDX!?rU;8cz292yJ@C<{TS z8{Q@2Jyb&5=sCKc5Cc#eUqIheB9pYD700GGP&fLFhS5WdNM@Ug(w+;o+DmBFB|exy zuaH&DqHm$rcDq@&!xPSo{6Rm0J$f{T?nbvx&ij`8^L?D6!cNqY>~Bo1OsI%2LDi!D utgIe2e(DoyPD1aXAy*jxMNO#DJbLDU6DQ-`a#+2EZkXVr+t!Qj%i|cKMNCQn literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/3f95558bfd1a4200 b/scripts/.hypothesis/examples/972da276db8e758a/3f95558bfd1a4200 new file mode 100644 index 0000000000000000000000000000000000000000..e238a4e6eca0456eede3e0c1a5a918778e93fec0 GIT binary patch literal 133 zcmXwx(Gh?!3__u49nycNbc>GTmydYnE(rmGEK|x7v*ZD~j6vfYP-ux$~!HN~lR`w*x%0ek?Q8q}vhz%xomTF`{$%2LKd;vw8odq>1 zS+Ni$=l)+dUa#}+yYIYn&%Hu;DGnKvs5n{|Ri`Q`B?{-`&G%$*{tkVi>)@dG{A9AI zdH-?IBzi*&Q16(2h?b!L^)~a-4jL?r)7TwFE!$`=8$Qpnhbwe~_Hvcu5YnUU1{Ht9roA1fs{2ls2*TF&W`N?F_ z@c!eXS@edMq1iM22z6li^)~a-E*hNNR+7G~+H9nRAUBGzLT6XS9eWP#3MC71Xwxxzpi0|B8OT(FR&a z4`>PX(V3~UHaR2}S literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/45e13567599e8a88 b/scripts/.hypothesis/examples/972da276db8e758a/45e13567599e8a88 new file mode 100644 index 0000000000000000000000000000000000000000..dc38b79c9c2e85edfb235df745dcd71359409df1 GIT binary patch literal 106 zcmXwxfeip42*ZkcrT-sdhe`-6WsIUMvTzP+Hd4c633HHzkEd0F|JBd?x)RsET5dB8 GNpk=kg8-`l literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/4680e69661a2ed6c b/scripts/.hypothesis/examples/972da276db8e758a/4680e69661a2ed6c new file mode 100644 index 0000000000000000000000000000000000000000..dacdda574703487ceda54d1ebaff326b7b6cde90 GIT binary patch literal 96 zcmXwx!4Uu;2*Uz6rTY(JK;;3ww1prX`ruBY2C1P~!Zu{h^J$gfx2C*rs^3jc+c_2G B0HOc@ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/473055d659fe0ab3 b/scripts/.hypothesis/examples/972da276db8e758a/473055d659fe0ab3 new file mode 100644 index 0000000000000000000000000000000000000000..26f5f3dbbeae26599dc572d5515f8d975d11a7fe GIT binary patch literal 996 zcmXw1TZm0z7+q^$jux=&VrSS8E3 z<9?D~G1_A=j&umYjBFqEK5HiGiS-WRSb?l_6&&gNhuBJNA>I&+i9X_*D)pTvIu)dV zSv|yjvZ`*On|2U`73^EYMdAnXo>0jiGCwq#mfx}#s6Y0k{c6NGVmi^SlDpf8D}+Q}B0gD2;4Sp%?2#eKwB(Fl z7lx8f>LRP>oFpC-qsd%HFQFa@wS(B;x{JzEq+pa9X^*WdW`inJFtAO3@|sbBkkB9u zLuJTsX-c>w!ME?KThy@|4VMVx>UYh(`zJN5Qm8Uij9q=6*^xE*`rL}uE=R8MdlBTuHsq(2tfF42_GY~#4iKA&EHQ~VLtG&C z5SvA>)MayUhU%bwUA>e9KDN#zC}d|;J!z47Sn8xk=;9TcbPX1$;Tma(B4YKYG9DkR Sf~8+KKyXQIPPhgpPWT7e0&v#= literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/474f46dd4323d3c4 b/scripts/.hypothesis/examples/972da276db8e758a/474f46dd4323d3c4 new file mode 100644 index 0000000000000000000000000000000000000000..5f0ae156ad23fc9ac31073274bbed2b99629096a GIT binary patch literal 17 ScmZQzU|<9RAjuHL00aO69spth literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/475f9843b3de8544 b/scripts/.hypothesis/examples/972da276db8e758a/475f9843b3de8544 new file mode 100644 index 0000000000000000000000000000000000000000..d6ca9b4c8816cd16d3c19abf1df2101c0e54a2e4 GIT binary patch literal 823 zcmXw%TZm3k6vu!6bLJc4yO|nfG<=E&mw3_02u~iA+!D#iUGg9g3PmWI2-Ar0I5mSJ zmt2Z8FN*M@A?D44sWAvOqll9KI^Wpsz0WyoueJV{eGu}94b^!2BX)@G;;mRF2E+}Y z4V)9*Vxbe}y%CG0x~3&rXtx-4W$L8SGarccVo(&t2XR>}70%ct72EHKZx|@%eDPJR zkn(-MMW@&xmA}05u}^E=OTFvFa;bj8Be6y7afelV#gt$u`iGqV{Fw7TPZjUPL6`M4 z1QN#sB2bX!lE{)!VOI z4n|X3dtG#7`bnbrYFrBMU6#wG#HHqc^a=CJxBV5TEg+Yq)cz;&$()BC26UCwDY4m( z2ALQkq{r}`zM)p}LL3!`e3m&7fNR9cjOwgRjtfyaN>e2_3uEicb4#n&W^#Nq`2b02 zVoP~Ob0B)vjJWes92Q$eK}-|p#U-&{Y%{&)o-jURXv^Z6skf3OyQA)W(omRF_q5I7 aQAPg^6>|2X>V0-+VR!rtBHvgttj9mCN?_*z literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/47a605b9c09873ee b/scripts/.hypothesis/examples/972da276db8e758a/47a605b9c09873ee new file mode 100644 index 0000000000000000000000000000000000000000..e860cc72bb61378a7ff9b7a80c08d9640bf2b391 GIT binary patch literal 158 zcmXwyu?>JQ3of8T9-k!=m%6EE>^`Cg@M&E1F@r_R8nN;><%nD@SXYy>q7c0RG|% Ab^rhX literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/4c269d80e5f3ea03 b/scripts/.hypothesis/examples/972da276db8e758a/4c269d80e5f3ea03 new file mode 100644 index 0000000000000000000000000000000000000000..422e162ad619eafb2d8144dbceaec1b9c41e3f80 GIT binary patch literal 395 zcmZ9IzeyLY>@v$HFNkHX0|iNddrs5n%llqemKod3zj@n`gf9s+|VIc2b@ z`u<_jCK{tXs0|FiL3( zgxbdd-Ps@ipc5ArN!4JFVLSy(Tki3QR$!s`j&{%*>Y*0eM|HCqyB@l8Rm}5^+UN+q wqFppZH>Mh1pg!6*VB-ZfVQ$rQeb-q~R7X?IUa<}DvNFr3Sl=|C@&B##3-Dbf@c;k- literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/4cb886acce73eb83 b/scripts/.hypothesis/examples/972da276db8e758a/4cb886acce73eb83 new file mode 100644 index 0000000000000000000000000000000000000000..158b05d1a371642bc2df5e439b8aba9c99f2e39e GIT binary patch literal 401 zcmZ9Iu}XtM5QOLZFMp7rrqW7Dn-@?-B$b_DEebYj;fvU4MBhM&SR`PTM(lh6L6LMe zLK?BsLKGyk|DlD)F?Y8+H#@sRcqtAUlPG*U5H*L2loF-mk@Gtl9DhJx=r%a$J*P|- zb?;v;T0w7U6B;AaFVHs3zTRg(Ize+)ai+U%bZQ%|9mD5!_Hcvx=qy*c3L!nqZctgu zPH23L(9q}64?6azBB>tg(TuyGx#}8sXdY&IFK8Vtq8{2sTc~9VpS0DDwT@nHWS*DaFX2}h7%N?p!l?Qw@?qa|%>$RR( Ye;$N*LUz_XO8)TeyjZBgnSId#A03hdxc~qF literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/50c07dd5285c028d b/scripts/.hypothesis/examples/972da276db8e758a/50c07dd5285c028d new file mode 100644 index 0000000000000000000000000000000000000000..d72c3c877c5a8756da3ac69eca9dce49a91c0e3b GIT binary patch literal 350 zcmZ9Iu}*?P5QOLZkDr2|RN9fh}+ zdgvPsps_an3Ejcv*L&up2Xu8BPIKBpGs~!kHv8wS;T0{>W1g~zM%u_~P+7`KXzbSL z#eRH56BiXp_2?eUcney6&sd>rxR`&U8`MT~bdPRPf6hCspGylJpegT>49lihn literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/51e175f59290b93b b/scripts/.hypothesis/examples/972da276db8e758a/51e175f59290b93b new file mode 100644 index 0000000000000000000000000000000000000000..066dfed82670fb32092c929f78620c177ac960bd GIT binary patch literal 194 zcmXwzu?@mN6hr;;NeYD0QPVO4Q)GZpvkgRyKt(}8j~D`ph9M9Y4Wh!IQ>;7RKYvTM z5Qg%RIYi}YBPN!rh@iHfJO9IE{f@rqnjZ8nE1N~*GkVbqy-)|!hwTT{L;JiHKiZ=C iKb+Zai3ZnLtWBSD>2N_Ov@a<~hr6CpXIZ21&EW^EAQ3JA literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/527d00d01bb9fdd2 b/scripts/.hypothesis/examples/972da276db8e758a/527d00d01bb9fdd2 new file mode 100644 index 0000000000000000000000000000000000000000..91fcbc9be15156c3cd8b9a43cb26e4784b685c9a GIT binary patch literal 401 zcmZ9Ize4no27}T3g27C}Lr{SH%j9D8@Wb2GCmgqPxwV-kgL`=aJlky4^`K5Bj^2j>Uq3-tqoK61%m zQTP7CqGj}sHlaB*`~q#m%-dteqhmB%i8FPwfKF|rv*R$n%^vR2H9E^GS3#r~*$pa7 z*$K_hA-eN<_=Ar8sYt2^do<%NXsuY|0nNd5?-i}1HtL}++Cm+(8M_$1^RMXV8||T8 z^o%yp2;G=!bdE03ssT$+Xbl?krgQ2bMi7z}M@VaOiJQ3SXs&|c6OMpFAW&-vjth`r)^P!X0znXj*Bw~F zWYTu}Ufb6JK^?e*tbsw%1Wc3)X2w)`$MiNC<6I5>y6M@VEa)BSOYK5-+4WL}EC zCPrlQdWw8vPPD7xY%F@jQZl+@nddHQ*b`e~6{l>x5iXD#B26JB%pWCD$WPzIOhv(v pd3Rq%Td+0Ij3d!;<*NH)!Et|zQiXNoJLm_J8uv1*>LUN&0w3y*84dsd literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/5548191b52bf0151 b/scripts/.hypothesis/examples/972da276db8e758a/5548191b52bf0151 new file mode 100644 index 0000000000000000000000000000000000000000..bb2ce1e35a925e9a514b98df49fea1433636d6b4 GIT binary patch literal 95 zcmXwx!4Uu;2*Uz6rTY(JK;;3w(3T(^`ruBY2C1P~!hXn_=hG^|Pfd7VSJz!%T5tdr CIsl*m literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/55dfa55b86838da2 b/scripts/.hypothesis/examples/972da276db8e758a/55dfa55b86838da2 new file mode 100644 index 0000000000000000000000000000000000000000..259b7b45cc024dd19c2e714edd7ff50dd83df220 GIT binary patch literal 200 zcmXwzAr3-83`FPsvR@E_Lt{Atr{Dmfxy^@g1QY^+CmezVgX01Og(0XvWkb`QcBhke zgm5T}j3F9#YcVj@Lnu*O`==DL-#VXF}{fF2|>>%C}D~KWDhPn-%BYIV&f&~M_QnIFTnTPfeqgn4e z#AV_K@qrNK09hKFMa&0tkrc#gGk*31Vk0q3q$b7y%L(<^O{Sgd@ZD6|wUGEmtRj=@ zZ=##nq<&vtd)gkEA+mo1v68Ht{D{~}>{XvN`-ti0gcuwV>P5S#zsw-s5r@cpwchw} z+}db9_DhE~h^fR}qFy|?ajr}^&T1rh7W7I9zKCD;75n>xrAZ8NhiA%%*V!Py3`fLxbP!qJbyO)#T oYwJxyePLeB(+-8lrTR9@h&79B6~00xAUZ>1(5l6AhQx54PZkR^Ih)Gm+tvI_bKVp>tp!6{;U%y=! A5C8xG literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/586417c6f7a4c41d b/scripts/.hypothesis/examples/972da276db8e758a/586417c6f7a4c41d new file mode 100644 index 0000000000000000000000000000000000000000..5ccb77a7b7993f13374cde7d0fa4e517b6a71245 GIT binary patch literal 517 zcmXw$KS-QG5XIl`KJPG>i&k1iu9ZMaMMSME0)mZ=P|!yv{=5R6-I+1cQS3=KH*5ncbOv`{vDz5MGKywu#93HZ58l$|Xrc-tl;| zpV&BljBe3kV9>wp$zW0NZemd%`h`ZJSU0?iUPIf@Zy6pfqK-5&HwF8 z!vWetD_NF}AkwL<2Icdz5{lP#wCi*J9)0kqT%tm-M=`E~_I~I1f;!<@?HmoGE>uGk zXdIQzW^7OB&VEHbcW4Stq914kHP9zhH9n#>G+;pQcQgd8&rRphY_x!u5cK55UP^q4 zO6Ux&qE{(m21?62=y#gPB!lR)W7QK>L0{2(^v)vEW}AxAr3iA%5wkihZhx&#l`H8R(b##tv^!$ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/5aac9ed9f1e2ef5e b/scripts/.hypothesis/examples/972da276db8e758a/5aac9ed9f1e2ef5e new file mode 100644 index 0000000000000000000000000000000000000000..085d746753966c1d212bed4376ebc0bc7535b8a9 GIT binary patch literal 651 zcmX|;O^A(Q7>2LwoSBK^7)nHqM%jog31MZSD$tktPAAIJ{bmkJy9%bcQ6M#hu>^l0)v%$3)2FtFCN!o;yc(wUvr z981O7vQUOYc3?oRO3YlAcO|8Ub=ujJj(?Xg1>BXL%N&dHRZH5GWoP8E%+Se0BNFea zIwadF$Gv}rQ?wTkq;MO`?);V3<`t$|y)0D6i6Zpwv%t+weosry3G!-s{V%%X(zMDO&xvzlk;Nq;_i`*Qra5fO=}t=D9r zjk;21!JDcPbaqmv+4$CyXltDKEvEyj)#)nL3+?;J9l!tY@04s$A1hfw76*^QJD9oj Y$ul`3hl2d?d!wwcBrd4r2Z-J92O*|aumAu6 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/5d2a46b1404125af b/scripts/.hypothesis/examples/972da276db8e758a/5d2a46b1404125af new file mode 100644 index 0000000000000000000000000000000000000000..d3af0d9b899d30dae1a344a7f4b7f6f413636339 GIT binary patch literal 121 zcmXwx!4ZH!2m_OgXOaHxzXdm_%m85t$TFceQ6n$ZEgztj#2elnbILxA0{n+_f4#1L P9N+w?h1j6>ldO0EQ1t;S literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/5f0f6bf95410410b b/scripts/.hypothesis/examples/972da276db8e758a/5f0f6bf95410410b new file mode 100644 index 0000000000000000000000000000000000000000..a66282135878150737be321f4ea071c542ed1543 GIT binary patch literal 216 zcmXwzEe=945QM*J=@TymhsJUQPQd{{a}^9f;Rq-M0)-(Q;w6~pxBx+cAPB;ghD~?2 zot^FuLJo4l7*X(ThB~G~j8Vya?)e=J<}czc&RHWKrDZXyeEwQ75_d6{>elkDm`J@_ zQ}kjf`oHDsu7+Z58-uCgbtoQAVlOsj%PtS%irt8muoKnKRvcaDAF=SK5UKEZ=NG?` B7Zm^i literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/5f66066ed6e612f2 b/scripts/.hypothesis/examples/972da276db8e758a/5f66066ed6e612f2 new file mode 100644 index 0000000000000000000000000000000000000000..b0cbeea11554dc3c5dc372c6d902a3398f9c7535 GIT binary patch literal 813 zcmXw%U1*PC7{;&P`|dyU|FRk~jVTU%#EJeg;mCoKuS7C2U&(^T*$`Erzi21gf!?7Ns2|;Q zwEsNnLW>Pp@D?qFnucZB(H=D9%+#QR(Uwec<4EI*-a~_2csNzN{1w)EGgFeLsp*DE!teXmc<+H3>QC9!i_cLL zT7ovCqfWDqDmS2p5THBgQsmlgx#AmS_n!D5rU|0pPyk}O;|bn9isxpcHor7Bd-;9a zZ8&aYZ=m)}eI#Cs3(*Ic$>kLHng7{~+*-c%A3EctBvth&{bzSO_-OR&G}>w>qlp+H zpxeA1zL{q95*nGA=f9#m4A+*F=b zF)EN%Bd)wcN6#wyPK|jQdgK)^Q_g!V~YL@ X8kI}pn!@w!uEOT{2~fViWLl5^WmjO@ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/61cd7c4ec836fe3e b/scripts/.hypothesis/examples/972da276db8e758a/61cd7c4ec836fe3e new file mode 100644 index 0000000000000000000000000000000000000000..6a5e140c8c664deea15116aaa6f5804c1f4cf02d GIT binary patch literal 651 zcmXw$O-NNy6otR_uJ57GmkFX27zR$lXjoXJBL_kB13^ee2`bSb8Z-%n3Y17pQ4nb; zs09TTm7qwI22rCh(Kl<5pjKF5K~WH{eV-ogIrseRwbxpEBa{wQCh<>ni!QMwPKs6W z#ILKPVoDr$z>!7KDwWr_rB_$QPa_itRW!|rcCjuB;^6|8Malz&TG}dO7S}#$mgU-4|~} zowRFmMcBKuPKryZ6=7?UTCt<4v1lI8allEd1?^` zxU7%GNa{UwJdAem$%(RAqMP|&MPXt2yZ^G d!hPuw@5OD=>$lW*kew4}Qi%ss69%Fx*a92IRj>d6 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/6361d9e05211444b b/scripts/.hypothesis/examples/972da276db8e758a/6361d9e05211444b new file mode 100644 index 0000000000000000000000000000000000000000..b5c3dd6fcc4f4e580e040229c2326697876a6ed8 GIT binary patch literal 586 zcmXw%Pe@il6vfZ)dwyd2`DarQ7;Z&rsc59D7DAAVHjV1WMzJ=r9GcNC*0AY~~m0Mc>dcdS(-;*p{NS>qPDLCi>wN2Pe=Q zWEb=3Pq=lt-7J^G1FD{%p`%cb9*v;B=+@X gufH_^^%`nVMjxUfXBh9IKHTU7nlccr2+g$UKL{vE6aWAK literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/638731351dc3bfa8 b/scripts/.hypothesis/examples/972da276db8e758a/638731351dc3bfa8 new file mode 100644 index 0000000000000000000000000000000000000000..4c7ae35e88c32d0bc46fec544a73bedba701457b GIT binary patch literal 532 zcmXw$Pbj8Q6vm(5_xj||ht*h-twysX2`dYwSlCRyVqqrD+S0;CN`}~3D*wuqEGUwV z-K@kk>?|llG72@KG|zcoZnt~yIp?|0dCoaPcquOVOhnGFucE}RT#_W@?T?u4#E1RI z=o#$=20dgUgGH(LI~KK~Tht2`r-m=00jRz?%<$+t`j954Fw=-;Eu*36<7p$)u#48w zT$W`uh;$~aLHWF_go?*gwB>v96;1n7E>UT)M=`E~nl|S+K($b{bb-21Jz7G8=rd|C zo3YKIJNp&&yr3^=82v^)=o0-f)#W@|M(qZ){6d{jR%bf9zC{Zt2|?u_w^QOPR6yrw z0d=Q{5h%=VqQ7Y(lXRec`xZ}75&cBtXv`wgW}Aw_l?%1nPw2=cj?SSqWECsuPpEaf uJuJ7w8!9LMp}Sy@8BL*~nAW>}ZMpY5VMT@gs4s1QQ##7G*+$eUz5WCHTR|}Z literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/649c8a4e574bc328 b/scripts/.hypothesis/examples/972da276db8e758a/649c8a4e574bc328 new file mode 100644 index 0000000000000000000000000000000000000000..3c2a5be2317353597abae45b9e5e89f8ac4f57c3 GIT binary patch literal 430 zcmZ9I&nv}26vfZy&G-A_^{`?^Z!3F}WM!e0wI~}T|A>trv9nZ97L*kW+4%<)>Fq42 zmy#6=QF88gvN26(?%X+Z?zvY8FU28a5;aHbqHwB~QlfM|-h596=kL%Lx(*I{&rc?c zy7wO!O`VXgNC55{fuVO2x_Ahw1`?(Gj}|E=U>s!H(Eoh z=mE{6E;_SR_W&KEX%i;y(G2tqTh6J?7y(5X>K(hRgkMk-J)uK1S1~rK0(r<)&jB8o S$6YvdPsS7zRz&&!AEjSJk}M?v literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/653a75e9986a553a b/scripts/.hypothesis/examples/972da276db8e758a/653a75e9986a553a new file mode 100644 index 0000000000000000000000000000000000000000..0bc4477afa69048381a9827639734b20d6044e6d GIT binary patch literal 85 xcmXww!4Uu;2*Uz6rTY(JK;=<#ff9s6FU%xrlnljE_CeP^A4`hgn)1G1wm1(60G9v& literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/6752d4feae057d5f b/scripts/.hypothesis/examples/972da276db8e758a/6752d4feae057d5f new file mode 100644 index 0000000000000000000000000000000000000000..1c787c5d3bfa4ada0a6d64750eed58504783d8f6 GIT binary patch literal 842 zcmXw%TZm6#6vfx?ocWLOzYI0VXc)zVOT1`ggeMP5Zi!^%E_sj#g(4J9glR;0oSH$A zOD;v47e#o{5cB52)EI;siYQt8`{z67+vl8b@4eREYab!J!iXB1KWIDJhTfp1Xb@eu zZ}2SYK?@u(_cdAsbxn)Y(Ju7enYn{T&bW`(p&?X8@6jc+1UX_Slsj&tuQE~G^UxQx z9E$zFQ5RYd^`BqbZEvly=v#}H!RYZ1(Pp&U2rKuX$x$I17rTi7~0{l(AW=CW_g~Qx5^g6-*vNh?wP9b zgw;L&6t$v-XahRzG-KBUN>g;ATj)aMT6P)n6|#(vd=Pv=CwuLQ;iOaK2F6A`Uga~> zP={Zd+iZT_Oc}^ZUqhWq4rP&iC1#{|PAe30#f*zT`jM+Fw*N(^%vQ*9)&4K#qbnbN z5Y*MuPNGc~IQoti?evl&mNX^M^l*Wv%pHo@2 zCeTfxN&A&mCbZU1ZwW?kE1xuafexW9sD!4XbLb-4hqk)Bmfny*RcPVjX*BCamZeGc m6tjlX?7AoIJ|0o_&(W-cwWv-YP0kK05q}3NHdd0-Hva&b?_mW1 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/67f64afe878a5e65 b/scripts/.hypothesis/examples/972da276db8e758a/67f64afe878a5e65 new file mode 100644 index 0000000000000000000000000000000000000000..a2cf5377b75ec637e03dbada77d2b123cd1df4b9 GIT binary patch literal 873 zcmXw%TZqk37{!0?sEs>1eB@gnTP=un1FpUV0Q!^-X z$)!m1q6jY2^lY!pWvVOULMY6>^p78e8S2H>o(g$w%F8^IZr_>^3R z1%)ynj6{6Ab~Db07OB$N>7v7n<~C2iZY8L2*{_Sv1SJb`SEFsb5Bd2V(e}cReqp(V z_P^q^Y4cf*(JvW4M?p`ohrl-TTQ|G$0VtJm~h?p~XCA&!bej!kzm2-k>}N$RZR zF8QgL);Y49#j*93x#iVslN}#TK0sEU*jky<5{w>por?8R92Q$eQA`u(#U-&{Y_q(U z-snS8=nBR+xwn%nwXLU+H5BL6J#F{)sFH6=GkMpd+KSY|s<*f*qR?1&jsTjUf1Ced AF#rGn literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/68b0244d212daf6c b/scripts/.hypothesis/examples/972da276db8e758a/68b0244d212daf6c new file mode 100644 index 0000000000000000000000000000000000000000..6ddb1d7bdd29ba5775317399766807b2db8b2236 GIT binary patch literal 200 zcmXwzu?@md3`Fn6kOCn(YFb9f6buk*wjmKCP*G6OBZfetp<@9=MT4j~=L^gK?0-Jl zCxk;;WDHTc+lY~=Dk2!0&zb*WFn>c|bV&_*myyMycK)@fK`*p|$=&ijYGL-g7CqXc m`EZ;~CUq-96#m(33{+Y(^_ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/691a4136d6f1b4cc b/scripts/.hypothesis/examples/972da276db8e758a/691a4136d6f1b4cc new file mode 100644 index 0000000000000000000000000000000000000000..fbb2c7d53f7c3514ca366131611e340e62f71dd0 GIT binary patch literal 839 zcmXw%TZm3!7=_of_xxl0CsTurhEZHN#EpI#;mU=QQz98TOD^O>p$J72VHy!Gr)E&( zkVBE?MiFi_#DC|))EI=CQAEjl_n&X?@7sHS@B6N`-t}!EJYo@bUjCpRXghj~mZ3p( z!?D40s244C!n`+VF*LL+$+mW*5m%;88a?v?T91ZM5q&_H(Ng4$T~O@2gTBc`anDCz z(F({{f1_@+0m@%qIqYb?vFKlimP6x&M`#P$V}wpeOyyjeNh`5qKG=_HiD?IkYlu4SV=B=@X@%P;9-TS6$ zK52I^JVR}05!#53xXjpffzlG4=r+0-wYFVGe2r}5V{ZhXS91jBNaVzA_2WW}NAc`* z)ajSjb}zqfc{6Zr^L5mfd7&hVuf_rCy~}dBRB^!hA5~u=(j?$FmW?^h&d2VU- z+N>RiCLd5zn%GvJQ3*y*+nyQp5*42&qMK_SGY zpcN=o^am1Y(;{pYQ`GEQG+>sbFbai1cFs@5DobJKCZcB8N8n$s#< zgGmEHlJ)0Rm^0!|)QZX`>l;K*kc)YQendz{B&tVmzV!z!MzTd@eYA<3Ul|)34&F!a z(014|Rz zqXXzL>OwahA9>B8T+h(34X!G;hHEVMT*mx_+{5X>k68q*xAkuG->dLo4=VZ6(&^*x z)4CqFbpj36vmVDR^et_KvRTD6^UD=vZTZ{((LE<+5~bup`_po3Z-OgcchQBA6K}7m f;H`N_J(o`O0rjKn_N~`_8l6lf?n~u6Q529vhfcnVs;kP zq{N1WC^_$Y*?7I~``)?doqO*6gz!>4q={xC{CwT;mE2Ku_xl&7dLFLQ7~K)vRXjX!M<4#eTlg z3R*^YXbyGIk)=AjXdg|QFm{Wkp=;1`hSuW<$fBX{k+VYh8Rh5^?V;I%u?BhL1icl7 hEHZ^IjWzFGSP6_4JVXD1EP}(`UUKGFyH_H literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/6ccc0acd42b04171 b/scripts/.hypothesis/examples/972da276db8e758a/6ccc0acd42b04171 new file mode 100644 index 0000000000000000000000000000000000000000..2be5fb84b385aea49a38a2e8672d127e41c7542f GIT binary patch literal 594 zcmXw%Pe@il6vfZ)dw!z!m2MOS!>uGPm5OTRLJ)N!M5NfFBwV)?bQ4ijVj$sC@K2DS z;vXoYjSHbwXq3Aa32KN5CMX5bx$|%sX5QR6bMCq4J|R35o4jVC;IBbZ=1?KaGK!AJ zozIyU$G6ZQ^dT_lcYbBCDEByc1M|E&iFVPvsditX8Fa&dwlC-wR5X~*p`oyVvJg~x zWi1i!qZ0aoCQ(O1JcQEN68e=AndBz==-AXZ)Q3KyQ8a83$!t?m+IOK=+k!S-;-hi& z23f@{+6%R|+s(2ao^avuDLM-F=+QHDFS>Pp{%N_#@8T2{_M)C-e{*VOLPdN9YL@M1 mb^TN0CpOTvB(xumxWf1^8bXa0(Q5~sI2q@b!{%+&C6E7IUP_n% literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/6e68172d082b368e b/scripts/.hypothesis/examples/972da276db8e758a/6e68172d082b368e new file mode 100644 index 0000000000000000000000000000000000000000..140c0af0459fb1a28666178bcc30391b707e23ed GIT binary patch literal 1233 zcmX|>ZD^Hc7{{;o>vYc9+1&eN+X?0eE0V|-SzAT;A;_)53`wc=BEt_+5L8f@P)ILR zl*}ahAZ!*DmY9`8ED$OaK{m;Kh>{$c6}51Jp_KifKJ@9F=YH<{zW&$m|Gyq$VxnYb zcV&qoPa0zTERs9l8fpCTK2B@*Bl^ax|E~}yj(DoLQ-&LpC`GW_X-jLl;k}*%mHOx@ z`g)`LQn$54B1}ePf+_ePJP|3k zN=EzUmF;ciQulI^36b?7^GO~I8GG4xChHtzoeHtUffE^AyRcaG`Xn`FQfKAn4f{G* zOkQ#IC#YNlCVSgN(dcXLyde0La zSE^kqP|lui6H-+1#_x*YasS6##&cUYH#3NQp&NIk3agcCj1CKW1*)w_mxj>tzIUVgJ$6_OCQ`nZ#hStu@+! zdgd?|9auNp6qJ1gl{;`dHiCc&O-t%Ur-O(nAY%>d$Sou&-cw`|Ubq$W2|Nm3N@FZ- zlu*WO>1}=ItD6@GZIR5V|FoU!YtY7DAHoa#+N8?+;#<*%Q=n%|&pTqn;Q9lK;1
  • f48r=uDt0V^Vbrb#Ea=6{84uKg}HR@K!OB9>qsu=13=C>KM+A;#GJH4;r qwrK~IbvOikb#icp3b=#lq69uWfs7++2vNDK0oTG!JQc_>g!C^<44hm5 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/6f291029da3d1de1 b/scripts/.hypothesis/examples/972da276db8e758a/6f291029da3d1de1 new file mode 100644 index 0000000000000000000000000000000000000000..8c0b2ac52602fe1514b83e799c0a0075988571bb GIT binary patch literal 827 zcmXw%TWF7A9LGQ3_uYTyf3g}fjlbf;A#OC8aOFbDDUnRhk_)*|C_>R9tch^B+EC<> zLy>l)2sawBI~P_ngxVBQ^8LO4d3v7bec$JI_#U1YA&=NljkiByhuALOie+Lz+;D8* zoahz{oiOi>SS-~wEy<2{i(yx$P8vP)fmkmFMNxbZm&H=yj9pT({f_vCfnv@VU&RV3 z-}hT|iVafv%PWT+t#vQ;t`p0p`U#K37O}@2R_zs2f}!Xia{lvU&ig!7yb}jq*4Ge7 z91oD3mq&5X9Vdy|qSs*iI>a?$F;~RLNJ&siHM?-)r}!SlwO&5-*6g>$X=4_g5l_T; zsnpdktleF^#HLJfWrR4vJv89P)lzo)E3EayNJ*NehO2^v-}kKX?tLRPp0ueKo{1K* zNNf~GTxK0LCO}gN;I_CJwRRhKd@bzWV;{scKr|eVgqUVLE|`Q3XQzvHzf@Yi{krAD zXliS(i;he`Nfcj=OX0oCa=Dba)clV=VSf3xzv8q7Hrvr4 z6C;H57{1dt)GA(xqvDWbnF9g1My$-J&dTJt5S61eRdTa1w!S>Kw0dnO$DzpwNJ}otNUU*eVKQnm8{miTz@m={5I+@fkx~7SBw*l_c36b?1|Y!koINZ9X1V a^xse+XD_PWXLsg+orvE-4B=~_?U_xRLo%_7_^1RQ-ea>_4Irj?TPqD~zCJNpSi86-@S(Z_BJnnqX zJUM=V?$J(Q(C_@pU{UVzfJHCRHF^b=Cx$PeK6rAqm*deCdYY0`ntqOEETf^{)7?g{ z;R{+rvw4=4AkueP4JsC8B~;#?pe?T-{-H@fDr71T_Ap}?RJS?DS5ymCi>Igy)uTl; zfO=7b*^F%o-TABV^A`=Gx9AAHL}zH-RA+N&3AG#0dWbsVQJv`=8i^867J@1ow-fON zDxn`}9(5PujruD#KF~i9A{Gi(He%-w2!f=u5z>g2 z7NQ{T$;A|2hBI@|S#$P2gP4!Hkyx;m(;l{yYL!y#BwuU!FA2#%%9q?#M&6rJVC-i7 zv9c_0vaY>h@H5%enb(JgmqVEwi#v6+D95qU-%9wrZamz|rJOV>7qt=3#Eo=1#EHF+ zq1&nCZ{@j9{$0Nu`JK!^V#i7$!U?XIMWcHZ~RoGq+;m2bUlW7#J9th?yG@OeQli6eA79 zK)n4LC$K51tLomay48p|)Qk9nU7}+grPP&D>{G8;@)DQ&vwX`#<;X{aLdJ3Ik1N~q zE_*tehkhjoy7Kna_;My|!*G|*H{~KSriXD~w@t&n+{k5{a$OtoLexm#6D3YQ=W>_( zs9|j>V1xrCe zr9V(an-)Q^ zCo8#z_h<=C=UEnlNIzvYs92PhP<^zC-gtlfA3gP>LZ-@Kk78T}wH?m!3Dv{J`QNAq zHKKWR7u`lpW;6C$=+0k7J*VhCx`)1_KD33FO||t5y+EA?v~8enxX@rahepE!Dnd}z z)whXw2bIt-G>du@VgyR%HFS^?nWPJSbZqVi8bn{vIC@|a$!t?m+Hs*)+ltm*;@C7= zL{{+R#E; l+A9;rKmUx{lh8Zpp(~94q9N3170o!{#K}0f9M*5i;|zT1N=g6# literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/76bcb06488e394cf b/scripts/.hypothesis/examples/972da276db8e758a/76bcb06488e394cf new file mode 100644 index 0000000000000000000000000000000000000000..7a94b90a72e0f3bb013704a631f1b70fc393a42b GIT binary patch literal 139 zcmXwyyAgme3_~TGWF}^zXG*qU6*?-Oj*HJ9MUov^CX^w1%LO{+4XV1^13nt>rorFV fYhCeJ&o5z?C%L@VZXHX^c2T*?A0h@Yb5a2xgMb9_ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/7794f93f7d176f9a b/scripts/.hypothesis/examples/972da276db8e758a/7794f93f7d176f9a new file mode 100644 index 0000000000000000000000000000000000000000..0376599e8cfb3014f1382919f30ba0feae4a4d33 GIT binary patch literal 1000 zcmXw1TZm0z7+q^$jux=&VrSS8E3 z<9?D~G1_A=j&umYjBFqEK5HiGiS-WRSb?l_6&&gNhuBJNA>I&+i9X_*D)pTvIu)dV zSv|yjvZ`*On|2U`73^EYMdAnXo>0jiGCwq#mfx}#s6Y0k{c6NGVmi^SlDpf8D}+Q}B0gD2;4Sp%?2#eKwB(Fl z7lx8f>LRP>oFpC-qsd%HFQFa@wS(B;x{JzEq+pa9X^*WdW`inJFtAO3@|sbBkkB9u zLuJTsX-c>w!ME?KThy@|4VMVx>UYh(`zJN5Qm8Uij9q=6*^xE*`rL}uE=R8MdlBTuHsq(2tfF42_GY~#4iKA&EHQ~VLtG&C z5SvA>)MayUhU%bwUA>e9KDN#zC}d|;J!z47Sn8xk=;9TcbPX1$;Tma(B4YKYG9DkR Tf~8+KKyXQIPPjG?#}~1GoRe_c literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/78a42c84bbadb163 b/scripts/.hypothesis/examples/972da276db8e758a/78a42c84bbadb163 new file mode 100644 index 0000000000000000000000000000000000000000..f01f81cbb898b1f69f81237e897db85c5b15f7c5 GIT binary patch literal 188 zcmXwzu?@md3`Fn6Bn67-sA(A?Q)GZpvrS+IY6^P95J)r`0#VT*D$ac6aIeJ&-#6`e~AhmuieOr!D3;Rh)-5B2~6 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/7971c1191d124bb2 b/scripts/.hypothesis/examples/972da276db8e758a/7971c1191d124bb2 new file mode 100644 index 0000000000000000000000000000000000000000..e0235218b43bcfc754b8b363e079c83a92f7b5e0 GIT binary patch literal 574 zcmXw%O-NNy6ouFKu21}VW)p)Tc~dDI8Yb1Kfe_fhN%+JD7U8&|kQ0%l6oUp01^WSm zkWx^@i36cgsF*Vc1+N!UK?;e2xc0etIrp4<_E~4`wf4S3_)#qKoQZ zbUemr8T~tLMOjUh}-k_TXT;E2wq2Y?@92$udP#1z4 zuP!Cx8Y-dh=r!t1h{sTxUO<0RB9q)gYmUu+LlyJ|jiFJCNX0f4rJ9XeZ715a#V0f9 zJ+g|o=x3;Px!o+6!vmVf|D(Ub9zB{w529P=`(Kv(Z#j11upiw^<-e9%nNSh`3>QDS co~@Uk8UJbn-AFN6lyv70?_SL}!pAI-yW}jaFr@*vHTc zIuH5MIvPS(pmO<(-S*}}&h%w;4ytP>&~|6@961@$cWu zvL3f}6!n+0p2sXSn>Iq(tYVt^KP6;s`JVsip_4L+Qu3f(vfQ=t;EGotx)yTc?G+V# eFz=A((t!=OzREtQgL)gp-gKoF8rfr_+<7Hxtc14EQ*FbHue zXax!t{Q*VVv;Mb6HJf@z|G1%*O*?ld&~IlZ2JJlj9yOyyR6uiR5S>9rbV8x{8m-D&@f|}e z=se_0>u3mFfy(7C4m+9)JJXlZIjF9kK-bYtGhDod4unHAzh?Z@edB%}L^J4)(@Hg= zr0x*O`u8d+w!1bST5;<`*TPQRy`q8- e)*bR(TF__Ih3-1GUH2t)A+>lUweLhxDQyBRBvr5g literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/7c1acad700f1c89f b/scripts/.hypothesis/examples/972da276db8e758a/7c1acad700f1c89f new file mode 100644 index 0000000000000000000000000000000000000000..aa40415edde0009f05abb7df4cde70bbad397cff GIT binary patch literal 121 zcmXwx$qfK83<8H-Mecw5Zz13$max$nfsltBygO=kKN^7qm>;Q|wd?IrzV9i%N`{#K0UZDU literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/7c3e15783e058563 b/scripts/.hypothesis/examples/972da276db8e758a/7c3e15783e058563 new file mode 100644 index 0000000000000000000000000000000000000000..0cb4441a677fc8935da0b94b6f1dcfc6faefc8e7 GIT binary patch literal 365 zcmZ9IJ4!@B5Jk^IMWcHWQ3R!9?APi62~oFkoO{WFls6KoDdy6Tw7` zG!O;x_B@=xrm3o~d#mbJBj!*Yu?3q%2iQxhDW%vZU$MMPO!5!%CAXC$?;R8}_H+NZ zvMO(~se^Io=d!JHulF5aj%8so+?kVQIgO0rPR!?3r{P8}<*b`>Q5*3@)JWSBB@RBu zavgv8BS$G}3jNx>E|V>sU(1X;S=8Clv#iUKjAU1~WSDN@u2kJ!Ro&-X_GM2VWkX(q aWMsu_Tc%OnH^0@J;-!Aj1n>C&E&KvGw;+%J literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/7c5c66ed9fb5b293 b/scripts/.hypothesis/examples/972da276db8e758a/7c5c66ed9fb5b293 new file mode 100644 index 0000000000000000000000000000000000000000..516efe836c8d413b50bf489b06e29c00bbcbb4c1 GIT binary patch literal 489 zcmZ9JPbfrD7{$+T-ps`Guwq5Cm9iuWD+{HpWy%K0+S0<#2GiJCPK`fB$%2JsV`nAA z>@28hN^Dq&l5^k7#_RRn?|%2(^PTfuA^a&Ua*RaA*@DQrl!>B})Ewv1xQ;qxffaE1<0CGD~o zi1a9{LAji)gu+K1op@dQLF>MhiIflQ!HiwdG3*|fs0-R^&uAR=pc` LC}ipWf0TX!rnEQ; literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/7c99970c2b50d45a b/scripts/.hypothesis/examples/972da276db8e758a/7c99970c2b50d45a new file mode 100644 index 0000000000000000000000000000000000000000..7946f62e9d749f5bed4b743fc5ab07b4149b548b GIT binary patch literal 520 zcmXw$Pbj8Q6vm(5_xi-=8&<4Fwo;ZfO~cAUDHgL4#RAFN(!xecGb6K`rSh*RSx_|D z%+5-PZ)ZXIlTav{Da~`N zG?!&r4kDe(YEV8eE1~dILYqFPU(q*z$|Wif_9(_xQ1jV2{-8SeuyBq#P(4~e1E?1@ zn9bOh(4GB?dj6qdG=z>(7rH=ern>lv7SR_2T8~gWRD3j@Lu1hb%0f_O(^g7+g^K75 z{X(57VibzA8|W@gWRf)8AW>PLHM5=~e{+H6x%ymFyd+l&re;`kg|K~}MZE<>%` o?P0kc-cU95jP8RyW;BBaV_NV2wdFo+hZhxoMLltMf;TJu2i)dAqW}N^ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/7cb7e261445e95bf b/scripts/.hypothesis/examples/972da276db8e758a/7cb7e261445e95bf new file mode 100644 index 0000000000000000000000000000000000000000..49daaf2de4c270701266f0b9f7492a034189dd1f GIT binary patch literal 55 mcmW-Wu>k-82!gP>vi}dsbV5Mr2cl5tnxPrX1XJK6>&5{Fi~xZE literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/7ddcf2f81e1003b1 b/scripts/.hypothesis/examples/972da276db8e758a/7ddcf2f81e1003b1 new file mode 100644 index 0000000000000000000000000000000000000000..8dc4ba749f72f7cdbb6d9060ff4f23f489728f4f GIT binary patch literal 851 zcmXw%U1*MB7{`DA=h-{+zVBu=WExW(_=potCLB3X@|8#?-;x74P$)vtBCLsUxY|(U zBOgWDi6We6#LgU8%@Ar+M9KfU-`wx>+|Tpg*T?_kdJyu84OMyjBX)@G;;mRF2E`4> z2G5BevCs+g-iXCgP1BNev|Eh0GI!GGnGeKzF(k_3gSae~3TNz+${lyaHw+ZleDPJR zkc$1kMVHth)qQ#8u%p%PrM`7yxl}*lk=P>kxWlTwVoER+1H;aLe$08Fr;2ytpv(Fj z0*T`RQt<6n9&*P?Vz%fr*uGA2O<2qo@i9^|lvBwro%kufM{%`pA9`!?TjsPe3(klq zV!Tw_Js_;zUAx7mq`0|4+@LP4@?LPUTf{Gmj_$!u{|k@(Fl3hJxp6CKVf;Ody?ftK zjVJByg=eBwED{^V5tq4lRdi_zCEOMlqt>?Lj<1DneC&h33pgAl&oG%_<-kbf$7Lns zf|ytN>~zuLm*zHaziy>cVau60Z4KMW2Pj;F+CI~@kZ3SGU1@ABl@#0zm$9C9of5`b&O%0zWmQkV49MQN_=W@&7F z-Q3#MYm*#@CLbWHo!DA8qa_f1TXiz)r8q3MijtTn&WlT8zu0DaExj>^#Ly1LGpVO_7B~}VHW@Z literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/7f2932f835f293a8 b/scripts/.hypothesis/examples/972da276db8e758a/7f2932f835f293a8 new file mode 100644 index 0000000000000000000000000000000000000000..7ff6e7172308ef414d6a26ff6d428ee24e30170a GIT binary patch literal 200 zcmXwzu?@md5JUZPBn3k0sA(A?Q!oJ3Yy%M^P*G6OBZfetp<@9=MT4mDW;jnChUI`l#d7~gH*qb0P@Yw@EE nnhwjEZ0D$VjM>WcIh71&bVR$d<&cB)a0G`m>WpkOzFGVLGHw!F literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/7f397c9f5279a2fd b/scripts/.hypothesis/examples/972da276db8e758a/7f397c9f5279a2fd new file mode 100644 index 0000000000000000000000000000000000000000..4e07a2657f08f7a585d76f23be16021ed71de35c GIT binary patch literal 51 mcmXAe!4Uv32*N^jO7|b6p!skK2nEnXwT7)|r{uoL!(cuJHvoYE literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/80e2951e61200b3e b/scripts/.hypothesis/examples/972da276db8e758a/80e2951e61200b3e new file mode 100644 index 0000000000000000000000000000000000000000..9fd324de8b479f91d258ed208321a6f4860e1564 GIT binary patch literal 869 zcmXw1TZm0j82-Ms&pyUE`y5k)jE19laETWk8R5x;l3OAfF>c9&JSY^QXd+A_!sFBo zid=Fj(!40bi-tIF9!!lvs2N3+eBV0FK6|ab&RYNff0uuOAV5C}n8qcTBk`BmN$eor z5i5v6;--QI&lA1GVg)RCODrWDT9(DFJ;aDI69tW({gBv53=tXek+?!ECls-p%sTH9 z-wot8sLCfOFU&Ie5=QZSw zrm9v!XX6%~C7u!!$x_b%AqP~ohu9KzSCpklfhskpIaRWD{0pwA8rY?Oc3K~a3`vsI z?RScf?@R2x2ZCxoC66yYCt8Um#Af2CB2+u)DlJxmJH#c|mHAM`H-yZ5q7CC24rY`D zh>Th3V8ro$rDTGM>B-K`Bs#UIv}yW%JEjt{{07k#QxQz=np=hsN=wrOZh7HnjS$^J z$3NnXVAGHwKg#K|Bn&??hdRg8#8x>ydh@KSPw?I9TpRI{I7S>+Y`l*KTt}>qROdu> zQBPU0su6A#$2XSem)5S2a&$EHAVO(!Yk5}Hh#FEI&3Z)~A+`}kVg_-6xJ(=%wu@f1 z&wYpt<)FV&y_AI5vfe^yD$Z+o)}ie&nQlo1sl2GSBDS!u&DVq|G?!GviNeQ!!tP-z literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/8282d34037c89183 b/scripts/.hypothesis/examples/972da276db8e758a/8282d34037c89183 new file mode 100644 index 0000000000000000000000000000000000000000..7d31b7fc1a6fc3f990bae44f9d236e4f2cf21cf1 GIT binary patch literal 200 zcmXwzu?@md3`Fn6kOCn(YFb9f6buk*wjmKCP*G6OBZfetp<@9=MT4j~=L^gK?0-Jl zCxk;;WDHTc+lY~=Dk2!0&zb*WFn>c|bV&_*myyMycK)@fK`*p|$=&ijYGL-g7CqXc m`EZ%JP)L!9K}gGi zDT9KFR4~Ggi>Ost)a+U$m>L>bP#8$xxdUA;_uY5T`Tm@9gh)$l0R2Vh(K+-9b)$Lo z)Y18S=ppKKLfc1l5H>bioCYowu|LeMVOet8NV? z-3XCbr3KUNKzq@wm9C7S$HTEI4UiOJX&3L#sXTjU=CW&X$n@bm>y}o8yW>LqY+2bzo<%ET{-*QLqzd;@7 z06K*RoFBO6Ft6um)DLzWQZ;VebD8r4at~hzf6OAn-gdstU$4^L-DudCmR=u!p4I%g ztxwQM4K)_C(3jK*<@1VZ7JpTdy%h)7(H(rTi7~0{l(AW=CW_g~Qx5^g6-*vNh?wP9b zgw;L&6t$v-XahRzG-KBUN>g;ATj)aMT6P)n6|#(vd=Pv=CwrA=cE)^?1G$H>QIc2r z%rw;Dm*zH`UpG?{ve?&9XHrC2BwvX!>7COGgwiQ)tqDWt9o7_0wB|(c9uDnO>knXbUQ#spuTKi1wkaF0Z9GCXgz$cJVZtB_qqy nuzHGFLuq#1lXf4EDEt3tR>4|ShmeM6hn0vQ1Qi=ANo<>cS-xQk literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/854b5ad550e6bc91 b/scripts/.hypothesis/examples/972da276db8e758a/854b5ad550e6bc91 new file mode 100644 index 0000000000000000000000000000000000000000..72cf867cd37fe5f8c17552155bd076ad34e935b4 GIT binary patch literal 362 zcmZ9Iy-Gtt5QV?*Zf=U;PoGBZ2p%*>fZ%%M7B3pR<4u$NR*O0iA8VtJRCwG&c{k;&Roz`x-RD~l|l9dNaJ#-c73o@#q%XoSIXv20QkHa@?9Q=)b1bbvOgic3V)${4am{L;&Iezf~}6{47zBg$1b6^7#vz!bHwx4jr+PC c+1wQ@m7-qy4=}q`umAu6 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/869db011b0b446f9 b/scripts/.hypothesis/examples/972da276db8e758a/869db011b0b446f9 new file mode 100644 index 0000000000000000000000000000000000000000..fc61eceafb3b8a4c252925c1cf17ddd40f8859a0 GIT binary patch literal 885 zcmXw1TZm0z7+ve%XCLF7eU7O?M#E7&xWtQ&jPT?^$t{tL+$9h4piqROi7<@_k5e_}UK@gy?M7y3+FwN<~uhgE? z@`u<(>?Gb1D~KWDreZ@Eh#q3G5*EBAmXZxE%i_^qVpPaPNn>X}BsLPmL`Dn{SBd3> zGWL*J$6ex^iTqzkd?i+qh1zeTi`Yb#zr2oNFA11eMfPtXR+5dA9uwP$eX6r&KQYZZ ziNO(}UYt%l{PKEZbvAgw)Ya95sF}O*F83Tu>3TE z$6okRBP6%b{+Bo_+B77Heyr(}EQ~y|hPuWx#8!3t|CeZAeWLHu^xBA*#Bt(?a#M>m z;W}b0}LkOkGt>sx&GwPP>*sNE?QDQq$BxVp7 zi7UiGVu$2a`#guJP#yFh-OEXcW9un|rsBMYXYD#3lj%#TAXP8wqlhC^KwkZ+5QXNF JY8WVf`~%hpVL|`^ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/87acf6dd5c0e6038 b/scripts/.hypothesis/examples/972da276db8e758a/87acf6dd5c0e6038 new file mode 100644 index 0000000000000000000000000000000000000000..e32c81bb21e1c9301f2656c2af84229df388121d GIT binary patch literal 452 zcmZ9J!7GGO6vfZ)d-F|9gB2^9t?Ws{%0ek?nX*ChkJw;hXE`;ppk%>9vhfcnVs;kP zq{N1WC^_$Y*?7I~``)?doqO*6gz!>4x$%QG{U{46NA=i@yP$8vHLlPA^t7JP3>rc$w1gH=&1&Y3M&IdG?B^S; zpk;K2=1>P6S*o*(_R*vXW4CA;x&|$0Xg!XAQZ&>(a#jdGqbhntduX;`tU2LwoSBK^7)nHqM%jog31MZSD$tktPAAIJ{bmkJy9%bcQ6M#hu>^l0)v%$3)2FtFCN!o;yc(wUvr z981O7vQUOYc3?oRO3YlAcO|8Ub=ujJj(?Xg1>BXL%N&dHRZH5GWoP8E%+Se0BNFea zIwadF$Gv}rQ?wTkq;MO`?);V3<`t$|y!h#fxg77@|#h1&y?|tsM=Q-zjt`Pndi#%td;J>G$%%MV-WfUEc zGw(A`j_;zsXe}`4JU=p6lzUubQ5!l#-B5XG_#Enm>L1%V9!;RzDLJJ#chIC|H1>J= z^D)=(1udYdJj?qa(pOmxDi&oWR9+mS6|bZJ(YP-aGL;8=n6V3L?m5Q>s)efgZ|DJP zK=Wt-Jw}aYGqyE!=eNSoKQx4%pncSZj?tp2j;GOE)M3EgJ#-&#)SJ$s=TQR6LQqB1 zY9c;GC3J*l(Zhsz2BpbQ=x0h~l1{Yl*xUi?LtE%28n%d3Y*SG>wNa~WK|8kiVhVjg zR`Cvp7GkTg$hT{e;J>KAf}$WgcRn13nQ!i#Irp4zbA4H)948r$+J8PB7Kt8pkh&0LiNuIn(}`AAG+m7g-oSj4>NW_O^b89LEB;L z_#$dUyU;i~g}P9q*^J#Ey7O1z=Px>gPNR?L7+OM4O|^6vJwS&IIPd`-flUpjb7(M1 zKvf9Zyys;iUO{E_8Qn)m6Jh|$!_U#Tl*lBl=(S^G3#bRZMOV-zi%7*b73CEhwc34X z-WD&6pvTB69-`$?>vFqUE{7*R9tch^B+EC<> zLy>l)2sawBI~P_ngxVBQ^8LO4?df?>&-4BLzK7>UC>y9s;;+~#c8GUkg%}Vwy*qGT zbc@9XEO;xHN;M73vZXy@*p;b4V`o1U8^xd~ijU%oST2m%Efw4Eitm^!=0fpJtdjD5 ze?+I)B$dCu_O^GcLr(7ou~Mp?^jNftz3#APpO_X3MgNfTFOD1cWx9AT4!NwaE|@qG zBspIm#X)zRBIb%-lkM*i*M-eo6`ulgDo1ImDNSxJ&uTI% zkX0keyb?#mHc=2W#07C#91z5eo$?8%gI22#Tb$ z5z>fNEX06#<}Nla%k1pgvuDnX5MGKyj!6{G_C;x^NGVYnk2l|wgYhTyjRwI%YT!oNcWjCm* zWGA#fhv?4d;SW0Ury{8l>d}n5V0P6t9?(2Y_utS4YNI~tp)J(0nz>8iJO7G)CTI`s zq8HRfBXnb_(K)(AYbGo|qjhL5SkBNvjDRxLBdSZQRtpm`6Hl~sYTJ%x8Hg<3|3~Q; DJ;oOV literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/933ac63db4c19566 b/scripts/.hypothesis/examples/972da276db8e758a/933ac63db4c19566 new file mode 100644 index 0000000000000000000000000000000000000000..758fad975e562c22ab2eae98c4be8da11f6891f5 GIT binary patch literal 65 qcmW-Xiwyuk3_+i3r|kZN97Mzqp#a1~(`XOFy6oVv?IL-E7YiQ<_W*_f literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/9665e857aaa4144f b/scripts/.hypothesis/examples/972da276db8e758a/9665e857aaa4144f new file mode 100644 index 0000000000000000000000000000000000000000..0724d98cd27af52dd058a772d7eb264e17558ac5 GIT binary patch literal 344 zcmZ9ID^5f~5Jk^j{--=vIK%gqX{H9wu0dkmOwHI0)fI192+3PjKd%a3IstA zZoh^RbUIblb?>cDBj!*Yu?4$CM>tBVE2Y>cU$MMPO!80iCHIvh?+pqW$GLx8*^)Qe z)yX{cOWD_z*T=?}Q&}6DyL7fG=NV&q5c7G{X1J4UxoBOkY9XG literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/97d0fe57dc4e9a7e b/scripts/.hypothesis/examples/972da276db8e758a/97d0fe57dc4e9a7e new file mode 100644 index 0000000000000000000000000000000000000000..18a7ccb4bb024708728f8e9f70f2e21157491faf GIT binary patch literal 634 zcmXw%Pe_ze6vfYPK4(aqvQ1&27_^C^Wl^E6S_IJ_2qGM*pdwsEiri_n!!k?vYFFj=C31w}!0?)#X>r7i|s| zvMi(Mc-;A%d2#$b`h(sC2K~sd3>GEN78dP6%jgJnEEqn924MZtT#iR0Xk$uFd2}19 zT1Ich%kO8ohS%r`s^wW81(801M}j_m0QI18bPAnBy=F6ZSLn`PMLmDfIdm3%M2AolJvCMH4tjw44A}hv?T0nprgLa0 zETAm}wQql!h!;^AeMa}u!GyQ~YMsAY?&_;JMTN)F(PaOQ)XId4 z_zT$Z+nnznJ33Tp+D$-V9;59WUy%RILD$}=mhmcxo-Fz8iLEmA9FlpE1~?ej@Gdu@;vrO~R?%rnWRiPm%dxpVR6`%oBQ$9dso18Xa%7`cdmZiC;>0vs zLRPVWzJ^+t+s$%0JfQjUFZ4awqesusaCGZ@|IKoLY{V`c-bVwe{9UP)2^H~oaOJJ* Y*>d%%@iRN;Gk##B)MG-mY!=2BOgYy^Y3mpXv zdP}bi7FC{qSk#T4(JW9LfOsDMt<9GbO=q}iq-uGpy6cA#@xoGGF$WEC6eF{pLB{aJ2@C)Cb= Rpx3}2g@01mnc$x&{Q|AOJ8u90 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/9d1523f2ea98267e b/scripts/.hypothesis/examples/972da276db8e758a/9d1523f2ea98267e new file mode 100644 index 0000000000000000000000000000000000000000..2c22b266090fbdc4865171df5410524fc0878750 GIT binary patch literal 81 wcmXww!3_W)2*ipwrTY(Jk0=jlN=i`h($ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/9d1555c8e1dc0cb4 b/scripts/.hypothesis/examples/972da276db8e758a/9d1555c8e1dc0cb4 new file mode 100644 index 0000000000000000000000000000000000000000..4b8a9f8234a89d795597a51f229529e34987803a GIT binary patch literal 509 zcmY+BKPZM#6vm(5_xj||i;0Q8Rmw;bCWBID`HBI_Y&2M;{*;MS8rVZIu7a9&=Qu%iP_=f4x={mKLxZRv<;-SmOVFME z3iW)W5j2dhP%kQ?9a9yT(K_ldp!E`UL0P@&>>3X(pd<(?Z#qbbA5e^L(F*EG5MvN8 z?xB|?kx4qyv3;x8D34Cj6q>Y%q}iq-esG~y+lhKrwJ5Nz0<7TD1to3<8Oa3M#^dv}hv;DHLH;Vi3_% z@DU_v^nfDTw1`@TN!^_b1v8}r3lszC%y;YKd(WIXXJ!ye164`<5f{Y;@maKr1u6IaCUP$=eC?Ek*seoKwwi|8?|ygit> z9wd1$kJ6$e){DJj+GJOU#3SKk#>Cff$)Svj_m&&0;%9&hUjFp9&$pc2wzk|6Z^cfj zdSqTWcSju&XH&)v|AZ6TBL^I~0_BolQCc5n%4Jz*x(Z3u`Djz?66p*tF!Dgx=r~t74GT(Tuxba@jTR(KL+rUePL=MLo2QHc-oI<}QTq{44tTM!RSS zJ)<==K$n&poS-w*HevAzt-#2P<(%4&5m1Jq(fONNC=avlEx?2ESWAcYZcH&rMU?OV GQThc!vM4_Q literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/a0178c41b8d476cc b/scripts/.hypothesis/examples/972da276db8e758a/a0178c41b8d476cc new file mode 100644 index 0000000000000000000000000000000000000000..dbbfe28e7aee665945eaa9631f1f47deb5570fb9 GIT binary patch literal 461 zcmZ9Ju`9(<6vw}xcYp82>xYSn-YPpum<&q2SzcL?{0#=11ur(^t0w~`1A}C-nH2Fh z1NBm3VGt$X`}<{ayPbRPIp6y|-*c`IUW$iogDBWr5{W~F5CTQVW6t+rvqfOMC6(`*qM0Lxk)NDSFat&wb0Bz@0_9KxV zWHqQ*l$B8aXrU9I>py72j|xGh$R3+<7xav|#wF^5uI3Y(LIbFY=Fu#wn9bPXs5^fZ z`}szTXaU`!8PrCHrfTn?Jv45>$Ss&Oa9~b7$`SbLRZ#{Qnigk7AMMOcea}T+}&K$g+&0 z<8kJF=E?Cd=p3yD1|8=|28()+3oPnJ2dEE9yN1uA0chIa&hh9qYE8*0zqyVkEu($V z)7ghy!zx-tQ+by8Akq(64JsC8C6rEf(PytO|Dg$ADrBk;_Ap}?G~afP4Ri%ASAL;h z)P^ePF?xvF&1US4(4F53KY!6P^b~zV_fZwSH&t~S&7nI6-295}Lc=xFIW!z4pe_V8 zb}T328Y-ioXa?O&h#@FXenf{Ukx6>cx?{87(IDDFqiDn;Qn5`%xn`qQ+l6*)@x>Hc zKvwY%{SLJ*x0~g1c)+ExQ}id;qetWDNp$OCzh}8eE3pfQ{pdj|e`jiCLPh)&v@E%v Z%~xL;|8^7INXeFwMr>=lCQP=mxSaWfCv?_OxE=Lrv-p|3AVn zt}_QGcsT6q+Iz3P5%Z{u$bwz0BOD~ul~U{zuetaoBJn5rlKYC0_m&D6hxvb4*_1cg z(a|*UOWD(<*T;sJQ(2h}cj0VZ&O>9oAMtt9INZs#T(l`ywGq#Rjr2WX;^<>4x6#Kx za+0F1Fs$9{GTFlAt;~3kRb8CC$hNG>L=I$E#_1O9M&;eA>OS9c7%yXLthQoq)g5!8 P!8~8;QD*su|1aSe5S1Py literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/a5b67f40c8e5989b b/scripts/.hypothesis/examples/972da276db8e758a/a5b67f40c8e5989b new file mode 100644 index 0000000000000000000000000000000000000000..0ead8ff99e00d706fe8ed2e26fc71fc48bf84399 GIT binary patch literal 1235 zcmX|>U1-&H7{{OYXKm-4&Ao4I=LGY@iX^f{)>aW-1UW0Lkd#_4GQ5a_pn}4LLVB6v z$V{ROW3#BR#Izh?fl!$UvPteDN^)dY)WQjdQtSKgqMP&b`#scW(A+jN4KFNb2V=w#8WSxVoQz4f4!HEp6Tv(!dZIYTYsk3tP#(kYD zCojA50P7movtlLD(@r~GZWr6&J`&vg$wF!CUZFoQp%a_j!2WyaDoL)NxtNx;OYMH< z+U!F0rsI|0j#C0dQo%4?3q{JU$NF0j-^Nq-F%3aT>(a$dos(k2?2nkbYiA7a8P~jN6s0Q+nnVa_QS8nWj3Bl~{KU%l_D@|Q4F_>)Yj5ea5 zIgG^w*26XhWgkK14&07H5HO)>NxkUw86pbEIKw$|3kizn6j_89ZpC~8kAj!dC`%h9 zlrdX+Ti^N8mL)-3B{OP2ZRgrrjPcip@B;5Psq((~HjLpEm>Jvij@T-2{Q*sI3*vyD z2+sK#qy52MG2S-tdB>i=+gDywzxf~YR}-AXi|rwNPWG5cV5%O%T9kI33|brVjmYyX&yvFvm|_T;uV%SZWfb0B#Xb$u2_~c!cmeP% zdm37sD$B}u--}l9-ycEsX_9jH^2!zcxCF3Zt%EZAQKjdU9tvwPS{(M8(;FI3sXpvn z*MBIqFd3QPqA|o5TZpK@RWNrKf$_`}rF!XUX;@nK51QY^+!VnHYf?3A}2nqyQ#e9Bf+WGBt z@;gE}lph&GRPI({V5*7;lKH&z90v0@)T2w*pjTO0ENbUpi)QGF=FoJO@6ZB9k89DR t7L9+$8Lp>jV;hsD;d3k=&gg))<;p&Pq`T|}r6fC{d3WgK*-^W4^9Azn6!HK7 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/aa28c21684eabccc b/scripts/.hypothesis/examples/972da276db8e758a/aa28c21684eabccc new file mode 100644 index 0000000000000000000000000000000000000000..449b465b69ec2db6bd96d2126d3a88f9f2b209cd GIT binary patch literal 506 zcmZvZKPZJ!7{;I9{qB`N7ZVfRRmw;bCWBIDxy68FHX1Ba@+UUqt?N%wGB8LMn@Nbf z8K_GM14WcP=linxI=$yR?|IJiKF|9K;ZI?cV~afQv5Z{a;d3w1aD;ZyYEoq@ z5b0J{gEARe3Dxf9PlzU!cQ5!ly_n>mq@EP;~YWBb9cr=EtrsR}fHKK9LXz2BF z{yx|68NEdld6tDB(w3|S6^pVGDo;1jNAE8#(5N33GL;8=6yqwWz2zLM=o(bd{ziAu z4K#}$p&ry=He*{tcm68s`G+2(ezbw^q8;?kR6CPs4&64Obscp=MZM`9dKwl`7J{xc ztt8@IR6^Tm8g(Va6DW-@qQjKPBpv9hV>7={FZzat(KCxkW}AxAt_!u=o9Ks29GpOJ zkX6j1KcUukyIHow6RMt{p`&1r9*v;B=+@>_M(9rCE1ICc_QInjozt#(*;$UpXU^7@%Lg*! B3j+WE literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/b00b258dbe043006 b/scripts/.hypothesis/examples/972da276db8e758a/b00b258dbe043006 new file mode 100644 index 0000000000000000000000000000000000000000..fed22c45e70ea073586a9e07867b5b5673fc89a3 GIT binary patch literal 127 zcmXwx!41GL2m|f7>5%z%;ZD?ZsvrU8Fvv2YHc=xF)FWS@k;D_;9djt~x2B(m711JEv<#|6grN-+h_n>! z4;W-eIN69y!XBP&O7(qb3Y+G6q~$eqTsLdqRpW~ zmSq$jk2{|;FOI)Qf6=SJpq2c}VA1Z`!lFIsJL-pyMZ+i1DcJDsU5-biXk$uF=}s@I zSVm9T%bzE?hL>mxRr4$lgGirbHKpvRtqe7=g?X70Ubeg^w?DOyXZdJZ@}&abP(2bo6ez& zVF7I+Xzh;YiMWAE=rg*94kyF~C{>=KA1RSZ4xrbLO?*UU^cG!5S1lr$Z7NC)7izUT zQOzY@siH^7DjuLOq1JZ0S+>Iy*4_M#eg=E==r$URZne%|Ew}k1PEp};G?47?ORY?( zh|faTjQ#A~GHm?VJldOto<`SPVf+`}p+?ha+yN&}#<}HCJAsaxV6)pcgf6*)W0%pk RFcd8{-TF5-j9cC=k5#@-QgZ+R literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/b1894fc8b294f2fc b/scripts/.hypothesis/examples/972da276db8e758a/b1894fc8b294f2fc new file mode 100644 index 0000000000000000000000000000000000000000..5985be4639b1c308f6f3353de9e358b7b849fde6 GIT binary patch literal 651 zcmX|;O^D4=7{-6Ud)74hx&-*;@^CD*DD0``Vmi5|f|B^x3s@c1^tDx##e#*jI(NQNWk;DB6{kX(`XMNAFr*r>KnKJi1o7I0Vo9NsMJblR+kvQze_ z-o^tmx2Ttq@$~fUSn@v3lQ(iGu=ez#g5&=>wU+Ox%g@RanW{aWB_;y&l#1D_-7>#yj^yH2YKxyYN(&$x7KKN0MJ~ zJ;eZS$;AZHZlUVbHkOi_FD0XTRO%P2D;*N$Gjh#potrQHx%Bqs_<6IVC(c}#fez|w z898q&Gifv^!)ktSOSCml{*f~Q)#_B_h4w?_jz1_|<#k$iWE_>OAWH|2!#fyj`{cPC VmBY#X-}ffjP)S@^$qx{_;V;_jRj>d6 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/b1db0ee037d0d160 b/scripts/.hypothesis/examples/972da276db8e758a/b1db0ee037d0d160 new file mode 100644 index 0000000000000000000000000000000000000000..bd60cd53ae77e32b1cbe14ec104169af25ac868e GIT binary patch literal 651 zcmXw$O^A+B7>2Lw`)0lvpP@w5Xq1h}k`PuFN`6X7Mkpi;S=gv46p1j6k}RjjPf^HE zk!&o)N<(}*3sYkdYAB-QKJUz&-gDmb^W4vU-_L_s4Qx~X%0AgEZ)Jmw$gRANT$HP_ zIswby$XcD!wXV84C_jR%Cur*8hq7Hpr70ieimaDJ9MERpUHL}1%C|zk$|mh-{gDCL zp`Bk|>o z98JdgvQ&mbcBEf!NX%T5k0qprb;hHoo%$u;3%HS)%Ph;Xt0ip4s`K(p=IHdnVTt!- z9h6;_;e`Gu)guh&C2PEzW9KOXNr2*bQHDe9%?vQpN_PB|7> ze6&RXUBv)*Dg8y6 zTra)geN_nB+bP}b_}P*O>p1;S&IMGf)0iax6s=>ACQoN&cj{PtmQmzC4evnu(jzbB Xxb)_&@?H40%H~SqlFCGY*a`muAqiEm literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/b25640052426d5bf b/scripts/.hypothesis/examples/972da276db8e758a/b25640052426d5bf new file mode 100644 index 0000000000000000000000000000000000000000..339509dc31938c22df107e884d525027fdf211ac GIT binary patch literal 191 zcmXwzu?@md3`Fn6Bt?YisA(C2DHs6iY!gsMNKHYH7y^lgArKV}qT-w{PX1^A^GQA- z3}ur!MCGXyGfP!OP+QNP|6#IzM_+VJ4|d|sK f&it@ON5@$0O`mhga6uPeX{z)Dp}4Q z_mljJ(Vl=wtU~}(vVGM1teL1M);ow}MY7ISaIEhiVk@zQctb2E`iN_))OVWbRFDE@ z^$_#Ps=9@4+CdCfux}9;i66v!LM401{Lo}#CKv}XNCY!{>OEpD(NAQJj3q20gt48> zwhH09v9dLr_(m)x)8*epJF!l9UthV~wu&IKdyO@KHDewUO~g*&EZ;>;FeOCqfU=%9 ztMr$N#9Lw?nJO2o9u6Cf`eRSFUyT??OeeZka(5eXg^=h=#3u`hyoDZ}IWi=fmYmY- z!cfvlU1ar~lf+|UG@0w@CDbFKb`Tp}cTri26pT`1?TK~8Z1$T9P?33u4hKph_C(RoDrutY#xp;V*db8{&4dE literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/b4bc0f30d70c584e b/scripts/.hypothesis/examples/972da276db8e758a/b4bc0f30d70c584e new file mode 100644 index 0000000000000000000000000000000000000000..59627c1e430c434343bd35399733f476be9084bf GIT binary patch literal 185 zcmXwzu?@md3`Fn6Bt;a_QPVO4Q!oJ3*@iGfCP*JK1QHEHAS#-OiZfrF{LlX9lYBxL z$|iG&%2O{^ma2%Lww^ox!({!AKIobr^e!u#MdSK=(H_0f0osS{BRazRc`JT&Mw{Pp bx?zVdj0=Y$VS literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/b686d72ec3131402 b/scripts/.hypothesis/examples/972da276db8e758a/b686d72ec3131402 new file mode 100644 index 0000000000000000000000000000000000000000..c5b09c60bb4e69d629c54a820219066938e9d2dd GIT binary patch literal 651 zcmXw%K}Z#06ot?C#`j2jX%LBlV$ddvmPJXmauG--1QHq*R7i_x;U*9&P(raD1|cm4 zE1{qy4T^BnB5D;D^>!^1%nA!MC<>%=|G{DS|M~BnIrp4%M+jevONW_Lz{cNM2)a% zasjoY7Bq=Yp%bXpY{u>l-T7DH=N~$U&Y};f11+M5rdqs(?xKSR?0b(6!-i(lxpW~S zpe6*>?s}StmrxmfMt9JWgy@5EWg7iRjZAU~&AB%55%r=s=qehph!nP|C@d6 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/b98009729ee2b3ff b/scripts/.hypothesis/examples/972da276db8e758a/b98009729ee2b3ff new file mode 100644 index 0000000000000000000000000000000000000000..5b338ebb46eac92e18a51840b7478b8e9672f95f GIT binary patch literal 565 zcmXw%K}b|l7=_O_Z$@gIvW-HZ%vO??MMb%CAqcu?BM#(3C0x67(I%p(#K471!Bj{P zDFr3mxDZ-}Mb6HJ!eodB859N4`R~KWefPfm-*eA@&i_9l{3sTA&P2gqW1{F#AnnznJ33Tp+D$-V9;59WUy%RILD$}=mhmcxo-Fz8iLEmA9FlpE1~?ej@Gdu@;vrO~R?%rnWRiPm%dxpVR6`%oBQ$9dso18Xa%7`cdmZiC;>0vs zLRPVWzJ^+t+s$%0JfQjUFZ4awqesusaCGZ@|IKoLY{V`c-bVwe{9UP)2^H~oaOJJ* X*>d%%@iRN9D}OpQUP88xD0t^Z`7z5o56|6A+(*808;f&hIbdTW=0X-1m_tReAH z&+|5-iP#*05g&BASm2D_e~6vL4&p7bf*2%jDBIvUqDLSB7W5NK$=b$c@n{b*Qq6sb zxJ>*YJ`gI|PZmdK67#`Kq7-9iKOi;|Lqy&}3|>x%znjc=i2dD)d@m%v5v#~-=|r?5-^6!oEikkODNi5QBTCdfS*zI$Kg8cu2o z7oHK##1hSuI4Xo_8E0y=8{8%?nyUeLCT|Ee^sx?H(14hx%FqzkSiR!6CGqPys)sItltZsx|<6`Klc z*GD@FO+AQEnA}{PRdz)^avhuXia0`SBXYzH;yiJQI6!QdymGJS5EZI}enqKnZI+O#7u8Y35h@_B{#1x;LqR!ARDJvd#)@gD literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/baed6326ebc5d987 b/scripts/.hypothesis/examples/972da276db8e758a/baed6326ebc5d987 new file mode 100644 index 0000000000000000000000000000000000000000..6c7b6fdb904f510c7f622dd1134945580e93486a GIT binary patch literal 124 zcmXwx%MHLV2t(~S>5#d1{}uY2DoB8TAj_1x#Ed*ZuRM`P5-;?6@Gxc*KLw%P+w)>y Qr*U%UO(WETc0Y8%2UIZuF8}}l literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/bbda293fec635f4d b/scripts/.hypothesis/examples/972da276db8e758a/bbda293fec635f4d new file mode 100644 index 0000000000000000000000000000000000000000..a8e993fd8593678721eaa338f05ce965e4dc929c GIT binary patch literal 492 zcmZ9JKPZJ!7{;I9{q7aF4-*sJRmw;bCWBIDxn)5z8x1xKZr5hKb^R$y1_sGuGYN4w z19jaJ3xgHnEe^@k#UeP4vYlc_QG_<{3rFgWCI+EhV8$GCG8HJ+5=V7Yh6z!vOT4gs7 z=|NV5ayeNE`Hvbp_PY9m*8C_FsVT4rGj>7ykZW9^PH3$@p)u5rs%QpHp@P|r?GL)s zSHaIWnnSbb4o#psIxtmz6K$hm0|su^q}iq-ZrG^R_MvNATq>hIWEDH;IjD8J{aJ2@-3Hbu M{ExyeJ^zo=FMx75^8f$< literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/bdd4453cecba0e37 b/scripts/.hypothesis/examples/972da276db8e758a/bdd4453cecba0e37 new file mode 100644 index 0000000000000000000000000000000000000000..9b1024695f27eaa7df4e00dcdf378a5bf8ae2574 GIT binary patch literal 816 zcmXw%TWF7Q7{@=~_uYTyf3g}fjVUf1;zoa&aOFbDDUnRfDY=jfg(4I!!kP$|s|`gC zITUF(ig2S5yK`YRL#Ry=CEw@W_Ureap5OC4-^24Flr2;x@mK5=JH$J&LiCH9KJ7m* zy2N59EO;xHN;M73vd|te9J@Ld);BpJ~1sAioQYTzc}u^FVn?)amZ!8b%Df* z0Ll6CDh{~g6fsxy7;JyLxGpT_s`wNs2}&8xE}Z-&enfG#F9&_A_$_hTxJ75hQ!!C0 zb@mBsch^p_B~#ouLY&|p8gS#`Qg-<(to6f4Nt&jH8wLr#?_1-&2S%trWm7Lc7foV` z*es5^%sQ$}fQAsj9dRjY?KbZCM%cY44#YM_-h_6oDhxBe4nOg~Af9%b;^ga;puew`LuZD#O@6&kvY z+~MIgi8#uZM-e<1SpCBu6C2Q0B*+W-In literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/be4ead06cf5c2b11 b/scripts/.hypothesis/examples/972da276db8e758a/be4ead06cf5c2b11 new file mode 100644 index 0000000000000000000000000000000000000000..fe8eebd374dd052f710b5d7a26ba79c17dc97f2c GIT binary patch literal 53 ncmXAeu>k-u2*N`3O8-BkpezuAPy*tiTJ(mZeMa`quis9|Qr~6SV6TgK>_x`yXN_v4eO^tRx1B8$ugANAxI20So$xrDRRRayRWEMpEoM z#AV_K@qtjuezG_^lb8=?f*8bt89Vy{v56QW@SPjq1>$H*DX&a)b{H{r>7z^a#w9^cyILM099r3vr33=(*Bn?t+H_x;ChVH zXGs`-XdF_Gr-*Ip_Wz4)x_VWiAuS7HBZ}R9+P)c<8<*#ExHEF)NqY7pp01kNyp=3Rj~By1_&;xF9_Gb#0mcZ D(2#4; literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/c32dde26c4c34be7 b/scripts/.hypothesis/examples/972da276db8e758a/c32dde26c4c34be7 new file mode 100644 index 0000000000000000000000000000000000000000..41ca765345af98e9f16a6f06fc8ed6f7ddc596cb GIT binary patch literal 51 lcmZQzU|<9RAjQPM$jk`hF#vfC3@jiSh%kr($uLBLBmf1H0DAxc literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/c6db75fdae76c45a b/scripts/.hypothesis/examples/972da276db8e758a/c6db75fdae76c45a new file mode 100644 index 0000000000000000000000000000000000000000..6ada3f36997377b9860df9bc3d64c037226aaf37 GIT binary patch literal 466 zcmZ9J!7D^j7{$+T?wg6}Va1AOD|?c#vQWxerfiV>4HkAbnAllPjVvfxu#jx*tQ0Xj z3u>AY8y2GE-1oBadYyak_nmvb^LHc15)E|@on^vpl%glJho&>e3Z%6Y v^p+K}$OO7{tp0$i=o+n~HJiwWZ7I@rM)gqrB#ATb+Zf_2DDLv}f0TX!{;V_o literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/c79e94cfbc1f2a33 b/scripts/.hypothesis/examples/972da276db8e758a/c79e94cfbc1f2a33 new file mode 100644 index 0000000000000000000000000000000000000000..0e43afb4f9e1ae0f97f9d4114cb365e1c8a016ae GIT binary patch literal 651 zcmXw$O-Pkt6oj9-pZ8+7n+8%C7zS-ZX_=Ums}@06K@gEqLQ1rV7Hxtcg+i266hd4I z{y{-SKTt%Q7NRRL(YtG*U{+XQL17@x`L4da-|v|@Gjm>q(uK+-{)u*RT`Y<-VpTkK zb#+LLixUPkEQn^QyyjH;>!$c+W@6B;x;NsISQ7=YEJnm>VZ;roFz`bBz*?~z#kx2v z<%^qQR9u!SzR$VrYA)=|Ulc9U-s*RvP26&a^S8yJa41$bjGyT;?%QFpB<`A4tO_L_ zghqxHi|nIuUpR}zVNzjDTxudQ&P$3uNQEsl$m z;)=L$nsb!d05uVS=VCaxZsvjGrk{id_&cfx`_PZ~Tod6 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/c7dd3fa59bca5bfe b/scripts/.hypothesis/examples/972da276db8e758a/c7dd3fa59bca5bfe new file mode 100644 index 0000000000000000000000000000000000000000..3b5e8466fb7a2599148a276d0000b506945384db GIT binary patch literal 387 zcmZ9IyGlb*5JlI@O;Q9Om3ETWA5cWZ%1*Er1snBOYk=HIZ<7!k@Wh?#?%YPLU|ATzVZDHiS4h6<` z&L1la@+NEA=?6cR4V`$suX#C;sbO=+4rk>kGP;{FpI5bp8@Z6cBx*5$rMg5rpKL3>v-=)R%AwcvL)-%O|`IdMR%Q5=J}Q#*_J0+ pm4RHQ)Zj$UWGTS>qb!GykdjrJF?y9PWQWaByeexO#%un+gj6vfYP-ps@_Sh1qn%AO=yStw;aQ8q}vhz%xomTF`{$%2LKd;vw8odq>1 zv0))f&i%h^yk6(sci(yEo_mGxQXDcSQF62<%1)J1N>rSWH{X-N`CIgbu7ZQ!^OMP< z>ix$>ljs#KK&@l?0a}Fqmz&H-+i0*TPJL$-wQQrYWcWPI9xl-_+RastLP!s?8&s*t zPN;o!(7DgeAGGC9rKD=8M>Fn%fhpIxMnlloenPWo1hvsJYNCeK%pDKk`B(JwjaJbL zx<~V!q2FV9??FUD;VogZ=IpHqEH@o X(R+Xg=dqU^x;JBrNh_j!|BuoyM?fxM literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/c8792a081899ea4f b/scripts/.hypothesis/examples/972da276db8e758a/c8792a081899ea4f new file mode 100644 index 0000000000000000000000000000000000000000..eab41e2211cb66d523e5f9bb4bdae55feb437779 GIT binary patch literal 812 zcmXw%TZm6l7{%A`od17}|IO4OqhS;eF7cv~5uQ9Kxh0a3yW~M06pBzZ5vCF0acTxd zF1ZwGUKHU)L;T-7m>PpnLlGtGJ2SI8XP>?Ix4ymBx4t7pHbf5e7wtgX(Oa|(^`je( z_Mb!DXrTe~-k`-$+qfh<+KqlVGc{=R%m-*a8bBrV0bNE*krBI~)P4tjleyxVkG`T6 zP^kVvooEA8zPxhS(VCFcyACafx(Sca7PQAVtlEpFghJFeX#DeI#(kcO-l2m|tJVjT zjt5EJuSaRXH%>ycQLoANb)aj=#auxj1CoeTL+Ij(U+8-z*ZB3Jr)IAb!^SK)gPx%A zQ10qOuHCnGp-oxEO~b+!+M@>f;-OUS^e(LR$4p6@rluPr3BT{T#=G~;&~VbGUU-ID z&?2-E9dVlL$XS3IqX6AT7bDkh%QwD8cJHwd;t7&y#_-mH$9d^dIy)V;d(qVD>Gv(G zFwnkUM;%%5k$5%wq4$=V&nwzl_*q3(R%rW&PCF?{RWri=$zlf|j_gjM%{DSL#0dR8 z=IwN2TG0!16diIbD?G^7pq0oHXJu75QB)!|CAnD~TUVJ|UcEM}%Av^zl$0m7RAw|A z70BGMDKF7sv=tT6G;|(aLi^D+i)-!)zl|rnkFQsWrzFW*(_KjFi*st9w)uEe$v;7p W@=0_lEYDgMF2_HB3Jqn`di)0`?qJ#g literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/c8bb039bcb5e1d77 b/scripts/.hypothesis/examples/972da276db8e758a/c8bb039bcb5e1d77 new file mode 100644 index 0000000000000000000000000000000000000000..9985900336b367a81e6a323c11aaeb6b24e954ff GIT binary patch literal 347 zcmZ9ItxCi}6vcnP|Lks9{7Bklt1lpk*=!aCo3CQ=10O+HFc?f0vH1dmWt+t)CJkZ` z&&*(P7|xwJ_sqTL4q_HH5G*+4bc~}=Ln*~^_?pYT1j0Ydw>(sheDqYrILZFg%C@}A zo=z8$U&(>4yghZjoXJ{i?$Y_DT*SugFz|KTJ>1KUT=p*4wGc1Fjf}^{iPO)8+$Em; z$Y~x8g-NYmhshMK?xe?~tn2dpRd!`V=5i$aGE22+x2o^{YG~ikhHXV?d?o92`I}LW OF%T??rRDqmKf*8g#T>u@ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/c9615f25e6feaea0 b/scripts/.hypothesis/examples/972da276db8e758a/c9615f25e6feaea0 new file mode 100644 index 0000000000000000000000000000000000000000..f8b2ee9fc24547966476955bb84b888d7d968f6b GIT binary patch literal 412 zcmZ9Iy-EZ@5QOX7**(s~pGc#VOT}Cf5hF9fSWYle17F0%AM_1`69WY!4aCeB5EQx0 zL^uR7(m)i%>K#lRhMJz9n(FEn!b@?;m_*@dOO#F(DJ3fB`g)i7Xb+9o#Tnk8LI<|dSu=cIWDnQq3?1ewry-;#*$t{H z*$J(WKDzX|^MiK%sYq&sdNkuM7@K#ETQmV9y=Sz9CQ%QqqgB+gnz=LKJO7G)zR@Py zK#yn{4bZuz21n=wEtoL-fEJOa`UQqAW;eqroBzZr5hKb^R$y1_sGuGYMfc zP}eQ7P(;adzAu}v(|gYMp67ku=XsA1{uDMjMk3?WjL15biK2*{^Wo0_k%RMB=nI_$ z40=ni3>GzBe^}IuUeGAi-x*#)b%RYDtu3}88_;u&2BEgibWY8M5s(dn>N<}S;wp;K1KL2t31SxF z!U1|s8kuAOojO;#MHA>8EusaBNQP}H;;M~WZ5O(<#rY!IK~}Mao`PDB+mGdOctOL` QN1%?vBPpC*{ZEvB0omg^e*gdg literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/ce7c500a330bdb84 b/scripts/.hypothesis/examples/972da276db8e758a/ce7c500a330bdb84 new file mode 100644 index 0000000000000000000000000000000000000000..f33ac90ef8b7125d3d830c03369e4d5b5a0e24b3 GIT binary patch literal 651 zcmX|;Pe_ze6vcmMzGkp#Qb7s>!=OzREtQgL)gp-gKoF8rfr_+<7Hxtc14EQ*FbHue zXax!t{Q*VVv;Mb6HJf@z|G1%*O*?l-7#W|_Ec0ybiH_dSImN*a&#r&G_Q}>Pgc~H!VJ5DRr zgc98$lJ)OZSTy5)aa2rO>~_C+AzaKe@gpD^lu$8yJls3i{xNZo_{H>Qpd;GrW0EA6b1a(u)&;(KXZn4;?&#A` z;v_zA*|ZU4v&1y>e@epM@;(2>LnmbtQt^;ovfZ`u(2851xE6Ne?iCe$ euKE^*hf?Yb|C3#r8;seLD+O4tM~JXNp& literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/cf13b60715d4ec84 b/scripts/.hypothesis/examples/972da276db8e758a/cf13b60715d4ec84 new file mode 100644 index 0000000000000000000000000000000000000000..a711cb1fcb420f44526abb129668095e1707a724 GIT binary patch literal 69 rcmW-X!2tj;3;|D*DYO3|g$HthkVOLfLsR4q!y5MCW6NS)n_nt?35NiP literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/d0ff0d68f27dbca8 b/scripts/.hypothesis/examples/972da276db8e758a/d0ff0d68f27dbca8 new file mode 100644 index 0000000000000000000000000000000000000000..dac90f01db03cbf161410b5e561577a671bd566f GIT binary patch literal 81 wcmXYn!4Uu;48nqSO7|Z`;@L;xLI~+$(7(t$)DFWgbSRUTRnb;7{}_%KE(}Bfk^lez literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/d1911510a996b2dc b/scripts/.hypothesis/examples/972da276db8e758a/d1911510a996b2dc new file mode 100644 index 0000000000000000000000000000000000000000..a7991a56421137013255949162a16d089f55665f GIT binary patch literal 544 zcmXw$JxESxFSNvrzB{Q9%QS1jI9Y@v?VjclPX=Gc!W?Q#jdXqTt<_C^}TgvW$}Bap!Yp z!`(S#-0k@`KzesFX~4((N}Zn_x4Pof2v zcy|oFL{{+}t%X|K?Pl2yPpEyki?)J2dh{6Gh;HqlH!OF1I!;mHRdhMoe00!K@$!*aWc*=hlOkCq6v<;ZGGsDE4VUWe!8ADX=HezC`iU?}+IrBdZ=I`i>uBk!qGO}1SKBE?`&4sl3 q{z<_n)t)c#ZE&?H$U49|5e-?rlO;Y-HwX&= literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/d3bf11900d341e8f b/scripts/.hypothesis/examples/972da276db8e758a/d3bf11900d341e8f new file mode 100644 index 0000000000000000000000000000000000000000..4b2828a2584e9e1f16cb80bf9aee9473be004267 GIT binary patch literal 613 zcmXw%OGuSb6ouD!f3K8Y(@BzG=rD?gMTRwUAVd!cB2-MskOtwPVNjC@LlXlLhZk-S zNT}!mN;q*4G!m6^=Agg_Qi2IeLA3Vy@o+fjKl`k+_F8-YLU<@PdCf$@U$;b+Lxn8M zC^{Z@K4)GWUqpY7!S?8ETjZjzl zfjZDpR6)JyI%+YSv8O_J{wn?I;0N zA?V=okBN94mC$!Ii8>Qv07|28(XW)qB7j6Q<0wW4b3?y0# zT7g1Ee;|=IEy7lzQL}52V3wp{LSZ1D`$l{`-uJ$D&%Ni|bA^cIQ-{!RbP|f?6*Pp- zL)H8z1ww4{@gH4Am(Uk<9L=IJ$7Ua(5!7VB!O!R@Y_4xfPuI{NXJ!U%+4lyWLvyHv zzN1Iz7&782l=@$w1rwR7U@%i>(Fv%j8%GyWhasms(e99dW|k~$@}_aW_Mormy3@+r zqm+7+T!%_?F1HIEKvQn1YXCh(miid|h?a696Zy1Z>#e_NalKb^j#nSKhu)(dux)q- zxh0nyMi){e4NkO{Mp38;5B08D@ba+lr)SNz>Y?Y1(>a%Ob! e&b&jOODp<_ZlG>sH~Kzy3TDPA+wIPFi*SL|5HUhZSUnozpg4OIa}5PU>D&D? dA;}f_3wSL{RZ82;h3nfz+czIgbD96|fe%Re7hM1V literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/d6493e97a346138a b/scripts/.hypothesis/examples/972da276db8e758a/d6493e97a346138a new file mode 100644 index 0000000000000000000000000000000000000000..b813f67d41bc3c8eff1c0550a53fc04f9e292de9 GIT binary patch literal 577 zcmXw%KS-8Q7{$-;d;KKsQ(F=Q#WfU1LqnSy0zrqCP|+bHni~aMLK00B92^Dv0}2uT zfkIpy1Se5Zw*~_>!h#fxg77@|#h1&y?|tsM=Q-zjt`Pndi#%td;J>G$%%MV-WfUEc zGw(A`j_;zsXe}`4JU=p6lzUubQ5!l#-B5XG_#Enm>L1%V9!;RzDLJJ#chIC|H1>J= z^D)=(1udYdJj?qa(pOmxDi&oWR9+mS6|bZJ(YP-aGL;8=n6V3L?m5Q>s)efgZ|DJP zK=Wt-Jw}aYGqyE!=eNSoKQx4%pncSZj?tp2j;GOE)M3EgJ#-&#)SJ$s=TQR6LQqB1 zY9c;GC3J*l(Zhsz2BpbQ=x0h~l1{Yl*xUi?LtE%28n%d3Y*SG>wNa~WK|8kiVhVjg zR`Cv%1Ig^D}pK+RC|{ PyKO!}V$527%B$fE-i-`v literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/db82ccfb54ca0f72 b/scripts/.hypothesis/examples/972da276db8e758a/db82ccfb54ca0f72 new file mode 100644 index 0000000000000000000000000000000000000000..7e8ea7504514a6ea171b4b15e15fef1126ce85b4 GIT binary patch literal 409 zcmZ9IKQBZ<6vfZ)&3hX*{!~gx=r~t74GT(Tuxba@jTR(KL+rUePL=MLo2QHc-oI<}QTq{44tTM!RSS zJ)<==K$n&poS-w*HevAzt-#2P<(%4&5m1Jq(fJz-*IId=b$bDxjVD_=w0&cWVJf10 H|Buoy(~T&Y literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/dc25925bbb5c63f5 b/scripts/.hypothesis/examples/972da276db8e758a/dc25925bbb5c63f5 new file mode 100644 index 0000000000000000000000000000000000000000..d8b2ec784d8d7097c853b75e863d7e40e3293941 GIT binary patch literal 854 zcmXw%ONh;37{-6k|I8WV+)NEJ8b+~jiH$}^SXn5!C6bZ5WFZTMA{0%8X+&5~&7jC7 zmmr26F(9tl zH*iMui1`kf^I9yF>Y5g%qn%>dnK=iIoPJNN6@#KA-iwQ3v2er=snl^xd=0dC=87+3 znN;ZeCA!2qsq*=S-S*bHmR_zAOQrg855y+1%N17a7L$UZ=pSR; z5J(&iki557Y0woXh?(N0!S-~DE5c$fi4PHyp&Zrd;;|p%TO`+d`_QJvUzx*3%{wI? ziLp|-yI)wlt9FYGNpW+PxIvv-W1DxfOT;gWimt(S|BD{`Wyma-%Ne(d7LC7SvA6FU zs`0qHd+v#76$`|AamZ<|T@zKBLJ2p;`N(zKam81{ZG7m1zzaC+C6{3`!OD)|h>yog z#so31(&?$9!ynCUHa~BqRNhs6QMriKLIDzQ9KosrZfJr%>cMs~e8 zy1p{IymEDtW7oueWaaU#m1!-3=xx=hSR9tch^B+EC<> zLy>l)2sawBI~P_ngxVBQ^8LO4d3v7bec$JI_#U1YA&=NljkiByhuALOie+Lz+;D8* zoahz{oiOi>SS-~wEy<2{i(yx$P8vP)fmkmFMNxbZm&H=yj9pT({f_vCfnv@VU&RV3 z-}hT|iVafv%PWT+t#vQ;t`p0p`U#K37O}@2R_zs2f}!Xia{lvU&ig!7yb}jq*4Ge7 z91oD3mq&5X9Vdy|qSs*iI>a?$F;~RLNJ&siHM?-)r}!SlwO&5-*6g>$X=4_g5l_T; zsnpdktleF^#HLJfWrR4vJv89P)lzo)E3EayNJ*NehO2^v-}kKX?tLRPp0ueKo{1K* zNNf~GTxK0LCO}gN;I_CJwRRhKd@bzWV;{scKr|eVgqUVLE|`Q3XQzvHzf@Yi{krAD zXliS(i;he`Nfcj=OX0oCa=Dba)clV=VSf3xzv8q7Hrvr4 z6C;H57{1dt)GA(xqvDWbnF9g1My$-J&dTJt5S61eRdTa1w!S>Kw0dnO$DzpwNJ}otNUU*eVKQnm8{miTz@m={5I+@fkx~7SBw*l_c36b?1|Y!koINZ9X1V a^xse+XD_PWXLsg+orvE-GzhLM9 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/dce8c8837f8291d9 b/scripts/.hypothesis/examples/972da276db8e758a/dce8c8837f8291d9 new file mode 100644 index 0000000000000000000000000000000000000000..658aa2f2c9e4cd67fc39f21c9ad9cc117f7dadb1 GIT binary patch literal 547 zcmXw$KS-5f7{$-;eqOQbO{bcSyNc3igs4-4Amrc@UC=>8njIZnB#2UUa}@j&7>J-k zAuerAk)n5VP`D|Qf(D8~be{LakN123JnwnWbI$V!;ZL#1b0!Mjy%7x#6|yX&=y=@u zoOyD558a`iz@Y2=%3#sxagRmM(Qot;N;Sh5(Q9Zq|B>U-NAxHqr##b+W-X&q^>n+Q zYxs)R&|IEnHHdU1t3k!0tc22^8rt&u?jQQ#M} zDJr95w1D~(VjRk|8|We>GD$Dmb!_nvRnd1eg(fW`728ylPi@p{pQ4|(I5CGlA*)zH zze26c?Pj?g9?(2}gD!(Tdh{NRM7QqGXO?^QB~IaR2o0w4ccxY*RKz!JqYz#9uK=e- F{{h~}LG}Ou literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/dda48081e3b3c427 b/scripts/.hypothesis/examples/972da276db8e758a/dda48081e3b3c427 new file mode 100644 index 0000000000000000000000000000000000000000..fa2890905184ec7689ccf5370d107a232208d857 GIT binary patch literal 51 lcmXYm!4Uue2!gPhvi%1syZm?nLLMkk9b1{>b{GZ30DJ%d literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/df928c770723c1c7 b/scripts/.hypothesis/examples/972da276db8e758a/df928c770723c1c7 new file mode 100644 index 0000000000000000000000000000000000000000..d501f7bb4085b85e7e50d77d6ba966d9a1d5c41e GIT binary patch literal 472 zcmZ9J!7GGO6vfYP-ps`GVa1AOD`iO%Ru*c?TBdA}{0$a%HkjC1PK_)mS+J07?5q?q zI}2)>5*rqx$0zR*SF zp!e*^WKs10$3ryO11+FARJNMABhhzu zEB5n^me3-)M-|jUN0w^sqJ1=B!ss2Ef{uR68Cs1aARi5N4xOdKZIqxVw1;L=#tJ00 z6ZDoAvdAR5G**8=RdkKk(V9)9!?qMj+l|`oaCGL;`eE`;4LXMS7K&N6{~x7aMu0R) literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/e04e0b8f3edf05dc b/scripts/.hypothesis/examples/972da276db8e758a/e04e0b8f3edf05dc new file mode 100644 index 0000000000000000000000000000000000000000..7125381a9abf35ca16405f3e2eb7ef85dbd35410 GIT binary patch literal 469 zcmZ9J!7GGO6vfYP-ps`GVa3WcTiKI@m4#BXmMI$~e}jdc4JLM$QzHvX7AzziJ1a%Z z&Vrhz#D;|^Iq&&6e-^rc)-F{;OA+y#B(u5pD1pr`qarcoI+(E^%76|0#$5`Aa4 zVn5$#2`!>~G>h8k$WrZHw2vlC7`;PN&^2f|L#uHFh@gA(+F_RvhqSb?N| xg5J_X7MVns#u^W(hOW^%TC<6C*p?#cxY2U7<+=J*@=lF7hWHSQS+@TlrC*@2G#dZ_ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/e089ff603e5749bb b/scripts/.hypothesis/examples/972da276db8e758a/e089ff603e5749bb new file mode 100644 index 0000000000000000000000000000000000000000..ea9c1c52985c0b21e71647c750a074dcf8b93ea5 GIT binary patch literal 384 zcmZ9IyGlb*5JlI@O;Q9Om3ETWA5cUr?F4I4u+jXAjSut>gouTLm5tc>1A-#yY=kso zrG+Sn`{ZH@FNZnj&a9c)Gl=;p7qJyK^6FtTu0~Z=w&E|b{8usYKggHd7DnFdP+)B5 z{IRkmZ?dkPLGV-A)T!6|nwJBa88vs}a9)lgqq`OJc~xt;kqbGlyPTIoJQFq2Y7r%N zJ_d4~d+$f~lhmkam+EDhOyTr$dfdsZPWE49Rpz8G+p;0uR13RMbk|vBo^RQe9eI*9 n8Omi!4Nv4uRst+O29Ao7QaUkyl@(-x&2hXcI~&Do{=bD^_~j&{ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/e1e145c86abe97d3 b/scripts/.hypothesis/examples/972da276db8e758a/e1e145c86abe97d3 new file mode 100644 index 0000000000000000000000000000000000000000..3baffebb6d4669e3f073baaa008bf9f5508d391c GIT binary patch literal 514 zcmY+BKPbgf6vw}x_w&T_Ffox;%19C>gHmQu3`l09!6GGpdN$)L|B8}au(4yB?fBJFs1vmeMQ7 zP|r6SMnmWVb)!49X{x(Lw1V0UXg)_BP*P($hsHt+C<=l~8+K#j0?MKrw1m21#3*DJ zw$XE($RzFP(6Rg_>PN?D5=~e{+-y^kEx1stZA7OoaXg3CkyWgs`=HkC_ORRzZz!Ak aKrewk%xDG;hH3rz50?A77d(^xv(hhC)js3{Ho_odZ$HYW;l`@iq$)J>3Zds7bMuW|Q8=LXgm4T9hL9*CPLfp+j z-EN76L6p4b|Fih}`_6a1?>+DLzUK(xPjQiB5IJXyBJWZzgh0Xd*z-O(xPFVi(0Rn5 z_pD{GXz~AtMZ@S7O+&G6cooe;$IEqwN1LcC9Zs^_;L! z%4$%dAS`7l6l$PDQ#E$b9vU@Z=njoTYmez%T8>vhJ_>5t72m+6E%Jv^5u<}EBCxDQL9K08*LDo>TVIF4T>uD>4pPKN#uGEcBodymT Ck^rOt literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/e4b4637062bc4a66 b/scripts/.hypothesis/examples/972da276db8e758a/e4b4637062bc4a66 new file mode 100644 index 0000000000000000000000000000000000000000..8c6168393a4167abc70c6dce65c01dd9f2ea95b4 GIT binary patch literal 815 zcmXw%TWF7Q7{|Y#_uYTyf3g}fjVUf1;zoa&aOFbDDUnRfDY=jfg(4I!!kP$|s|`gC zITUF(ig2S5yK`YRL#Ry=CEw@W_Ureap5OC4-^23?ku6aL`ipj=9q1ief%?%+pZ1?e zU1+fr7Q97Ep{8M37TSY`T$ws)?CghVBN{+O^buV_%aJp7L$U2H`YvO|UWmS-Rgmxf zgF4VAD1UwJW1m(Bot_P7CDcxOj9SoMcUZFzO$&yoZ_xQKjyvzmbo3q_a#?R(An8Pa zxYq&G))aR3=)3dx5j%9j8K2dre1uGn$Qxo z869<*byS&v8bW~Xpi5C}x8;s+kllOYKx_jpyhH?2}a0qXa&i@8F}+uhVF&y$l+$LPEEJ zJ3O0a^b#FIhkcf553qG;bw+YdCd7rJ9HlAAt-|=)^8C`;^_dVKO+BcjG`XoftKzK4 ztQzs<6*_{pp#qwLE}+Zk0NQSHmF}=Sv%qG>Gt(V1vgvf?le)sZnrE#Jk16^;XjCqV TL51ttw8H544N$(mWLU5N=pA6& literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/e5195318a0b1d607 b/scripts/.hypothesis/examples/972da276db8e758a/e5195318a0b1d607 new file mode 100644 index 0000000000000000000000000000000000000000..197ddd2ffdc4c3370362f80b410fac8e1da80f98 GIT binary patch literal 586 zcmXw%Pe@il6vfZ)dwyd2`DarQ7;Z&rsc59D7DAAVHjNVw;N6u8mslP4vSS2Pe=Q zWEJ!1PpEad-7J^G1FD{%p`&1r9*v;B=+@X gufH_@^%`nVLLZ_bJB)WxA8PagO+{O*FgVkq{|E3%5C8xG literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/e573a130daba5963 b/scripts/.hypothesis/examples/972da276db8e758a/e573a130daba5963 new file mode 100644 index 0000000000000000000000000000000000000000..cb939c5909ff1be364df9d082377b3bb8f6ef88b GIT binary patch literal 830 zcmXw%TWF7A9LGQ3_uYTyf3g}fjlbf;A#OC8aOFbDDUnRfDY=jfg(4I!!kP$|s|`gC zITUF(ig2S5yK`YRL#Ry=CEwrs=jnN#_kEw=;d^*qggjzHHQs)U?P8mFBbJFlaow@O zv!X{Vbi%yXVzE@$v?M#)B}QDCI%)LG`(nKq5=HS|ToOx#Gj>YFj@#lZ28uafd=V?8 zeE%=eB{oRq&o3QzwAQ`Uw@xgV>L)xDZDO}OtlA@{1Vb?}?EGg(o%d;~cqX4YIfoH5AiLEYrTBvt=Vsh)5a_~Egp;U zQmK1DSi8G+i%ps0N|m@lU26Iv1NW|0v%_EEt{(;6yL(M^W)_e{@s+q2-nlH7ONo2UfA1IOmv8?gPFX-MNvZu$;-fhaKM3e5sgq)} zO${Tqd5@0YW}(NLL3rXL_tgw=fp*^Pi!^4=H4(qV`$6bnW?vuB)g-Ye9};uQ}?9Z d$D@k=Au8nTMb-Q4&K$54@kfY!V<~{W_zTk?VDA6` literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/e65fcba7001a3a92 b/scripts/.hypothesis/examples/972da276db8e758a/e65fcba7001a3a92 new file mode 100644 index 0000000000000000000000000000000000000000..8058f6fe90c96f1a2e6d8b6d5e2d151ff3c48d2d GIT binary patch literal 106 zcmXwxSrz~w2m;5YOLqT*1Xg|sZxjeZg9Ys*YLGk>E$D-oc|I>E@KY1s_sezj7j2yq GmgE2&p#ZM{ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/e6b85ff31576e872 b/scripts/.hypothesis/examples/972da276db8e758a/e6b85ff31576e872 new file mode 100644 index 0000000000000000000000000000000000000000..323d9c79206cd929a2d1adb9d6834054416230fd GIT binary patch literal 63 qcmW-Xiwyuk3_+i3r|kZN97Mzqp#a1~(`XOFy6oVv?IL-E=MNtT=>UZQ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/e6dcd643c4d59894 b/scripts/.hypothesis/examples/972da276db8e758a/e6dcd643c4d59894 new file mode 100644 index 0000000000000000000000000000000000000000..cebd10ca724a121186490b3d1e7a6215e5d28332 GIT binary patch literal 213 zcmXwzF%E%I5QOLZ*ZYevCnA7wIayK`F^jXr3)PxXwQ&9kpL>zH^}#f&c&j literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/e79acfc5fe8e7e5b b/scripts/.hypothesis/examples/972da276db8e758a/e79acfc5fe8e7e5b new file mode 100644 index 0000000000000000000000000000000000000000..1bcb7e94c9498eba3191a308c25a5e2b8cb9a4e1 GIT binary patch literal 136 zcmXwx!4ZH!3<4qXEb{(VX&1KQ&zFnNWhMy$f-FYGDMg literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/e7f1eca362155d60 b/scripts/.hypothesis/examples/972da276db8e758a/e7f1eca362155d60 new file mode 100644 index 0000000000000000000000000000000000000000..b67dc1b546075f9a1afbe02be49fbc83ac90138e GIT binary patch literal 818 zcmXw%TWF7A9LGQ3_uYTyf3g}fjVUf1;zpARS1y#C63N7zk_)*|C_>R9tch^B+EC<> zLy>l)2sawBI~P_ngxVBQ^8LO4?df?>&-4BLzK7>UC>y9s;;+~#c8GUkg%}Vwy*qGT zbc@9XEO;xHN;M73vZXy@*p;b4V`o1U8^xd~ijU%oST2m%Efw4Eitm^!=0fpJtdjD5 ze?+I)B$dCu_O^GcLr(7ou~Mp?^jNftz3#APpO_X3MgNfTFOD1cWx9AT4!NwaE|@qG zBspIm#X)zRBIb%-lkM*i*M-eo6`ul%;?nf+i}Cst=V=VV@7h{{o#D!Ek{Ut6AETDv~;;;pF%NlKHO%d?t{ z3S`wtG_S-Fu}u`j3~@nR76-(3i)-qM)UyJg?DpE?6_D9U`WMTgYI-_+k=sSlDi>B`%iw5Wm zjiA~Ye??b%VVm(nl0 Cup0&d literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/ea19679a27e4fdc1 b/scripts/.hypothesis/examples/972da276db8e758a/ea19679a27e4fdc1 new file mode 100644 index 0000000000000000000000000000000000000000..503b2f7fcfa2d446eeac3fd05f1248dae290d472 GIT binary patch literal 914 zcmXw1U5HI#6kY2(=Un65bMH(IG8(Sp!4NOgl@XpiDEUhyBgPDA9^^rxh$)%~(}?gm zHG?8Q`6<%8D8DZn;=Xw>H3k_qqll8V_szNIeCNC0UVE>#_C6p8(5^^t?GiAFwTZwS ziH~}ocM;9RHU~OB=yaLDvEF}(T|@`*j#y2M5I0n9|kN}I{5-Z4>#+825Nlbuo zB+%sf4~Q+qD3KWzE)%N=A@-12&mCgSIPG3Sd?VJ9Y2`Q3M{FgFUtfFJma1HGXfv^f ztegIbXe0Kj&iZ}CY|}{$k1Oj%m#DwYA>I>*$Xun~_;B3H$h}?JsBF$877|0E+}}%F zBV_3c@yQ^;8|3KxiJ!!GOU~(0_q3F?Q;%4?^bGNYm_`=*hY58+Rr`tU?z^NcAyr1H zvDQS%I@4>hpzXL<_N86C;iap|sd4 zHJTgTCN5g81^`ukL#UyTbzq!E2}KbFNRTO0V8ZZr%gs~;C6d|Mc|?ykrB*G!Zh0!9 zwqGZDJr%*kUA3{{gUL@K*x1t_6+&{;?!Uxo(Iz2+`!P+QWnuiGX{c&EMeIelkDm`J@_ zQ}kjf`oHDsu7+Z58-uCgbtoQAVlOsj%PtS%irt8muoKnKRvcaDAF=SK02LnZ`~tso B7ZLyf literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/ef5ac1803b7cf8e1 b/scripts/.hypothesis/examples/972da276db8e758a/ef5ac1803b7cf8e1 new file mode 100644 index 0000000000000000000000000000000000000000..9401a36ee599b5ee026e4f9189aabd32724f6664 GIT binary patch literal 503 zcmZvZKPZJ!7{;I9{qDW_b1^ZIRmw;bCWBIDxn)5z8x0mI;dX7tTi2hWWMGgiHj@x{ zGf*gDpoo&^d|x(Sr}up4eV_BZ&+{H3{3&d5j6}+RlOpX@DvBa9&WD=Mk%RLW=nEYM z40=mS28*oM9~O0^XEY2o6~jwt6zZSO5Q`e(T=I^SJ67^HK6Mf^+Q#&>71GlBOo0FRkt6+#E&S4ZqXVVj1g0i zE9{|{xRFWv(6Mu+Ym`T)Xb#O0tC<4g|MIa()jy&rVtG)fqK50$}hqB2v zMCIuzYD-l_&{)r#_i(ZPMqjihgFfYCShUWIMR#3UNInP#g^n`k#^vduh)CU!hCkYpw{j7u-p!BD4YC1 dFM&PGXc`TKY5n^TmixLFy!78B!`%tIegRhp$J8buqMLgYD1Bi zycB6Sig2S5yK`YRL#Ry=CEwrqZ%^ku=bY#H{(j$==OE+}6RPs`SL_r!#5=J<42YZF z8#phz#bN^%ycJ8OnucZB(jGDF%G98-vmc6$Vo(&tM{z|g7e?%sitTsBcT5!5Lh((k zlJb3jM5ov!mA}6Bws))DOT8P!N~w0zW6>)1y2F}%Vp=E^{X@pTIBwjR>EgXOKeW zy%Vll9VPl zmuEE@709ZQY+i{YVw)(48RCMtEDnh67T44hv1c(juy|(P?IX!fs5_t373S4EYxDA$ ZqW^_Pa!#U>e0E|HcKiw=Utcn<$A1vCVCDb- literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/f46379dd712010a5 b/scripts/.hypothesis/examples/972da276db8e758a/f46379dd712010a5 new file mode 100644 index 0000000000000000000000000000000000000000..48118e08aa98ff6fc9109f8febd4e6bb65aa245c GIT binary patch literal 347 zcmZvYuS$eL6vcnPZ}!`;_$O(Tt-gRDX0uroY`%&`U3>&#!C)|1#O4bKmTeZJm^6q% zJoAkI&nkUd_aXt2?RjAnUq3f013;khvVmzD%PQ?p73ke|5tc2D5`m!z)u^$sQ73)m&RfQl!c(mrmd9t3Kh{A z`h_}E#3&SJH_%<$$RurO*R}Z*)Q|SiB$}{@bl9e%cx9tj+l&ruaeNM~AgfqHm!a0< q_G5V*UQjjljP8Ry-e?95#%sOj*OvRR9a%X1ih4Z$NZsQtO8)_+D?l&+ literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/f5b135c751cc7126 b/scripts/.hypothesis/examples/972da276db8e758a/f5b135c751cc7126 new file mode 100644 index 0000000000000000000000000000000000000000..231a520ea59a489e720d54126a5aaadbc37fe4d7 GIT binary patch literal 106 zcmXwx(G>t72m;S^%Jv^5pz=d`CqPjee9&H02T4OSf_{jZucxI1ek$R8U9O9-CfFrz F;Q$W(Ql8P(6ki#R%mxF<+tu+aZ;i2-pVMr2uwz9zoOD15pf iqbt}MR<2nc-)eBgQ-LvTB3G~5vj+Dzi+zdzZ-EaAHyAVk literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/f7f2e0b635416af1 b/scripts/.hypothesis/examples/972da276db8e758a/f7f2e0b635416af1 new file mode 100644 index 0000000000000000000000000000000000000000..de92efe44ea2ee6229a8bf6bb1549ad2ac3f5eea GIT binary patch literal 848 zcmXw%U1*MB7{`DA=h-{+zVBu=WExW(_=potCLB3X@|8#?-;x74P$)vtBCLsUxY|(U zBOgWDi6We6#LgU8%@Ar+M9KfU-`wx>+|Tpe*T?_kdJ*!94OMyjBX)@G;;mRF2E`4> z2G5BevCs+g-iXCgP1BNev|Eh0GI!GGnGeKzF(k_3gSae~3TNz+${lyaHw+ZleDPJR zkc$1kMVHth)qQ#8u%p%PrM`7yxl}*lk=P>kxWlTwVoER+1H;aLe$08Fr;2ytpv(Fj z0*T`RQt<6n9&*P?Vz%fr*uGA2O<2qo@i9^|lvBwro%kufM{%`pA9`!?TjsPe3(klq zV!Tw_Js_;zUAx7mq`0|4+@LP4@?LPUTf{Gmj_$!ue}%_>7&6QA+_)9AF#ev!-o0VS#EMr`- z@+zO5E;{_u+~)1qtyCxM_jS>kOd$(qS7TDVcUhs36O%6f=ojW%Z2v1x8?%t*RR1UR z$^3^O27wB}Q)07i4)w7@RIlN?JhnFRLL3!`97}El;2Na8S8 n^Xe&P4W&6XPuqPws_ef=GX;B5nM0bN19l?36~)HdWTFZ;#iTaa}}J@_Ybj^*h0J^788BMHC5_6O>`OGz;ys~~J!F1pGBFcO1u=*PGkoejVlB~6Bu2&(77@bO zPA08F_-?Fh%_hDPOUX?6H_=Y46W-TX?zXKWi0oct4PecfheQ*xQ#i|a5fe-a(L125 z=glhpWg_vG*hi+z1*?a{2BZGilk}?*0b8B5EZT`gSf7%!&$3C=9}L=f`1~`RC4=bI-Z=7s5la$!jJG{<2IyJ~U_< zO&wnTKFc*sqX{&WXL%AtT9nnGVo_E?^;!i@dcXT0-SeYDrc$tn8M~nNm~*^EyI}k1 z5;}=?qfyj}+EJ6)j6D>(^H<^LAG(Y#p?P!)Eu*KVT7G~Yqhf6%XBj~?}-i_xvk^H%%asMmY&6&`xXxz0I#HAi43foW65=)k zbzO;tL6kh-|DVOz*ZaNS`##_EKJWVp;iYiMHWC?oiz4e#CW<0*j)$D@k&WZG=nI_( z40=yf28+D+9~O3x7?`J4x$^kxKc&?L8PbbKg!y5-Zl!~qTr?X H|5o}18R0h4 literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/972da276db8e758a/ff68979d0ce29eb5 b/scripts/.hypothesis/examples/972da276db8e758a/ff68979d0ce29eb5 new file mode 100644 index 0000000000000000000000000000000000000000..742eb8626e2e6f403137e58e2f6dd3e58f62045c GIT binary patch literal 57 ncmXAeu>k-82!gP>vi}ds$_WIa9f&}AYKEkIUa-{TX4;hj2K)eo literal 0 HcmV?d00001 diff --git a/scripts/.hypothesis/examples/a7082e79f930272b/38b060a751ac9638 b/scripts/.hypothesis/examples/a7082e79f930272b/38b060a751ac9638 new file mode 100644 index 00000000..e69de29b diff --git a/scripts/.hypothesis/examples/a7765ca8ac786d69/38b060a751ac9638 b/scripts/.hypothesis/examples/a7765ca8ac786d69/38b060a751ac9638 new file mode 100644 index 00000000..e69de29b diff --git a/scripts/.hypothesis/examples/c5cc8ddf7622ef8a/38b060a751ac9638 b/scripts/.hypothesis/examples/c5cc8ddf7622ef8a/38b060a751ac9638 new file mode 100644 index 00000000..e69de29b diff --git a/scripts/.hypothesis/examples/ceb7445d967ce5aa/38b060a751ac9638 b/scripts/.hypothesis/examples/ceb7445d967ce5aa/38b060a751ac9638 new file mode 100644 index 00000000..e69de29b diff --git a/scripts/.hypothesis/examples/f8448706e2bfab64/38b060a751ac9638 b/scripts/.hypothesis/examples/f8448706e2bfab64/38b060a751ac9638 new file mode 100644 index 00000000..e69de29b diff --git a/scripts/.hypothesis/unicode_data/14.0.0/charmap.json.gz b/scripts/.hypothesis/unicode_data/14.0.0/charmap.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..6dad3fd631c3d14fa8723fe9c0dffdd4924a764f GIT binary patch literal 21505 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 character) public static string ToAccountSafeString(this string o) { + if (string.IsNullOrEmpty(o)) return string.Empty; o = Regex.Replace(o, @"[^0-9a-zA-Z\._]", ""); return o; } public static string After(this string value, string a) { + if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(a)) return string.Empty; + var posA = value.LastIndexOf(a, StringComparison.InvariantCultureIgnoreCase); if (posA == -1) { diff --git a/src/Ghosts.Animator/Internet.cs b/src/Ghosts.Animator/Internet.cs index c7d403f8..1b1353fd 100644 --- a/src/Ghosts.Animator/Internet.cs +++ b/src/Ghosts.Animator/Internet.cs @@ -47,13 +47,14 @@ public static string GetFreeEmail(string name = null) public static string GetUserName(string name = null) { - //% have a random username not associated with their own name + // 67% chance to get a random username from the file if (AnimatorRandom.Rand.Next(0, 3) > 1) { - var file = $"config/usernames.txt"; + var file = "config/usernames.txt"; return file.GetRandomFromFile(); } - + + // If name is null, generate a new name if (name == null) { switch (AnimatorRandom.Rand.Next(2)) @@ -62,20 +63,35 @@ public static string GetUserName(string name = null) name = new Regex(@"\W").Replace(Name.GetFirstName(), "").ToLower(); break; default: - name = new[] {Name.GetFirstName(), Name.GetLastName()}.Select(n => new Regex(@"\W").Replace(n, "")) - .Join(new[] {".", "_"}.RandomElement()).ToLower(); + name = new[] + { + new Regex(@"\W").Replace(Name.GetFirstName(), ""), + new Regex(@"\W").Replace(Name.GetLastName(), "") + }.Join(new[] { ".", "_" }.RandomElement()).ToLower(); break; } } + // Convert the name to an account-safe string name = name.ToAccountSafeString(); - name = name.Split(' ').Join(new[] {".", "_"}.RandomElement()).ToLower(); + + // Split and join the name using a random delimiter if there are spaces + name = name.Split(' ').Join(new[] { ".", "_" }.RandomElement()).ToLower(); - if (AnimatorRandom.Rand.Next(0,4) > 0) - name = name.Substring(0, AnimatorRandom.Rand.Next(1, name.Length - 1)); + // Randomly shorten the name + if (AnimatorRandom.Rand.Next(0, 4) > 0) + { + if (name.Length > 1) + { + name = name.Substring(0, AnimatorRandom.Rand.Next(1, name.Length)); + } + } - if (AnimatorRandom.Rand.Next(0,4) > 0) - name += AnimatorRandom.Rand.Next(0, 9999); + // Randomly append a number + if (AnimatorRandom.Rand.Next(0, 4) > 0) + { + name += AnimatorRandom.Rand.Next(0, 10000); // Range 0 to 9999 + } return name; } @@ -157,8 +173,11 @@ public static AccountsProfile GetAccountProfile(string name = null) return o; } - public static IEnumerable GetAccounts(string name = null) + public static IEnumerable GetAccounts(string name) { + if (string.IsNullOrEmpty(name)) + return new List(); + var o = new List(); var numberOfAccounts = AnimatorRandom.Rand.Next(0, 15); diff --git a/src/Ghosts.Animator/MilitaryUnits.cs b/src/Ghosts.Animator/MilitaryUnits.cs index fb1b61f7..daae88a7 100644 --- a/src/Ghosts.Animator/MilitaryUnits.cs +++ b/src/Ghosts.Animator/MilitaryUnits.cs @@ -41,6 +41,10 @@ public static MilitaryUnit GetOneByServiceBranch(MilitaryBranch branch) { choice.Unit.Address = GetBaseAddress(branch, hq.MilUnit.Address.Name); } + else + { + choice.Unit.Address = new AddressProfiles.AddressProfile(); + } return choice.Unit; } diff --git a/src/Ghosts.Api/Areas/Animator/Controllers/Api/AnimationJobsController.cs b/src/Ghosts.Api/Areas/Animator/Controllers/Api/AnimationJobsController.cs deleted file mode 100644 index 2c2204a1..00000000 --- a/src/Ghosts.Api/Areas/Animator/Controllers/Api/AnimationJobsController.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. - -using System; -using System.Threading; -using System.Threading.Tasks; -using ghosts.api.Areas.Animator.Infrastructure.Animations; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.DependencyInjection; -using Swashbuckle.AspNetCore.Annotations; - -namespace ghosts.api.Areas.Animator.Controllers.Api; - -[Area("Animator")] -[Route("animations")] -[Controller] -[Produces("application/json")] -public class AnimationJobsController : Controller -{ - private readonly AnimationsManager _animationsManager; - - public AnimationJobsController(IServiceProvider serviceProvider) - { - _animationsManager = serviceProvider.GetRequiredService() as AnimationsManager; - } - - [SwaggerOperation("animationsStart")] - [HttpGet("start")] - public async Task Start(CancellationToken cancellationToken) - { - await _animationsManager.StartAsync(cancellationToken); - return Ok(); - } - - [SwaggerOperation("animationsStop")] - [HttpGet("stop")] - public async Task Stop(CancellationToken cancellationToken) - { - await _animationsManager.StopAsync(cancellationToken); - return Ok(); - } - - [SwaggerOperation("animationsStatus")] - [HttpGet("status")] - public IActionResult Status(CancellationToken cancellationToken) - { - return Ok(_animationsManager.GetRunningJobs()); - } - - [SwaggerOperation("animationsOutput")] - [HttpGet("output")] - public IActionResult Output(AnimationJobTypes job, CancellationToken cancellationToken) - { - var zipFilePath = _animationsManager.GetOutput(job); - - var bytes = System.IO.File.ReadAllBytes(zipFilePath); - return File(bytes, "application/zip", $"{job.ToString().ToLower()}-{DateTime.Now.ToString("yyyyMMddHHmmss")}.zip"); - } -} \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Controllers/Api/NpcsGenerateController.cs b/src/Ghosts.Api/Areas/Animator/Controllers/Api/NpcsGenerateController.cs deleted file mode 100644 index ec91c3bd..00000000 --- a/src/Ghosts.Api/Areas/Animator/Controllers/Api/NpcsGenerateController.cs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using Ghosts.Animator; -using Ghosts.Animator.Models; -using ghosts.api.Areas.Animator.Infrastructure.Models; -using Ghosts.Api.Infrastructure.Data; -using Microsoft.AspNetCore.Mvc; -using NLog; -using Swashbuckle.AspNetCore.Annotations; -using Npc = Ghosts.Animator.Npc; - -namespace ghosts.api.Areas.Animator.Controllers.Api; - -/// -/// Build entire team of NPCs for a campaign and enclave -/// -[ApiController] -[Produces("application/json")] -[Route("api/[controller]")] -public class NpcsGenerateController : ControllerBase -{ - private static readonly Logger _log = LogManager.GetCurrentClassLogger(); - private readonly ApplicationDbContext _context; - - public NpcsGenerateController(ApplicationDbContext context) - { - _context = context; - } - - /// - /// Returns all NPCs at the specified level - Campaign, Enclave, or Team - /// - /// campaign, enclave, team - /// - [ProducesResponseType(typeof(IEnumerable), (int) HttpStatusCode.OK)] - [SwaggerResponse((int) HttpStatusCode.OK, Type = typeof(IEnumerable))] - [SwaggerOperation("getKeys")] - [HttpGet] - public IEnumerable GetKeys(string key) - { - return key.ToLower() switch - { - "campaign" => _context.Npcs.Where(x => x.Campaign != null).Distinct().Select(x=>x.Campaign).ToList(), - "enclave" => _context.Npcs.Where(x => x.Enclave != null).Distinct().Select(x=>x.Enclave).ToList(), - "team" => _context.Npcs.Where(x => x.Team != null).Distinct().Select(x=>x.Team).ToList(), - _ => throw new KeyNotFoundException("Invalid key! Key must be campaign, enclave or team") - }; - } - - /// - /// Create NPCs belonging to a campaign, enclave and team based on configuration - /// - /// - /// - /// - [ProducesResponseType(typeof(IEnumerable), (int) HttpStatusCode.OK)] - [SwaggerResponse((int) HttpStatusCode.OK, Type = typeof(IEnumerable))] - [SwaggerOperation("createBuild")] - [HttpPost] - public async Task> Create(GenerationConfiguration config, CancellationToken ct) - { - var t = new Stopwatch(); - t.Start(); - - var createdNpcs = new List(); - foreach (var enclave in config.Enclaves) - { - foreach (var team in enclave.Teams) - { - for (var i = 0; i < team.Npcs.Number; i++) - { - var last = t.ElapsedMilliseconds; - var branch = team.Npcs.Configuration?.Branch ?? MilitaryUnits.GetServiceBranch(); - var npc = NpcRecord.TransformToNpc(Npc.Generate(new NpcGenerationConfiguration { Branch = branch, PreferenceSettings = team.PreferenceSettings })); - npc.Id = npc.NpcProfile.Id; - npc.Team = team.Name; - npc.Campaign = config.Campaign; - npc.Enclave = enclave.Name; - - this._context.Npcs.Add(npc); - createdNpcs.Add(npc); - _log.Trace($"{i} generated in {t.ElapsedMilliseconds - last} ms"); - } - } - } - await this._context.SaveChangesAsync(ct); - - t.Stop(); - _log.Trace($"{createdNpcs.Count} NPCs generated in {t.ElapsedMilliseconds} ms"); - - return createdNpcs; - } - - /// - /// Generate random NPC by random service branch - /// - /// NPC Profile - [ProducesResponseType(typeof(NpcProfile), (int) HttpStatusCode.OK)] - [SwaggerResponse((int) HttpStatusCode.OK, Type = typeof(NpcProfile))] - [SwaggerOperation("generateNpc")] - [HttpPost("one")] - public async Task GenerateOne() - { - var npc = NpcRecord.TransformToNpc(Npc.Generate(MilitaryUnits.GetServiceBranch())); - npc.Id = npc.NpcProfile.Id; - this._context.Npcs.Add(npc); - await this._context.SaveChangesAsync(); - return npc; - } - - /// - /// Ensures an NPC is created for each and every machine currentusername that exists - /// - /// NPC Profile - [ProducesResponseType(typeof(NpcProfile), (int) HttpStatusCode.OK)] - [SwaggerResponse((int) HttpStatusCode.OK, Type = typeof(NpcProfile))] - [SwaggerOperation("syncNpcsWithMachines")] - [HttpPost("syncWithMachineUsernames")] - public async Task SyncWithMachineUsernames() - { - var machines = this._context.Machines.ToList(); - var npcs = this._context.Npcs.ToArray(); - - foreach (var machine in machines) - { - if (npcs.Any(x => x.MachineId == machine.Id)) - continue; - if (npcs.Any(x => string.Equals(x.NpcProfile.Name.ToString()?.Replace(" ", "."), - machine.CurrentUsername, StringComparison.InvariantCultureIgnoreCase))) - continue; - - var npc = NpcRecord.TransformToNpc(Npc.Generate(MilitaryUnits.GetServiceBranch(), machine.CurrentUsername)); - - //todo: need to be sure user is aligned with the machine currentusername - - npc.Id = npc.NpcProfile.Id; - npc.MachineId = machine.Id; - this._context.Npcs.Add(npc); - _log.Trace($"NPC created for {machine.CurrentUsername}..."); - } - await this._context.SaveChangesAsync(); - _log.Trace($"NPCs created for each username in machines"); - } -} \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Controllers/HomeController.cs b/src/Ghosts.Api/Areas/Animator/Controllers/HomeController.cs deleted file mode 100644 index ed80397e..00000000 --- a/src/Ghosts.Api/Areas/Animator/Controllers/HomeController.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. - -using System.Threading.Tasks; -using Ghosts.Api; -using ghosts.api.Areas.Animator.Infrastructure.ContentServices.Ollama; -using ghosts.api.Areas.Animator.Infrastructure.Models; -using Microsoft.AspNetCore.Mvc; - -namespace ghosts.api.Areas.Animator.Controllers; - -[Area("Animator")] -[Route("animator")] -public class HomeController : Controller -{ - [ApiExplorerSettings(IgnoreApi = true)] - [HttpGet] - public IActionResult Index() - { - return View(); - } - - [ApiExplorerSettings(IgnoreApi = true)] - [HttpGet("test")] - public async Task Test() - { - var x = new OllamaFormatterService(Program.ApplicationSettings.AnimatorSettings.Animations.SocialSharing.ContentEngine); - var o = await x.GenerateNextAction(new NpcRecord(),"why is the sky blue?"); - return Ok(o); - - } -} \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs deleted file mode 100644 index ea3703a5..00000000 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Net; -using System.Threading; -using Ghosts.Animator.Extensions; -using ghosts.api.Areas.Animator.Hubs; -using ghosts.api.Areas.Animator.Infrastructure.ContentServices; -using ghosts.api.Areas.Animator.Infrastructure.Models; -using Ghosts.Api.Infrastructure; -using Ghosts.Api.Infrastructure.Data; -using ghosts.api.Infrastructure.Models; -using ghosts.api.Infrastructure.Services; -using Ghosts.Domain; -using Microsoft.AspNetCore.SignalR; -using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; -using NLog; -using RestSharp; - -namespace ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions; - -public class SocialSharingJob -{ - private static readonly Logger _log = LogManager.GetCurrentClassLogger(); - private readonly ApplicationSettings _configuration; - private readonly Random _random; - private readonly int _currentStep; - private readonly IHubContext _activityHubContext; - private readonly CancellationToken _cancellationToken; - private readonly ApplicationDbContext _context; - private readonly IMachineUpdateService _updateService; - private readonly IFormatterService _formatterService; - - public SocialSharingJob(ApplicationSettings configuration, IServiceScopeFactory scopeFactory, Random random, - IHubContext activityHubContext, CancellationToken cancellationToken) - { - try - { - this._activityHubContext = activityHubContext; - this._configuration = configuration; - this._random = random; - - using var innerScope = scopeFactory.CreateScope(); - this._context = innerScope.ServiceProvider.GetRequiredService(); - - this._cancellationToken = cancellationToken; - this._updateService = innerScope.ServiceProvider.GetRequiredService(); - - _formatterService = - new ContentCreationService(_configuration.AnimatorSettings.Animations.Chat.ContentEngine).FormatterService; - - if (!_configuration.AnimatorSettings.Animations.SocialSharing.IsInteracting) - { - _log.Trace($"Social sharing is not interacting. Exiting..."); - return; - } - - while (!this._cancellationToken.IsCancellationRequested) - { - if (this._currentStep > _configuration.AnimatorSettings.Animations.SocialSharing.MaximumSteps) - { - _log.Trace($"Maximum steps met: {this._currentStep - 1}. Social sharing is exiting..."); - return; - } - - this.Step(); - Thread.Sleep(this._configuration.AnimatorSettings.Animations.SocialSharing.TurnLength); - this._currentStep++; - } - } - catch (ThreadInterruptedException e) - { - _log.Info("Social sharing thread interrupted!"); - _log.Error(e); - } - catch (Exception e) - { - _log.Error(e); - } - _log.Info("Social sharing job complete. Exiting..."); - } - - private async void Step() - { - _log.Trace("Social sharing step proceeding..."); - - //take some random NPCs - var activities = new List(); - var rawAgents = this._context.Npcs.ToList(); - if (!rawAgents.Any()) - { - _log.Warn("No NPCs found. Is this correct?"); - return; - } - _log.Trace($"Found {rawAgents.Count()} raw agents..."); - - var agents = rawAgents.Shuffle(_random).Take(_random.Next(5, 20)).ToList(); - _log.Trace($"Processing {agents.Count()} agents..."); - foreach (var agent in agents) - { - _log.Trace($"Processing agent {agent.NpcProfile.Email}..."); - var tweetText = await this._formatterService.GenerateTweet(agent); - if (string.IsNullOrEmpty(tweetText)) - { - _log.Trace($"Content service generated no payload..."); - return; - } - - activities.Add(new NpcActivity {ActivityType = NpcActivity.ActivityTypes.SocialMediaPost, NpcId = agent.Id, CreatedUtc = DateTime.UtcNow, Detail = tweetText}); - - // the payloads to socializer are a bit randomized - var userFormValue = new[] { "user", "usr", "u", "uid", "user_id", "u_id" }.RandomFromStringArray(); - var messageFormValue = - new[] { "message", "msg", "m", "message_id", "msg_id", "msg_text", "text", "payload" } - .RandomFromStringArray(); - - if (_configuration.AnimatorSettings.Animations.SocialSharing.IsSendingTimelinesDirectToSocializer) - { - var client = new RestClient(_configuration.AnimatorSettings.Animations.SocialSharing.PostUrl); - var request = new RestRequest("/", Method.Post) - { - RequestFormat = DataFormat.Json - }; - request.AddParameter(userFormValue, agent.NpcProfile.Name.ToString()); - request.AddParameter(messageFormValue, tweetText); - - try - { - var response = client.Execute(request); - if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.NoContent) - { - throw (new Exception( - $"Socializer responded with {response.StatusCode} to the request agent: {agent.NpcProfile.Name} text: {tweetText}")); - } - } - catch (Exception e) - { - _log.Error( - $"Could not post timeline command to Socializer {_configuration.AnimatorSettings.Animations.SocialSharing.PostUrl}: {e}"); - } - } - - if (_configuration.AnimatorSettings.Animations.SocialSharing.IsSendingTimelinesToGhostsApi) - { - var payload = new - { - Uri = _configuration.AnimatorSettings.Animations.SocialSharing.PostUrl, - Category = "social", - Method = "POST", - Headers = new Dictionary - { - { "u", agent.NpcProfile.Email } - }, - FormValues = new Dictionary - { - { userFormValue, agent.NpcProfile.Email }, - { messageFormValue, tweetText } - } - }; - - var t = new Timeline(); - t.Id = Guid.NewGuid(); - t.Status = Timeline.TimelineStatus.Run; - var th = new TimelineHandler(); - th.HandlerType = HandlerType.BrowserFirefox; - th.Initial = "about:blank"; - th.UtcTimeOn = new TimeSpan(0, 0, 0); - th.UtcTimeOff = new TimeSpan(23, 59, 59); - th.HandlerArgs = new Dictionary(); - th.HandlerArgs.Add("isheadless", "false"); - th.Loop = false; - var te = new TimelineEvent(); - te.Command = "browse"; - te.CommandArgs = new List(); - te.CommandArgs.Add(JsonConvert.SerializeObject(payload)); - te.DelayAfter = 0; - te.DelayBefore = 0; - th.TimeLineEvents.Add(te); - t.TimeLineHandlers.Add(th); - - var machineUpdate = new MachineUpdate(); - if (agent.MachineId.HasValue) - { - machineUpdate.MachineId = agent.MachineId.Value; - } - - machineUpdate.Update = JsonConvert.SerializeObject(t); - machineUpdate.Username = agent.NpcProfile.Email; - machineUpdate.Status = StatusType.Active; - machineUpdate.Type = UpdateClientConfig.UpdateType.TimelinePartial; - - _ = await _updateService.CreateAsync(machineUpdate, _cancellationToken); - } - - //post to hub - await this._activityHubContext.Clients.All.SendAsync("show", - "1", - agent.Id.ToString(), - "social", - tweetText, - DateTime.Now.ToString(CultureInfo.InvariantCulture), - cancellationToken: _cancellationToken); - } - - await this._context.NpcActivities.AddRangeAsync(activities, _cancellationToken); - await this._context.SaveChangesAsync(this._cancellationToken); - } - -} \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPCToInsiderThreatCsv.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPCToInsiderThreatCsv.cs deleted file mode 100644 index 699204f7..00000000 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPCToInsiderThreatCsv.cs +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using FileHelpers; -using Ghosts.Animator; -using Ghosts.Animator.Extensions; -using Ghosts.Animator.Models.InsiderThreat; - -namespace ghosts.api.Areas.Animator.Infrastructure.Models; - -[DelimitedRecord(",")] -public class NPCToInsiderThreatCsv -{ - [FieldQuoted] public Guid Id { get; set; } - [FieldQuoted] public string Hostname { get; set; } - [FieldQuoted] public string DNS { get; set; } - [FieldQuoted] public string OpenVPNUsername { get; set; } - [FieldQuoted] public string OpenVPNPassword { get; set; } - [FieldQuoted] public string GmailUsername { get; set; } - [FieldQuoted] public string GmailPassword { get; set; } - [FieldQuoted] public string NmailUser { get; set; } - [FieldQuoted] public string NmailPassword { get; set; } - [FieldQuoted] public string IPAddress { get; set; } - [FieldQuoted] public string DomainUser { get; set; } - [FieldQuoted] public string FirstName { get; set; } - [FieldQuoted] public string LastName { get; set; } - [FieldQuoted] public string Password { get; set; } - [FieldQuoted] public string Company { get; set; } - [FieldQuoted] public string StartDate { get; set; } - [FieldQuoted] public string Department { get; set; } - [FieldQuoted] public string Organization { get; set; } - [FieldQuoted] public string JobTitle { get; set; } - [FieldQuoted] public int JobLevel { get; set; } - [FieldQuoted] public string Salary { get; set; } - [FieldConverter(typeof(EmptyGuidConverter))] [FieldQuoted] public Guid Manager { get; set; } - [FieldQuoted] public string EmailSuffix { get; set; } - [FieldQuoted] public string Email { get; set; } - [FieldQuoted] public string Type { get; set; } - [FieldQuoted] public string Address { get; set; } - [FieldQuoted] public string City { get; set; } - [FieldQuoted] public string Phone { get; set; } - [FieldQuoted] public string State { get; set; } - [FieldQuoted] public string Zip { get; set; } - [FieldQuoted] public string Country { get; set; } - [FieldQuoted] public string EmploymentStatus { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool Disgruntled { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool Demoted { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool MissedRaises { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool TeamLayoffs { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool NotifiedOfTermination { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool AnnouncesTermination { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool AnnouncesResignation { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool Threats { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool MissedPromotion { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool Insubordination { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool Absenteeism { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool HRComplaints { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool ITPolicyViolations { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool IPPolicyViolations { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool DrugAlcoholAbuse { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool CoworkerConflict { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool EAPReferral { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool AccessRevoked { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool UnauthorizedCodingChange { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool UnauthorizedAccessChange { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool FinancialProblems { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool ArrestRecord { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool GamblingHistory { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool ServiceAccountUse { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool RemoteAccess { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool BackdoorAccountUse { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool SolicitedByCompetitor { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool AfterHoursLogin { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool PrivilegeCreep { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool FileExtensionModification { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool FileHeaderModification { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool FileContentModification { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool FileTypeModification { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool SensitiveInformationCopied { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool ScreenShots { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool ZipFile { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool Encryption { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool DocumentMarkingTampering { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool Steganography { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool LogDeletion { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool ConcealmentInformation { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool SaleAttempt { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool Scanner { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool CloudStorage { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool RemovableMedia { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool Print { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool NetworkShare { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool PersonalEmailAccount { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool EmailToConspirator { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool DNSExfiltrationTool { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool FileDeletion { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool RecentHRTicket { get; set; } - [FieldConverter(typeof(TrueFalseToXConverter))] [FieldQuoted] public bool BackgroundCkResult { get; set; } - [FieldQuoted] public int InterpersonalSkills { get; set; } - [FieldQuoted] public int AdherenceToPolicy { get; set; } - [FieldQuoted] public int EnthusiasmAndAttitude { get; set; } - [FieldQuoted] public int OpenToFeedback { get; set; } - [FieldQuoted] public int GeneralPerformance { get; set; } - [FieldQuoted] public int OverallPerformance { get; set; } - - public static IEnumerable ConvertToCsv(IEnumerable npcs) - { - var finalList = new List(); - foreach (var n in npcs) - { - var events = n.NpcProfile.InsiderThreat.GetAllEvents(); - - var i = AnimatorRandom.Rand.Next(0, 99); - var o = new NPCToInsiderThreatCsv(); - o.Id = n.Id; - o.Hostname = $"user{i}"; - o.DNS = $"FIN-USR-{i}"; - - foreach (var account in n.NpcProfile.Accounts.Where(x => x.Url.ToLower().Contains("openvpn"))) - { - o.OpenVPNUsername = account.Username; - o.OpenVPNPassword = account.Password; - } - - // o.HRMUserID - // o.HRMManagerID - // o.TestCase - // o.ExampleCase - - foreach (var account in n.NpcProfile.Accounts.Where(x => x.Url.ToLower().Contains("gmail"))) - { - o.GmailUsername = account.Username; - o.GmailPassword = account.Password; - } - - foreach (var account in n.NpcProfile.Accounts.Where(x => x.Url.ToLower().Contains("nmail"))) - { - o.NmailUser = account.Username; - o.NmailPassword = account.Password; - } - - o.IPAddress = n.NpcProfile.Workstation.IPAddress; - - o.DomainUser = n.NpcProfile.Workstation.Username; - o.FirstName = n.NpcProfile.Name.First; - o.LastName = n.NpcProfile.Name.Last; - o.Password = n.NpcProfile.Workstation.Password; - o.Type = "User"; - if (n.NpcProfile.Employment.EmploymentRecords != null && n.NpcProfile.Employment.EmploymentRecords.Any()) - { - var currentEmployer = n.NpcProfile.Employment.EmploymentRecords.LastOrDefault(); - o.EmploymentStatus = "Employed"; - o.Company = currentEmployer?.Company; - o.StartDate = currentEmployer?.StartDate.ToString(CultureInfo.InvariantCulture); - o.Department = currentEmployer?.Department; - o.Organization = currentEmployer?.Organization; - o.JobTitle = currentEmployer?.JobTitle; - o.JobLevel = currentEmployer.Level; - o.Salary = currentEmployer?.Salary.ToString(CultureInfo.InvariantCulture); - o.Manager = currentEmployer.Manager; - if(o.JobLevel > 2) - { - if (AnimatorRandom.Rand.Next(0, 100) > 50) - { - o.Type = "Administrator"; - } - } - } - else - { - o.EmploymentStatus = "Unemployed"; - } - o.EmailSuffix = n.NpcProfile.Email.After("@"); - o.Email = n.NpcProfile.Email; - - o.Address = n.NpcProfile.Address.FirstOrDefault()?.Address1; - o.City = n.NpcProfile.Address.FirstOrDefault()?.City; - o.Phone = n.NpcProfile.CellPhone; - o.State = n.NpcProfile.Address.FirstOrDefault()?.State; - o.Zip = n.NpcProfile.Address.FirstOrDefault()?.PostalCode; - o.Country = "US"; - var relatedEvents = events as RelatedEvent[] ?? events.ToArray(); - o.Demoted = relatedEvents.Any(x => x.Description.Contains("Demoted", StringComparison.CurrentCultureIgnoreCase)); - o.Disgruntled = relatedEvents.Length > 3; - o.MissedRaises = relatedEvents.Any(x => x.Description.Contains("Missed raise", StringComparison.CurrentCultureIgnoreCase)); - o.TeamLayoffs = relatedEvents.Any(x => x.Description.Contains("Team layoffs", StringComparison.CurrentCultureIgnoreCase)); - o.NotifiedOfTermination = relatedEvents.Any(x => x.Description.Contains("Notified of termination", StringComparison.CurrentCultureIgnoreCase)); - o.AnnouncesTermination = relatedEvents.Any(x => x.Description.Contains("Announces Termination", StringComparison.CurrentCultureIgnoreCase)); - o.AnnouncesResignation = relatedEvents.Any(x => x.Description.Contains("Announces Resignation", StringComparison.CurrentCultureIgnoreCase)); - o.Threats = relatedEvents.Any(x => x.Description.Contains("Threatening", StringComparison.CurrentCultureIgnoreCase)) || - relatedEvents.Any(x => x.Description.Contains("threatened", StringComparison.CurrentCultureIgnoreCase)); - o.MissedPromotion = relatedEvents.Any(x => x.Description.Contains("Missed Promotion", StringComparison.CurrentCultureIgnoreCase)); - o.Insubordination = relatedEvents.Any(x => x.Description.Contains("insubordinate", StringComparison.CurrentCultureIgnoreCase)); - o.Absenteeism = relatedEvents.Any(x => x.Description.Contains("missed work", StringComparison.CurrentCultureIgnoreCase)); - o.HRComplaints = relatedEvents.Any(x => x.Description.Contains("Human Resource Complaint", StringComparison.CurrentCultureIgnoreCase)); - o.ITPolicyViolations = relatedEvents.Any(x => x.Description.Contains("Employee violated company IT policy", StringComparison.CurrentCultureIgnoreCase)); - o.IPPolicyViolations = relatedEvents.Any(x => x.Description.Contains("Compliance Violation", StringComparison.CurrentCultureIgnoreCase)); - o.DrugAlcoholAbuse = n.NpcProfile.InsiderThreat.SubstanceAbuseAndAddictiveBehaviors.RelatedEvents.Any(); - o.CoworkerConflict = relatedEvents.Any(x => x.Description.Contains("coworker", StringComparison.CurrentCultureIgnoreCase)); - o.EAPReferral = relatedEvents.Any(x => x.Description.Contains("EAP Referral", StringComparison.CurrentCultureIgnoreCase)); - o.AccessRevoked = relatedEvents.Any(x => x.Description.Contains("Access Revoked", StringComparison.CurrentCultureIgnoreCase)); - o.UnauthorizedCodingChange = relatedEvents.Any(x => x.Description.Contains("unauthorized changes to a code base", StringComparison.CurrentCultureIgnoreCase)); - o.UnauthorizedAccessChange = relatedEvents.Any(x => x.Description.Contains("unauthorized changes to access", StringComparison.CurrentCultureIgnoreCase)); - o.FinancialProblems = relatedEvents.Any(x => x.Description.Contains("Financial Problems", StringComparison.CurrentCultureIgnoreCase)) || - n.NpcProfile.InsiderThreat.FinancialConsiderations.RelatedEvents.Any(); - o.ArrestRecord = relatedEvents.Any(x => x.Description.Contains("arrest", StringComparison.CurrentCultureIgnoreCase)); - o.GamblingHistory = relatedEvents.Any(x => x.Description.Contains("gambling", StringComparison.CurrentCultureIgnoreCase)); - o.ServiceAccountUse = relatedEvents.Any(x => x.Description.Contains("service account", StringComparison.CurrentCultureIgnoreCase)); - o.RemoteAccess = relatedEvents.Any(x => x.Description.Contains("Virtual Access Anomaly", StringComparison.CurrentCultureIgnoreCase)); - o.BackdoorAccountUse = relatedEvents.Any(x => x.Description.Contains("backdoor account", StringComparison.CurrentCultureIgnoreCase)); - o.SolicitedByCompetitor = relatedEvents.Any(x => x.Description.Contains("Solicited by Competitor", StringComparison.CurrentCultureIgnoreCase)); - o.AfterHoursLogin = relatedEvents.Any(x => x.Description.Contains("After Hours Login", StringComparison.CurrentCultureIgnoreCase)); - o.PrivilegeCreep = relatedEvents.Any(x => x.Description.Contains("Misusing Privileged Function", StringComparison.CurrentCultureIgnoreCase)); - o.FileExtensionModification = relatedEvents.Any(x => x.Description.Contains("modified file extension", StringComparison.CurrentCultureIgnoreCase)); - o.FileHeaderModification = relatedEvents.Any(x => x.Description.Contains("modified file header", StringComparison.CurrentCultureIgnoreCase)); - o.FileContentModification = relatedEvents.Any(x => x.Description.Contains("altered document", StringComparison.CurrentCultureIgnoreCase)); - o.FileTypeModification = relatedEvents.Any(x => x.Description.Contains("modified file extension", StringComparison.CurrentCultureIgnoreCase)); - o.SensitiveInformationCopied = relatedEvents.Any(x => x.Description.Contains("copied sensitive information", StringComparison.CurrentCultureIgnoreCase)); - o.ScreenShots = relatedEvents.Any(x => x.Description.Contains("took screenshots", StringComparison.CurrentCultureIgnoreCase)); - o.ZipFile = relatedEvents.Any(x => x.Description.Contains("compressed files", StringComparison.CurrentCultureIgnoreCase)); - o.Encryption = relatedEvents.Any(x => x.Description.Contains("encrypted files", StringComparison.CurrentCultureIgnoreCase)); - o.DocumentMarkingTampering = relatedEvents.Any(x => x.Description.Contains("altered document markings", StringComparison.CurrentCultureIgnoreCase)); - o.Steganography = relatedEvents.Any(x => x.Description.Contains("used steganography", StringComparison.CurrentCultureIgnoreCase)); - o.LogDeletion = relatedEvents.Any(x => x.Description.Contains("deleted logs", StringComparison.CurrentCultureIgnoreCase)); - o.ConcealmentInformation = relatedEvents.Any(x => x.Description.Contains("concealed actions", StringComparison.CurrentCultureIgnoreCase)); - o.SaleAttempt = relatedEvents.Any(x => x.Description.Contains("Information Sale Attempt", StringComparison.CurrentCultureIgnoreCase)); - o.Scanner = relatedEvents.Any(x => x.Description.Contains("scanned files", StringComparison.CurrentCultureIgnoreCase)); - o.CloudStorage = relatedEvents.Any(x => x.Description.Contains("cloud storage", StringComparison.CurrentCultureIgnoreCase)); - o.RemovableMedia = relatedEvents.Any(x => x.Description.Contains("removable media device", StringComparison.CurrentCultureIgnoreCase)); - o.Print = relatedEvents.Any(x => x.Description.Contains("printed sensitive files", StringComparison.CurrentCultureIgnoreCase)); - o.NetworkShare = relatedEvents.Any(x => x.Description.Contains("unauthorized changes", StringComparison.CurrentCultureIgnoreCase)); - o.PersonalEmailAccount = relatedEvents.Any(x => x.Description.Contains("personal email account", StringComparison.CurrentCultureIgnoreCase)); - o.EmailToConspirator = relatedEvents.Any(x => x.Description.Contains("Email to Conspirator", StringComparison.CurrentCultureIgnoreCase)); - o.DNSExfiltrationTool = relatedEvents.Any(x => x.Description.Contains("dns exfiltration", StringComparison.CurrentCultureIgnoreCase)); - o.FileDeletion = relatedEvents.Any(x => x.Description.Contains("deleted files", StringComparison.CurrentCultureIgnoreCase)); - o.RecentHRTicket = relatedEvents.Any(x => x.Reported > DateTime.Now.AddYears(-1)); //reported in the last year - o.BackgroundCkResult = n.NpcProfile.InsiderThreat.IsBackgroundCheckStatusClear; - o.InterpersonalSkills = n.NpcProfile.MentalHealth.InterpersonalSkills; - o.AdherenceToPolicy = n.NpcProfile.MentalHealth.AdherenceToPolicy; - o.EnthusiasmAndAttitude = n.NpcProfile.MentalHealth.EnthusiasmAndAttitude; - o.OpenToFeedback = n.NpcProfile.MentalHealth.OpenToFeedback; - o.GeneralPerformance = n.NpcProfile.MentalHealth.GeneralPerformance; - o.OverallPerformance = n.NpcProfile.MentalHealth.OverallPerformance; - finalList.Add(o); - } - - foreach (var npc in finalList.Where(x => x.Manager != Guid.Empty)) - { - var manager = finalList.FirstOrDefault(x => x.Id == npc.Manager); - if (manager == null) continue; - if (npc.Company != manager.Company || npc.Department != manager.Department) - { - npc.Manager = Guid.Empty; - } - } - - return finalList; - } -} - -public class TrueFalseToXConverter : ConverterBase -{ - public override object StringToField(string o) - { - return o.Equals("X", StringComparison.InvariantCultureIgnoreCase); - } - - public override string FieldToString(object o) - { - return Convert.ToBoolean(o) ? "X" : string.Empty; - } - -} - -public class EmptyGuidConverter : ConverterBase -{ - public override object StringToField(string o) - { - return o.Equals(Guid.Empty.ToString(), StringComparison.InvariantCultureIgnoreCase); - } - - public override string FieldToString(object o) - { - var x = Guid.Parse(o.ToString() ?? ""); - return x == Guid.Empty ? "" : x.ToString(); - } -} \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Services/NpcService.cs b/src/Ghosts.Api/Areas/Animator/Infrastructure/Services/NpcService.cs deleted file mode 100644 index 7141118d..00000000 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/Services/NpcService.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Ghosts.Animator; -using Ghosts.Animator.Models; -using ghosts.api.Areas.Animator.Infrastructure.Models; -using Ghosts.Api.Infrastructure.Data; -using Microsoft.EntityFrameworkCore; -using NLog; - -namespace ghosts.api.Areas.Animator.Infrastructure.Services; - -public interface INpcService -{ - public Task> GetAll(); - public Task> GetEnclave(string campaign, string enclave); - public Task> GetListAsync(); - public Task> GetTeam(string campaign, string enclave, string team); - public Task GetById(Guid id); - public Task Create(NpcProfile npcProfile, bool generate); - public Task DeleteById(Guid id); -} - -public class NpcService : INpcService -{ - private static readonly Logger _log = LogManager.GetCurrentClassLogger(); - private readonly ApplicationDbContext _context; - - public NpcService(ApplicationDbContext context) - { - _context = context; - } - - public async Task> GetAll() - { - return await this._context.Npcs.ToListAsync(); - } - - public async Task> GetEnclave(string campaign, string enclave) - { - return await _context.Npcs.Where(x => x.Campaign == campaign && x.Enclave == enclave).ToListAsync(); - } - - public async Task> GetListAsync() - { - return await this._context.Npcs - .Select(item => new NpcNameId - { - Id = item.Id, - Name = $"{item.NpcProfile.Name.First} {item.NpcProfile.Name.Last}" - }) - .ToListAsync(); - } - - public async Task> GetListAsync(string campaign) - { - return await this._context.Npcs - .Where(x=>x.Campaign == campaign) - .Select(item => new NpcNameId - { - Id = item.Id, - Name = $"{item.NpcProfile.Name.First} {item.NpcProfile.Name.Last}" - }) - .ToListAsync(); - } - - public async Task> GetTeam(string campaign, string enclave, string team) - { - return await this._context.Npcs.Where(x => x.Campaign == campaign && x.Enclave == enclave && x.Team == team).ToListAsync(); - } - - public async Task GetById(Guid id) - { - return await this._context.Npcs.FirstOrDefaultAsync(x => x.Id == id); - } - - public async Task Create(NpcProfile npcProfile, bool generate) - { - NpcRecord npc; - if (generate) - { - npc = NpcRecord.TransformToNpc(Npc.Generate(MilitaryUnits.GetServiceBranch())); - npc.NpcProfile.Name = npcProfile.Name; - npc.NpcProfile.Email = npcProfile.Email; - } - else - { - npc = NpcRecord.TransformToNpc(npcProfile); - } - - npc.NpcProfile.Id = Guid.NewGuid(); - npc.NpcProfile.Created = DateTime.UtcNow; - npc.Id = npc.NpcProfile.Id; - - this._context.Npcs.Add(npc); - await this._context.SaveChangesAsync(); - return npc; - } - - public async Task DeleteById(Guid id) - { - var o = await this._context.Npcs.FindAsync(id); - if (o != null) - { - this._context.Npcs.Remove(o); - await this._context.SaveChangesAsync(); - } - } -} \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Views/Home/Index.cshtml b/src/Ghosts.Api/Areas/Animator/Views/Home/Index.cshtml deleted file mode 100644 index 55fbe913..00000000 --- a/src/Ghosts.Api/Areas/Animator/Views/Home/Index.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -
    -
    -

    Welcome to GHOSTS ANIMATOR.

    -
    -
    diff --git a/src/Ghosts.Api/Areas/Animator/Views/_ViewStart.cshtml b/src/Ghosts.Api/Areas/Animator/Views/_ViewStart.cshtml deleted file mode 100644 index c34f4d58..00000000 --- a/src/Ghosts.Api/Areas/Animator/Views/_ViewStart.cshtml +++ /dev/null @@ -1,3 +0,0 @@ -@{ - Layout = "~/Views/Shared/_Layout.cshtml"; -} \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Controllers/AnimationsController.cs b/src/Ghosts.Api/Controllers/AnimationsController.cs similarity index 95% rename from src/Ghosts.Api/Areas/Animator/Controllers/AnimationsController.cs rename to src/Ghosts.Api/Controllers/AnimationsController.cs index 2c831323..4151530f 100644 --- a/src/Ghosts.Api/Areas/Animator/Controllers/AnimationsController.cs +++ b/src/Ghosts.Api/Controllers/AnimationsController.cs @@ -6,10 +6,9 @@ using Newtonsoft.Json; using NLog; -namespace ghosts.api.Areas.Animator.Controllers; +namespace ghosts.api.Controllers; -[Area("Animator")] -[Route("animator/[controller]")] +[Route("[controller]")] [ApiExplorerSettings(IgnoreApi = true)] public class AnimationsController : Controller { diff --git a/src/Ghosts.Api/Controllers/Api/AnimationJobsController.cs b/src/Ghosts.Api/Controllers/Api/AnimationJobsController.cs new file mode 100644 index 00000000..9aad418a --- /dev/null +++ b/src/Ghosts.Api/Controllers/Api/AnimationJobsController.cs @@ -0,0 +1,44 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + +using System; +using ghosts.api.Areas.Animator.Infrastructure.Animations; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; + +namespace ghosts.api.Controllers.Api; + +[Route("animations")] +[Route("api/[controller]")] +[Produces("application/json")] +public class AnimationJobsController : Controller +{ + private readonly AnimationsManager _animationsManager; + + public AnimationJobsController(IServiceProvider serviceProvider) + { + _animationsManager = serviceProvider.GetRequiredService() as AnimationsManager; + } + // + // [SwaggerOperation("AnimationStart")] + // [HttpGet("start")] + // public async Task Start(CancellationToken cancellationToken) + // { + // await _animationsManager.StartAsync(cancellationToken); + // return Ok(); + // } + // + // [SwaggerOperation("AnimationStop")] + // [HttpGet("stop")] + // public async Task Stop(CancellationToken cancellationToken) + // { + // await _animationsManager.StopAsync(cancellationToken); + // return Ok(); + // } + // + // [SwaggerOperation("AnimationGetStatus")] + // [HttpGet("status")] + // public IActionResult Status(CancellationToken cancellationToken) + // { + // return Ok(_animationsManager.GetRunningJobs()); + // } +} \ No newline at end of file diff --git a/src/Ghosts.Api/Controllers/ClientIdController.cs b/src/Ghosts.Api/Controllers/Api/ClientIdController.cs similarity index 67% rename from src/Ghosts.Api/Controllers/ClientIdController.cs rename to src/Ghosts.Api/Controllers/Api/ClientIdController.cs index df2b0187..ed0dde97 100755 --- a/src/Ghosts.Api/Controllers/ClientIdController.cs +++ b/src/Ghosts.Api/Controllers/Api/ClientIdController.cs @@ -6,8 +6,9 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using NLog; +using Swashbuckle.AspNetCore.Annotations; -namespace Ghosts.Api.Controllers +namespace ghosts.api.Controllers.Api { /// /// GHOSTS CLIENT CONTROLLER @@ -31,22 +32,29 @@ public ClientIdController(IMachineService service) /// /// Cancellation Token /// A client's particular unique GHOSTS system ID (GUID) + [SwaggerOperation("ClientIdGet")] [HttpGet] public async Task Index(CancellationToken ct) { - var id = Request.Headers["ghosts-id"]; - _log.Trace($"Request by {id}"); + if (!Request.Headers.TryGetValue("ghosts-id", out var id)) + { + _log.Warn("Request missing ghosts-id header"); + return BadRequest("Missing ghosts-id header"); + } + + _log.Info($"Request by {id}"); - var findMachineResponse = await this._service.FindOrCreate(HttpContext, ct); + var findMachineResponse = await _service.FindOrCreate(HttpContext, ct); if (!findMachineResponse.IsValid()) { + _log.Error($"FindOrCreate failed for {id}: {findMachineResponse.Error}"); return StatusCode(StatusCodes.Status401Unauthorized, findMachineResponse.Error); } - var m = findMachineResponse.Machine; + var machineId = findMachineResponse.Machine.Id; //client saves this for future calls - return Json(m.Id); + return Ok(machineId); } } -} \ No newline at end of file +} diff --git a/src/Ghosts.Api/Controllers/ClientResultsController.cs b/src/Ghosts.Api/Controllers/Api/ClientResultsController.cs similarity index 60% rename from src/Ghosts.Api/Controllers/ClientResultsController.cs rename to src/Ghosts.Api/Controllers/Api/ClientResultsController.cs index ea678fca..95849b00 100755 --- a/src/Ghosts.Api/Controllers/ClientResultsController.cs +++ b/src/Ghosts.Api/Controllers/Api/ClientResultsController.cs @@ -12,8 +12,9 @@ using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using NLog; +using Swashbuckle.AspNetCore.Annotations; -namespace Ghosts.Api.Controllers +namespace ghosts.api.Controllers.Api { /// /// GHOSTS CLIENT CONTROLLER @@ -38,28 +39,32 @@ public ClientResultsController(IBackgroundQueue service) /// The encrypted timeline or health log payload /// Cancellation Token /// 204 No Content on success + [SwaggerOperation("ClientResultsCreateSecure")] [HttpPost("secure")] public IActionResult Secure([FromBody] EncryptedPayload transmission, CancellationToken ct) { - string raw; - try { - var key = Request.Headers["ghosts-name"].ToString(); - //decrypt + if (!Request.Headers.TryGetValue("ghosts-name", out var key)) + { + _log.Warn("Request missing ghosts-name header"); + return BadRequest("Missing ghosts-name header"); + } + + // Decrypt transmission.Payload = Base64Encoder.Base64Decode(transmission.Payload); - raw = Crypto.DecryptStringAes(transmission.Payload, key); + var raw = Crypto.DecryptStringAes(transmission.Payload, key); + + // Deserialize + var value = JsonConvert.DeserializeObject(raw); + + return Process(HttpContext, Request, value, ct); } catch (Exception exc) { - _log.Trace(exc); - throw new Exception("Malformed data"); + _log.Error(exc, "Malformed data"); + return BadRequest("Malformed data"); } - - //deserialize - var value = JsonConvert.DeserializeObject(raw); - - return Process(HttpContext, Request, value, ct); } /// @@ -68,48 +73,49 @@ public IActionResult Secure([FromBody] EncryptedPayload transmission, Cancellati /// Timeline or health log payload /// Cancellation Token /// 204 No Content on success + [SwaggerOperation("ClientResultsCreate")] [HttpPost] public IActionResult Index([FromBody] TransferLogDump value, CancellationToken ct) { return Process(HttpContext, Request, value, ct); } - // ReSharper disable once UnusedParameter.Local private IActionResult Process(HttpContext context, HttpRequest request, TransferLogDump value, CancellationToken ct) { - var id = request.Headers["ghosts-id"]; + if (!Request.Headers.TryGetValue("ghosts-id", out var id)) + { + _log.Warn("Request missing ghosts-id header"); + return Unauthorized("Missing ghosts-id header"); + } - var m = WebRequestReader.GetMachine(HttpContext); + var m = WebRequestReader.GetMachine(context); if (!string.IsNullOrEmpty(id)) { m.Id = new Guid(id); } - else + else if (!m.IsValid()) { - if (!m.IsValid()) - return StatusCode(StatusCodes.Status401Unauthorized, "Invalid machine request"); + return Unauthorized("Invalid machine request"); } if (value is not null && !string.IsNullOrEmpty(value.Log)) { - _log.Trace($"payload received: {value.Log}"); + _log.Info($"Payload received: {value.Log}"); - _service.Enqueue( - new QueueEntry + _service.Enqueue(new QueueEntry + { + Payload = new MachineQueueEntry { - Payload = - new MachineQueueEntry - { - Machine = m, - LogDump = value, - HistoryType = Machine.MachineHistoryItem.HistoryType.PostedResults - }, - Type = QueueEntry.Types.Machine - }); + Machine = m, + LogDump = value, + HistoryType = Machine.MachineHistoryItem.HistoryType.PostedResults + }, + Type = QueueEntry.Types.Machine + }); } return NoContent(); } } -} \ No newline at end of file +} diff --git a/src/Ghosts.Api/Controllers/ClientSurveyController.cs b/src/Ghosts.Api/Controllers/Api/ClientSurveyController.cs similarity index 64% rename from src/Ghosts.Api/Controllers/ClientSurveyController.cs rename to src/Ghosts.Api/Controllers/Api/ClientSurveyController.cs index 0b23b57d..def3e306 100755 --- a/src/Ghosts.Api/Controllers/ClientSurveyController.cs +++ b/src/Ghosts.Api/Controllers/Api/ClientSurveyController.cs @@ -11,8 +11,9 @@ using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using NLog; +using Swashbuckle.AspNetCore.Annotations; -namespace ghosts.api.Controllers +namespace ghosts.api.Controllers.Api { /// /// GHOSTS CLIENT CONTROLLER @@ -37,28 +38,32 @@ public ClientSurveyController(IBackgroundQueue service) /// The encrypted survey result /// Cancellation Token /// 204 No Content on success + [SwaggerOperation("ClientSurveyCreateSecure")] [HttpPost("secure")] public IActionResult Secure([FromBody] EncryptedPayload transmission, CancellationToken ct) { - string raw; - try { - var key = Request.Headers["ghosts-name"].ToString(); - //decrypt - the headers must be the same as encrypted with the client + if (!Request.Headers.TryGetValue("ghosts-name", out var key)) + { + _log.Warn("Request missing ghosts-name header"); + return BadRequest("Missing ghosts-name header"); + } + + // Decrypt transmission.Payload = Base64Encoder.Base64Decode(transmission.Payload); - raw = Crypto.DecryptStringAes(transmission.Payload, key); + var raw = Crypto.DecryptStringAes(transmission.Payload, key); + + // Deserialize + var value = JsonConvert.DeserializeObject(raw); + + return Process(HttpContext, Request, value, ct); } catch (Exception exc) { - _log.Trace(exc); - throw new Exception("Malformed data"); + _log.Error(exc, "Malformed data"); + return BadRequest("Malformed data"); } - - //deserialize - var value = JsonConvert.DeserializeObject(raw); - - return Process(HttpContext, Request, value, ct); } /// @@ -67,6 +72,7 @@ public IActionResult Secure([FromBody] EncryptedPayload transmission, Cancellati /// The client survey result /// Cancellation Token /// 204 No Content on success + [SwaggerOperation("ClientSurveyCreate")] [HttpPost] public IActionResult Index([FromBody] Survey value, CancellationToken ct) { @@ -75,29 +81,32 @@ public IActionResult Index([FromBody] Survey value, CancellationToken ct) private IActionResult Process(HttpContext context, HttpRequest request, Survey value, CancellationToken ct) { - var id = request.Headers["ghosts-id"]; + if (!Request.Headers.TryGetValue("ghosts-id", out var id)) + { + _log.Warn("Request missing ghosts-id header"); + return Unauthorized("Missing ghosts-id header"); + } - _log.Trace($"Request by {id}"); + _log.Info($"Request by {id}"); - var m = WebRequestReader.GetMachine(HttpContext); + var m = WebRequestReader.GetMachine(context); if (!string.IsNullOrEmpty(id)) { m.Id = new Guid(id); } - else + else if (!m.IsValid()) { - if (!m.IsValid()) - return StatusCode(StatusCodes.Status401Unauthorized, "Invalid machine request"); + return Unauthorized("Invalid machine request"); } value.MachineId = m.Id; if (value.Created == DateTime.MinValue) value.Created = DateTime.UtcNow; - _service.Enqueue(new QueueEntry {Type = QueueEntry.Types.Survey, Payload = value}); + _service.Enqueue(new QueueEntry { Type = QueueEntry.Types.Survey, Payload = value }); return NoContent(); } } -} \ No newline at end of file +} diff --git a/src/Ghosts.Api/Controllers/ClientTimeline.cs b/src/Ghosts.Api/Controllers/Api/ClientTimeline.cs similarity index 73% rename from src/Ghosts.Api/Controllers/ClientTimeline.cs rename to src/Ghosts.Api/Controllers/Api/ClientTimeline.cs index f3d3e654..324cd309 100644 --- a/src/Ghosts.Api/Controllers/ClientTimeline.cs +++ b/src/Ghosts.Api/Controllers/Api/ClientTimeline.cs @@ -6,12 +6,12 @@ using Ghosts.Api.Infrastructure; using ghosts.api.Infrastructure.Services; using Ghosts.Domain; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using NLog; +using Swashbuckle.AspNetCore.Annotations; -namespace ghosts.api.Controllers +namespace ghosts.api.Controllers.Api { /// /// GHOSTS CLIENT CONTROLLER @@ -38,12 +38,17 @@ public ClientTimelineController(IMachineTimelinesService service, IMachineServic /// The client's current timeline /// Cancellation Token /// The saved timeline record + [SwaggerOperation("ClientTimelineCreate")] [HttpPost] public async Task Index([FromBody] string timeline, CancellationToken ct) { - var id = Request.Headers["ghosts-id"]; + if (!Request.Headers.TryGetValue("ghosts-id", out var id)) + { + _log.Warn("Request missing ghosts-id header"); + return Unauthorized("Missing ghosts-id header"); + } - _log.Trace($"Request by {id}"); + _log.Info($"Request by {id}"); var m = WebRequestReader.GetMachine(HttpContext); @@ -52,12 +57,9 @@ public async Task Index([FromBody] string timeline, CancellationT m.Id = new Guid(id); await _machineService.CreateAsync(m, ct); } - else + else if (!m.IsValid()) { - if (!m.IsValid()) - { - return StatusCode(StatusCodes.Status401Unauthorized, "Invalid machine request"); - } + return Unauthorized("Invalid machine request"); } Timeline tl; @@ -68,11 +70,12 @@ public async Task Index([FromBody] string timeline, CancellationT } catch (Exception e) { - _log.Error(e); - return StatusCode(StatusCodes.Status400BadRequest, "Invalid timeline file"); + _log.Error(e, "Invalid timeline file"); + return BadRequest("Invalid timeline file"); } - return Ok(await _service.CreateAsync(m, tl, ct)); + var createdTimeline = await _service.CreateAsync(m, tl, ct); + return Ok(createdTimeline); } } -} \ No newline at end of file +} diff --git a/src/Ghosts.Api/Controllers/ClientUpdatesController.cs b/src/Ghosts.Api/Controllers/Api/ClientUpdatesController.cs similarity index 94% rename from src/Ghosts.Api/Controllers/ClientUpdatesController.cs rename to src/Ghosts.Api/Controllers/Api/ClientUpdatesController.cs index e0b15f38..498d59b7 100755 --- a/src/Ghosts.Api/Controllers/ClientUpdatesController.cs +++ b/src/Ghosts.Api/Controllers/Api/ClientUpdatesController.cs @@ -9,8 +9,9 @@ using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json.Linq; using NLog; +using Swashbuckle.AspNetCore.Annotations; -namespace Ghosts.Api.Controllers +namespace ghosts.api.Controllers.Api { /// /// GHOSTS CLIENT CONTROLLER @@ -41,10 +42,11 @@ public ClientUpdatesController(IMachineService machineService, IMachineUpdateSer /// Returns json payload of a particular update /// Unauthorized or incorrectly formatted machine request /// No Update - [HttpGet] [ProducesResponseType(200)] [ProducesResponseType(401)] [ProducesResponseType(404)] + [SwaggerOperation("ClientUpdatesCreate")] + [HttpGet] public async Task Index(CancellationToken ct) { var id = Request.Headers["ghosts-id"]; diff --git a/src/Ghosts.Api/Controllers/InstallController.cs b/src/Ghosts.Api/Controllers/Api/InstallController.cs similarity index 83% rename from src/Ghosts.Api/Controllers/InstallController.cs rename to src/Ghosts.Api/Controllers/Api/InstallController.cs index 68667829..d5c7f504 100644 --- a/src/Ghosts.Api/Controllers/InstallController.cs +++ b/src/Ghosts.Api/Controllers/Api/InstallController.cs @@ -1,8 +1,9 @@ using System.IO; using System.Linq; using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; -namespace ghosts.api.Controllers; +namespace ghosts.api.Controllers.Api; /// /// For installing client binaries from the api @@ -10,6 +11,7 @@ namespace ghosts.api.Controllers; [Route("/install")] public class InstallController : Controller { + [SwaggerOperation("InstallersGetWindows64")] [HttpGet("client/windows")] [HttpGet("client/windows/x64")] public IActionResult Windows64Client() @@ -17,12 +19,14 @@ public IActionResult Windows64Client() return GetFile("config/binaries/windows/x64"); } + [SwaggerOperation("InstallersGetWindows32")] [HttpGet("client/windows/x32")] public IActionResult Windows32Client() { return GetFile("config/binaries/windows/x32"); } + [SwaggerOperation("InstallersGetLinux")] [HttpGet("client/linux")] public IActionResult LinuxClient() { diff --git a/src/Ghosts.Api/Controllers/MachineGroupsController.cs b/src/Ghosts.Api/Controllers/Api/MachineGroupsController.cs similarity index 60% rename from src/Ghosts.Api/Controllers/MachineGroupsController.cs rename to src/Ghosts.Api/Controllers/Api/MachineGroupsController.cs index 79b0add1..713309f2 100644 --- a/src/Ghosts.Api/Controllers/MachineGroupsController.cs +++ b/src/Ghosts.Api/Controllers/Api/MachineGroupsController.cs @@ -3,17 +3,20 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading; using System.Threading.Tasks; +using Ghosts.Api.Infrastructure.Extensions; using ghosts.api.Infrastructure.Models; using ghosts.api.Infrastructure.Services; using Microsoft.AspNetCore.Mvc; using NLog; +using Swashbuckle.AspNetCore.Annotations; -namespace Ghosts.Api.Controllers +namespace ghosts.api.Controllers.Api { [Produces("application/json")] - [Route("api/machinegroups")] + [Route("api/[controller]")] [ResponseCache(Duration = 5)] public class MachineGroupsController : Controller { @@ -33,6 +36,7 @@ public MachineGroupsController(IMachineGroupService service, IMachineService mac /// Query /// Cancellation Token /// Group information + [SwaggerOperation("MachineGroupsGetByQuery")] [HttpGet] public async Task> GetMachineGroup(string q, CancellationToken ct) { @@ -45,14 +49,23 @@ public async Task> GetMachineGroup(string q, CancellationToke /// Group Id /// Cancellation Token /// Group information + [SwaggerOperation("MachineGroupsGetById")] [HttpGet("{id}")] public async Task GetMachineGroup([FromRoute] int id, CancellationToken ct) { - if (!ModelState.IsValid) return BadRequest(ModelState); + if (!ModelState.IsValid) + { + _log.Warn("Invalid model state"); + return BadRequest(ModelState); + } var machineGroup = await _service.GetAsync(id, ct); + if (machineGroup == null) + { + _log.Info($"Group with id {id} not found"); + return NotFound(); + } - if (machineGroup == null) return NotFound(); return Ok(machineGroup); } @@ -62,12 +75,25 @@ public async Task GetMachineGroup([FromRoute] int id, Cancellatio /// The group to update /// Cancellation Token /// The updated group + [SwaggerOperation("MachineGroupsUpdate")] [HttpPut("{id}")] public async Task PutMachineGroup([FromBody] Group model, CancellationToken ct) { - if (!ModelState.IsValid) return BadRequest(ModelState); + if (!ModelState.IsValid || model.ContainsInvalidUnicode()) + { + _log.Warn("Invalid model state"); + return BadRequest(ModelState); + } + + // if trying to update something that doesn't exist, create it instead + if (await _service.GetAsync(model.Id, ct) == null) + { + var id = await _service.CreateAsync(model, ct); + return CreatedAtAction(nameof(GetMachineGroup), new { id }, model); + } await _service.UpdateAsync(model, ct); + _log.Info($"Group with id {model.Id} updated"); return Ok(model); } @@ -78,14 +104,29 @@ public async Task PutMachineGroup([FromBody] Group model, Cancell /// The new group to add /// Cancellation Token /// The saved group + [ProducesResponseType((int)HttpStatusCode.OK)] + [SwaggerResponse((int)HttpStatusCode.OK)] + [SwaggerOperation("MachineGroupsCreate")] [HttpPost] public async Task PostMachineGroup([FromBody] Group model, CancellationToken ct) { - if (!ModelState.IsValid) return BadRequest(ModelState); + if (!ModelState.IsValid + || model.ContainsInvalidUnicode() + || model.Status == StatusType.Deleted + || model.GroupMachines == null) + { + _log.Warn("Invalid model state"); + return BadRequest(ModelState); + } + // does group exist? + if(await _service.GetAsync(model.Id, ct) != null) + return CreatedAtAction(nameof(GetMachineGroup), new { model.Id }, model); + var id = await _service.CreateAsync(model, ct); + _log.Info($"Group with id {id} created"); - return CreatedAtAction("GetMachineGroup", new {id}, model); + return CreatedAtAction(nameof(GetMachineGroup), new { id }, model); } /// @@ -94,13 +135,19 @@ public async Task PostMachineGroup([FromBody] Group model, Cancel /// The group to delete /// Cancellation Token /// 204 No Content + [SwaggerOperation("MachineGroupsDeleteById")] [HttpDelete("{id}")] [ResponseCache(Duration = 0)] public async Task DeleteMachineGroup([FromRoute] int id, CancellationToken ct) { - if (!ModelState.IsValid) return BadRequest(ModelState); + if (!ModelState.IsValid) + { + _log.Warn("Invalid model state"); + return BadRequest(ModelState); + } await _service.DeleteAsync(id, ct); + _log.Info($"Group with id {id} deleted"); return NoContent(); } @@ -113,6 +160,7 @@ public async Task DeleteMachineGroup([FromRoute] int id, Cancella /// How many records to return /// Cancellation token /// The activity for the group + [SwaggerOperation("MachineGroupsGetActivityById")] [HttpGet("{id}/activity")] public async Task Activity([FromRoute] int id, int skip, int take, CancellationToken ct) { @@ -123,7 +171,8 @@ public async Task Activity([FromRoute] int id, int skip, int take } catch (Exception exc) { - return Json(exc); + _log.Error(exc, $"Error getting activity for group {id}"); + return StatusCode(500, "Internal server error"); } } @@ -133,16 +182,30 @@ public async Task Activity([FromRoute] int id, int skip, int take /// Group Id /// Cancellation Token /// Health records for machines in the group + [SwaggerOperation("MachineGroupsGetHealthById")] [HttpGet("{id}/health")] public async Task GetGroup([FromRoute] int id, CancellationToken ct) { - if (!ModelState.IsValid) return BadRequest(ModelState); - - var list = new List(); + if (!ModelState.IsValid) + { + _log.Warn("Invalid model state"); + return BadRequest(ModelState); + } var group = await _service.GetAsync(id, ct); + if (group == null) + { + _log.Info($"Group with id {id} not found"); + return NotFound(); + } + + var list = new List(); + foreach (var machine in group.GroupMachines) + { + list.AddRange(await _serviceMachine.GetMachineHistory(machine.MachineId, ct)); + } - foreach (var machine in group.GroupMachines) list.AddRange(await _serviceMachine.GetMachineHistory(machine.MachineId, ct)); + _log.Info($"Health records retrieved for group {id}"); return Ok(list.OrderByDescending(o => o.CreatedUtc)); } diff --git a/src/Ghosts.Api/Controllers/Api/MachineUpdatesController.cs b/src/Ghosts.Api/Controllers/Api/MachineUpdatesController.cs new file mode 100755 index 00000000..89f45132 --- /dev/null +++ b/src/Ghosts.Api/Controllers/Api/MachineUpdatesController.cs @@ -0,0 +1,179 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + +using System; +using System.Threading; +using System.Threading.Tasks; +using ghosts.api.Infrastructure.Models; +using ghosts.api.Infrastructure.Services; +using Ghosts.Api.ViewModels; +using Ghosts.Domain; +using Microsoft.AspNetCore.Mvc; +using NLog; +using Swashbuckle.AspNetCore.Annotations; + +namespace ghosts.api.Controllers.Api +{ + /// + /// Enter a machine command, so that the next time a machine checks in, + /// it executes the indicated MachineUpdate.Type command + /// + [Produces("application/json")] + [Route("api/[controller]")] + public class MachineUpdatesController : Controller + { + private static readonly Logger _log = LogManager.GetCurrentClassLogger(); + private readonly IMachineUpdateService _updateService; + + public MachineUpdatesController(IMachineUpdateService updateService) + { + _updateService = updateService; + } + + /// + /// Sends a command for machine to perform, + /// e.g. health or timeline updates, or post back current timeline + /// + /// The saved MachineUpdate record + [ProducesResponseType(200)] + [ProducesResponseType(401)] + [ProducesResponseType(404)] + [SwaggerOperation("MachineUpdatesCreate")] + [HttpPost] + public async Task Create([FromBody] MachineUpdate machineUpdate, CancellationToken ct) + { + if (!ModelState.IsValid) + { + _log.Warn("Invalid model state"); + return BadRequest(ModelState); + } + + try + { + var result = await _updateService.CreateAsync(machineUpdate, ct); + _log.Info($"Machine update created with ID {result.Id}"); + return Ok(result); + } + catch (Exception e) + { + _log.Error(e, "Error creating machine update"); + return StatusCode(500, "Internal server error"); + } + } + + /// + /// Send a new timeline to an entire group of machines + /// + /// Group Id + /// The update to send + /// Cancellation token + /// 204 No content + [SwaggerOperation("MachineUpdateGroupUpdate")] + [HttpPost("group/{groupId}")] + public async Task GroupUpdate([FromRoute] int groupId, [FromBody] MachineUpdateViewModel machineUpdate, CancellationToken ct) + { + if (!ModelState.IsValid) + { + _log.Warn("Invalid model state"); + return BadRequest(ModelState); + } + + try + { + await _updateService.UpdateGroupAsync(groupId, machineUpdate, ct); + _log.Info($"Group update sent to group ID {groupId}"); + return NoContent(); + } + catch (Exception e) + { + _log.Error(e, $"Error updating group ID {groupId}"); + return StatusCode(500, "Internal server error"); + } + } + + /// + /// Gets a machine update by its ID + /// + /// Update ID + /// Cancellation token + /// The machine update + [SwaggerOperation("MachineUpdatesGetById")] + [HttpGet("{updateId}")] + public async Task GetById([FromRoute] int updateId, CancellationToken ct) + { + if (!ModelState.IsValid) + { + _log.Warn("Invalid model state"); + return BadRequest(ModelState); + } + + var update = await _updateService.GetById(updateId, ct); + if (update == null) + { + _log.Info($"Machine update with ID {updateId} not found"); + return NotFound(); + } + + return Ok(update); + } + + /// + /// Gets machine updates by machine ID + /// + /// Machine ID + /// Cancellation token + /// List of machine updates + [SwaggerOperation("MachineUpdatesGetByMachineId")] + [HttpGet("machine/{machineId}")] + public async Task GetByMachineId([FromRoute] Guid machineId, CancellationToken ct) + { + if (!ModelState.IsValid) + { + _log.Warn("Invalid model state"); + return BadRequest(ModelState); + } + + var updates = await _updateService.GetByMachineId(machineId, ct); + return Ok(updates); + } + + /// + /// Gets machine updates by type + /// + /// Update type + /// Cancellation token + /// List of machine updates + [SwaggerOperation("MachineUpdatesGetByType")] + [HttpGet("type/{type}")] + public async Task GetByType([FromRoute] UpdateClientConfig.UpdateType type, CancellationToken ct) + { + if (!ModelState.IsValid) + { + _log.Warn("Invalid model state"); + return BadRequest(ModelState); + } + + var updates = await _updateService.GetByType(type, ct); + return Ok(updates); + } + + /// + /// Gets machine updates by status + /// + /// Update status + /// Cancellation token + /// List of machine updates + [SwaggerOperation("MachineUpdatesGetByStatus")] + [HttpGet("status/{status}")] + public async Task GetByStatus([FromRoute] StatusType status, CancellationToken ct) + { + if (!ModelState.IsValid) + { + _log.Warn("Invalid model state"); + return BadRequest(ModelState); + } + + var updates = await _updateService.GetByStatus(status, ct); + return Ok(updates); + } + } +} diff --git a/src/Ghosts.Api/Controllers/MachinesController.cs b/src/Ghosts.Api/Controllers/Api/MachinesController.cs similarity index 85% rename from src/Ghosts.Api/Controllers/MachinesController.cs rename to src/Ghosts.Api/Controllers/Api/MachinesController.cs index 870a7f40..d50d420f 100644 --- a/src/Ghosts.Api/Controllers/MachinesController.cs +++ b/src/Ghosts.Api/Controllers/Api/MachinesController.cs @@ -6,8 +6,10 @@ using ghosts.api.Infrastructure.Models; using ghosts.api.Infrastructure.Services; using Microsoft.AspNetCore.Mvc; +using NLog; +using Swashbuckle.AspNetCore.Annotations; -namespace Ghosts.Api.Controllers +namespace ghosts.api.Controllers.Api { [Produces("application/json")] [Route("api/[controller]")] @@ -15,6 +17,7 @@ namespace Ghosts.Api.Controllers public class MachinesController : Controller { private readonly IMachineService _service; + private static readonly Logger _log = LogManager.GetCurrentClassLogger(); public MachinesController(IMachineService service) { @@ -27,6 +30,7 @@ public MachinesController(IMachineService service) /// Query /// Cancellation Token /// Machine information + [SwaggerOperation("MachinesGetByQuery")] [HttpGet] public async Task GetMachines(string q, CancellationToken ct) { @@ -41,8 +45,8 @@ public async Task GetMachines(string q, CancellationToken ct) /// /// Cancellation Token /// All machine records - [HttpGet] - [Route("list")] + [SwaggerOperation("MachinesGet")] + [HttpGet("list")] public IActionResult GetList(CancellationToken ct) { return Ok(_service.GetList()); @@ -54,6 +58,7 @@ public IActionResult GetList(CancellationToken ct) /// Machine Guid /// Cancellation Token /// Machine record + [SwaggerOperation("MachinesGetById")] [HttpGet("{id}")] public async Task GetMachine([FromRoute] Guid id, CancellationToken ct) { @@ -72,6 +77,7 @@ public async Task GetMachine([FromRoute] Guid id, CancellationTok /// The machine record to update /// Cancellation Token /// The updated machine record + [SwaggerOperation("MachinesUpdate")] [HttpPut("{id}")] public async Task PutMachine([FromBody] Machine machine, CancellationToken ct) { @@ -89,14 +95,15 @@ public async Task PutMachine([FromBody] Machine machine, Cancella /// The machine to create /// Cancellation Token /// + [SwaggerOperation("MachinesCreate")] [HttpPost] public async Task PostMachine([FromBody] Machine machine, CancellationToken ct) { - if (!ModelState.IsValid) return BadRequest(ModelState); + if (!ModelState.IsValid || !machine.IsValid()) return BadRequest(ModelState); var id = await _service.CreateAsync(machine, ct); - return CreatedAtAction("GetMachine", new {id}, machine); + return CreatedAtAction(nameof(GetMachine), new { id }, machine); } /// @@ -105,8 +112,9 @@ public async Task PostMachine([FromBody] Machine machine, Cancell /// The Id of the machine to delete /// Cancellation Token /// 204 No Content - [HttpDelete("{id}")] [ResponseCache(Duration = 0)] + [SwaggerOperation("MachinesDeleteById")] + [HttpDelete("{id}")] public async Task DeleteMachine([FromRoute] Guid id, CancellationToken ct) { if (!ModelState.IsValid || id == Guid.Empty) return BadRequest(ModelState); @@ -123,6 +131,7 @@ public async Task DeleteMachine([FromRoute] Guid id, Cancellation /// How many records to return /// Cancellation Token /// The activity history for the requested machine + [SwaggerOperation("MachinesGetActivityById")] [HttpGet("{id}/activity")] public async Task Activity([FromRoute] Guid id, int skip, int take, CancellationToken ct) { @@ -135,7 +144,9 @@ public async Task Activity([FromRoute] Guid id, int skip, int tak } catch (Exception exc) { - return Json(exc); + // Log the exception and return a 500 status code + _log.Error(exc, $"An error occurred while fetching activity for machine {id}"); + return StatusCode(500, "Internal server error"); } } @@ -145,6 +156,7 @@ public async Task Activity([FromRoute] Guid id, int skip, int tak /// Machine Guid /// Cancellation Token /// Health records for the machine + [SwaggerOperation("MachinesGetHealthById")] [HttpGet("{id}/health")] public async Task Health([FromRoute] Guid id, CancellationToken ct) { @@ -155,4 +167,4 @@ public async Task Health([FromRoute] Guid id, CancellationToken c return Ok(list); } } -} \ No newline at end of file +} diff --git a/src/Ghosts.Api/Areas/Animator/Controllers/Api/NpcsController.cs b/src/Ghosts.Api/Controllers/Api/NpcsController.cs similarity index 74% rename from src/Ghosts.Api/Areas/Animator/Controllers/Api/NpcsController.cs rename to src/Ghosts.Api/Controllers/Api/NpcsController.cs index 86ebb1e0..729ca3ac 100644 --- a/src/Ghosts.Api/Areas/Animator/Controllers/Api/NpcsController.cs +++ b/src/Ghosts.Api/Controllers/Api/NpcsController.cs @@ -13,14 +13,16 @@ using Ghosts.Animator.Extensions; using Ghosts.Animator.Models; using ghosts.api.Areas.Animator.Infrastructure.Models; -using ghosts.api.Areas.Animator.Infrastructure.Services; using Ghosts.Api.Infrastructure.Data; +using Ghosts.Api.Infrastructure.Extensions; +using ghosts.api.Infrastructure.Services; +using Ghosts.Domain.Code; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Swashbuckle.AspNetCore.Annotations; using Swashbuckle.AspNetCore.Filters; -namespace ghosts.api.Areas.Animator.Controllers.Api; +namespace ghosts.api.Controllers.Api; [ApiController] [Produces("application/json")] @@ -40,26 +42,26 @@ public NpcsController(ApplicationDbContext context, INpcService service) /// Returns all generated NPCs in the system (caution, could return a very large amount of data) /// /// IEnumerable<NpcProfile> - [ProducesResponseType(typeof(IEnumerable), (int)HttpStatusCode.OK)] - [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] - [SwaggerOperation("getNPCs")] + [ProducesResponseType(typeof(ActionResult>), (int)HttpStatusCode.OK)] + [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(ActionResult>))] + [SwaggerOperation("NpcsGetAll")] [HttpGet] - public async Task> Get() + public async Task>> NpcsGetAll() { - return await this._service.GetAll(); + return Ok(await this._service.GetAll()); } /// /// Returns name and Id for all NPCs in the system (caution, could return a large amount of data) /// /// IEnumerable<NpcNameId> - [ProducesResponseType(typeof(IEnumerable), (int)HttpStatusCode.OK)] - [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] - [SwaggerOperation("getNPCList")] + [ProducesResponseType(typeof(ActionResult>), (int)HttpStatusCode.OK)] + [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(ActionResult>))] + [SwaggerOperation("NpcsGetList")] [HttpGet("list")] - public async Task> List() + public async Task>> NpcsGetList() { - return await this._service.GetListAsync(); + return Ok(await this._service.GetListAsync()); } /// @@ -67,13 +69,13 @@ public async Task> List() /// /// /// - [ProducesResponseType(typeof(NpcRecord), (int)HttpStatusCode.OK)] - [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(NpcRecord))] - [SwaggerOperation("getNPCById")] + [ProducesResponseType(typeof(ActionResult), (int)HttpStatusCode.OK)] + [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(ActionResult))] + [SwaggerOperation("NpcsGetById")] [HttpGet("{id:guid}")] - public async Task GetById(Guid id) + public async Task> NpcsGetById(Guid id) { - return await this._service.GetById(id); + return Ok(await this._service.GetById(id)); } /// @@ -83,9 +85,9 @@ public async Task GetById(Guid id) /// [ProducesResponseType((int)HttpStatusCode.OK)] [SwaggerResponse((int)HttpStatusCode.OK)] - [SwaggerOperation("deleteNPCById")] + [SwaggerOperation("NpcsDeleteById")] [HttpDelete("{id:guid}")] - public async Task DeleteById(Guid id) + public async Task NpcsDeleteById(Guid id) { await this._service.DeleteById(id); } @@ -97,47 +99,28 @@ public async Task DeleteById(Guid id) /// [ProducesResponseType(typeof(IActionResult), (int)HttpStatusCode.OK)] [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(IActionResult))] - [SwaggerOperation("getNpcAvatarById")] + [SwaggerOperation("NpcsGetAvatarById")] [HttpGet("{id:guid}/photo")] - public async Task GetPhotoById(Guid id) + public async Task NpcsGetAvatarById(Guid id) { - //get npc and find image - var npc = await this._service.GetById(id); + // Get NPC and find image + var npc = await _service.GetById(id); if (npc == null) return NotFound(); - //load image as stream - var stream = new FileStream(npc.NpcProfile.PhotoLink, FileMode.Open); - return File(stream, "image/jpg", $"{npc.NpcProfile.Name.ToString()!.Replace(" ", "_")}.jpg"); - } - /// - /// Create one NPC (handy for syncing up from ghosts core api) - /// - /// NPC Profile - [ProducesResponseType(typeof(NpcRecord), (int)HttpStatusCode.OK)] - [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(NpcRecord))] - [SwaggerOperation("createNpc")] - [HttpPost] - public async Task Create(NpcProfile npcProfile, bool generate) - { - NpcRecord npc; - if (generate) - { - npc = NpcRecord.TransformToNpc(Npc.Generate(MilitaryUnits.GetServiceBranch())); - npc.NpcProfile.Name = npcProfile.Name; - npc.NpcProfile.Email = npcProfile.Email; - } - else + // Determine the image path + var imagePath = string.IsNullOrEmpty(npc.NpcProfile.PhotoLink) + ? ApplicationDetails.ConfigurationFiles.DefaultNpcImage + : npc.NpcProfile.PhotoLink; + + // Check if the image file exists + if (!System.IO.File.Exists(imagePath)) { - npc = NpcRecord.TransformToNpc(npcProfile); + imagePath = ApplicationDetails.ConfigurationFiles.DefaultNpcImage; } - npc.NpcProfile.Id = Guid.NewGuid(); - npc.NpcProfile.Created = DateTime.UtcNow; - npc.Id = npc.NpcProfile.Id; - - this._context.Npcs.Add(npc); - await this._context.SaveChangesAsync(); - return npc; + // Load image as stream and return as file result + var stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read); + return File(stream, "image/jpg", $"{npc.NpcProfile.Name.ToString()!.Replace(" ", "_")}.jpg"); } /// @@ -148,8 +131,14 @@ public async Task Create(NpcProfile npcProfile, bool generate) /// [HttpPost("npc/{npcId:guid}")] [Obsolete("Obsolete")] - public async Task GetNpcReduced(Guid npcId, [FromBody] string[] fieldsToReturn) + [SwaggerOperation("NpcsGetReducedFields")] + public async Task NpcsGetReducedFields(Guid npcId, [FromBody] string[] fieldsToReturn) { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + var npc = await this._service.GetById(npcId); if (npc == null) return null; return new NPCReduced(fieldsToReturn, npc).PropertySelection; @@ -163,9 +152,9 @@ public async Task GetNpcReduced(Guid npcId, [FromBody] string[] fieldsTo /// [ProducesResponseType(typeof(IEnumerable), (int)HttpStatusCode.OK)] [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] - [SwaggerOperation("getEnclave")] + [SwaggerOperation("NpcsEnclaveGet")] [HttpGet("{campaign}/{enclave}")] - public async Task> GetEnclave(string campaign, string enclave) + public async Task> NpcsEnclaveGet(string campaign, string enclave) { return await _service.GetEnclave(campaign, enclave); } @@ -178,12 +167,13 @@ public async Task> GetEnclave(string campaign, string enc /// [ProducesResponseType(typeof(IActionResult), (int)HttpStatusCode.OK)] [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(IActionResult))] - [SwaggerOperation("getEnclaveCsv")] + [SwaggerOperation("NpcsEnclaveGetCsv")] [HttpGet("{campaign}/{enclave}/csv")] - public async Task GetAsCsv(string campaign, string enclave) + [Obsolete("Obsolete")] + public async Task NpcsEnclaveGetCsv(string campaign, string enclave) { var engine = new FileHelperEngine(); - var list = await GetEnclave(campaign, enclave); + var list = await NpcsEnclaveGet(campaign, enclave); var filteredList = list.Select(n => new NPCToCsv { Id = n.Id, Email = n.NpcProfile.Email }).ToList(); @@ -204,11 +194,11 @@ public async Task GetAsCsv(string campaign, string enclave) /// [ProducesResponseType((int)HttpStatusCode.OK)] [SwaggerResponse((int)HttpStatusCode.OK)] - [SwaggerOperation("deleteEnclave")] + [SwaggerOperation("NpcsEnclaveDelete")] [HttpDelete("{campaign}/{enclave}")] - public async Task DeleteEnclave(string campaign, string enclave) + public async Task NpcsEnclaveDelete(string campaign, string enclave) { - var list = await GetEnclave(campaign, enclave); + var list = await NpcsEnclaveGet(campaign, enclave); this._context.Npcs.RemoveRange(list); await this._context.SaveChangesAsync(); } @@ -222,9 +212,10 @@ public async Task DeleteEnclave(string campaign, string enclave) /// [HttpPost("{campaign}/{enclave}/custom")] [Obsolete("Obsolete")] - public async Task GetReducedNpcs(string campaign, string enclave, [FromBody] string[] fieldsToReturn) + [SwaggerOperation("NpcsEnclaveReducedFields")] + public async Task NpcsEnclaveReducedFields(string campaign, string enclave, [FromBody] string[] fieldsToReturn) { - var npcList = await GetEnclave(campaign, enclave); + var npcList = await NpcsEnclaveGet(campaign, enclave); var npcDetails = new Dictionary>(); foreach (var npc in npcList) @@ -253,9 +244,9 @@ public async Task GetReducedNpcs(string campaign, string enclave, /// [ProducesResponseType(typeof(IEnumerable), (int)HttpStatusCode.OK)] [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] - [SwaggerOperation("getTeam")] + [SwaggerOperation("NpcsTeamGet")] [HttpGet("{campaign}/{enclave}/{team}")] - public async Task> GetTeam(string campaign, string enclave, string team) + public async Task> NpcsTeamGet(string campaign, string enclave, string team) { return await this._service.GetTeam(campaign, enclave, team); } @@ -269,12 +260,13 @@ public async Task> GetTeam(string campaign, string enclav /// [ProducesResponseType(typeof(IActionResult), (int)HttpStatusCode.OK)] [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(IActionResult))] - [SwaggerOperation("getTeamCsv")] + [SwaggerOperation("NpcsTeamGetCsv")] + [Obsolete("Obsolete")] [HttpGet("{campaign}/{enclave}/{team}/csv")] - public async Task GetAsCsv(string campaign, string enclave, string team) + public async Task NpcsTeamGetCsv(string campaign, string enclave, string team) { var engine = new FileHelperEngine(); - var list = await this.GetTeam(team, enclave, campaign); + var list = await this.NpcsTeamGet(team, enclave, campaign); var filteredList = list.Select(n => new NPCToCsv { Id = n.Id, Email = n.NpcProfile.Email }).ToList(); @@ -293,13 +285,21 @@ public async Task GetAsCsv(string campaign, string enclave, strin /// /// [ProducesResponseType(typeof(IActionResult), (int)HttpStatusCode.OK)] + [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(IActionResult))] - [SwaggerOperation("getBuildTfVars")] + [SwaggerResponse((int)HttpStatusCode.BadRequest, Type = typeof(string))] + [Obsolete("Obsolete")] + [SwaggerOperation("NpcsTfVarsGet")] [HttpPost("tfvars")] - public async Task GetTeamAsTfVars(TfVarsConfiguration configuration) + public async Task NpcsTfVarsGet(TfVarsConfiguration configuration) { + if (!ModelState.IsValid || configuration == null || !configuration.IsValid()) + { + return BadRequest(ModelState); + } + var s = new StringBuilder("users = {").Append(Environment.NewLine); - var list = await this.GetTeam(configuration.Campaign, configuration.Enclave, configuration.Team); + var list = await this.NpcsTeamGet(configuration.Campaign, configuration.Enclave, configuration.Team); var pool = configuration.GetIpPool(); foreach (var item in pool) @@ -360,15 +360,25 @@ public async Task GetTeamAsTfVars(TfVarsConfiguration configurati [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [SwaggerRequestExample(typeof(InsiderThreatGenerationConfiguration), typeof(InsiderThreatGenerationConfigurationExample))] - [SwaggerOperation("createInsiderThreatBuild")] + [SwaggerOperation("NpcsInsiderThreatCreate")] [HttpPost("insiderThreat")] - public async Task> Create(InsiderThreatGenerationConfiguration config, CancellationToken ct) + [Obsolete("Obsolete")] + [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] + [SwaggerResponse((int)HttpStatusCode.BadRequest, Type = typeof(string))] + public async Task>> NpcsInsiderThreatCreate(InsiderThreatGenerationConfiguration config, CancellationToken ct) { + if (!ModelState.IsValid || config?.Enclaves == null) + { + return BadRequest(ModelState); + } + var createdNpcs = new List(); foreach (var enclave in config.Enclaves) { + if (enclave.Teams == null) continue; foreach (var team in enclave.Teams) { + if (team.Npcs == null) continue; for (var i = 0; i < team.Npcs.Number; i++) { var branch = team.Npcs.Configuration.Branch ?? MilitaryUnits.GetServiceBranch(); @@ -413,9 +423,10 @@ public async Task> Create(InsiderThreatGenerationConfigur /// [ProducesResponseType(typeof(IActionResult), (int)HttpStatusCode.OK)] [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(IActionResult))] - [SwaggerOperation("getInsiderThreatCsv")] + [SwaggerOperation("NpcsInsiderThreatGetCsv")] [HttpGet("insiderThreat/csv")] - public async Task GetAsCsv() + [Obsolete("Obsolete")] + public async Task NpcsInsiderThreatGetCsv() { var engine = new FileHelperEngine(); engine.HeaderText = engine.GetFileHeader(); diff --git a/src/Ghosts.Api/Controllers/Api/NpcsGenerateController.cs b/src/Ghosts.Api/Controllers/Api/NpcsGenerateController.cs new file mode 100644 index 00000000..aa0b035e --- /dev/null +++ b/src/Ghosts.Api/Controllers/Api/NpcsGenerateController.cs @@ -0,0 +1,90 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + +using System.Collections.Generic; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using ghosts.api.Areas.Animator.Infrastructure.Models; +using ghosts.api.Infrastructure.Services; +using Microsoft.AspNetCore.Mvc; +using NLog; +using Swashbuckle.AspNetCore.Annotations; + +namespace ghosts.api.Controllers.Api; + +/// +/// Build entire team of NPCs for a campaign and enclave +/// +[ApiController] +[Produces("application/json")] +[Route("api/[controller]")] +public class NpcsGenerateController : ControllerBase +{ + private static readonly Logger _log = LogManager.GetCurrentClassLogger(); + private readonly INpcService _service; + + public NpcsGenerateController(INpcService service) + { + this._service = service; + } + + /// + /// Returns all NPCs at the specified level - Campaign, Enclave, or Team + /// + /// campaign, enclave, team + /// + [ProducesResponseType(typeof(ActionResult>), (int)HttpStatusCode.OK)] + [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(ActionResult>))] + [SwaggerOperation("NpcsGenerateGetByKey")] + [HttpGet] + public async Task>> GetKeys(string key) + { + return Ok(await this._service.GetKeys(key)); + } + + /// + /// Create NPCs belonging to a campaign, enclave and team based on configuration + /// + /// + /// + /// + [ProducesResponseType(typeof(ActionResult>), (int)HttpStatusCode.OK)] + [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(ActionResult>))] + [SwaggerOperation("NpcsGenerateCreate")] + [HttpPost] + public async Task>> Create(GenerationConfiguration config, CancellationToken ct) + { + if (config == null || config.Enclaves == null) + { + return BadRequest(ModelState); + } + + return Ok(await this._service.Create(config, ct)); + } + + /// + /// Generate random NPC by random service branch + /// + /// NPC Profile + [ProducesResponseType(typeof(ActionResult), (int)HttpStatusCode.OK)] + [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(ActionResult))] + [SwaggerOperation("NpcsGenerateCreateOne")] + [HttpPost("one")] + public async Task> CreateOne() + { + return await this._service.CreateOne(); + } + + /// + /// Ensures an NPC is created for each and every machine currentusername that exists + /// + /// NPC Profile + [ProducesResponseType((int)HttpStatusCode.OK)] + [SwaggerResponse((int)HttpStatusCode.OK)] + [SwaggerOperation("NpcsGenerateSyncWithMachineUsernames")] + [HttpPost("syncWithMachineUsernames")] + public async Task SyncWithMachineUsernames() + { + await this._service.SyncWithMachineUsernames(); + } +} \ No newline at end of file diff --git a/src/Ghosts.Api/Controllers/SurveysController.cs b/src/Ghosts.Api/Controllers/Api/SurveysController.cs similarity index 81% rename from src/Ghosts.Api/Controllers/SurveysController.cs rename to src/Ghosts.Api/Controllers/Api/SurveysController.cs index 46d70657..c134f419 100644 --- a/src/Ghosts.Api/Controllers/SurveysController.cs +++ b/src/Ghosts.Api/Controllers/Api/SurveysController.cs @@ -7,9 +7,12 @@ using ghosts.api.Infrastructure.Services; using Ghosts.Domain.Messages.MesssagesForServer; using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; -namespace ghosts.api.Controllers +namespace ghosts.api.Controllers.Api { + [Produces("application/json")] + [Route("api/[controller]")] public class SurveysController : Controller { private readonly ISurveyService _surveyService; @@ -20,6 +23,7 @@ public SurveysController(ISurveyService surveyService) } [ProducesResponseType(typeof(Survey), 200)] + [SwaggerOperation("SurveysGetLatestByMachineId")] [HttpGet("surveys/{machineId}")] public async Task Survey([FromRoute] Guid machineId, CancellationToken ct) { @@ -27,6 +31,7 @@ public async Task Survey([FromRoute] Guid machineId, Cancellation } [ProducesResponseType(typeof(IEnumerable), 200)] + [SwaggerOperation("SurveysGetAllByMachineId")] [HttpGet("surveys/{machineId}/all")] public async Task SurveyAll([FromRoute] Guid machineId, CancellationToken ct) { diff --git a/src/Ghosts.Api/Controllers/TimelinesController.cs b/src/Ghosts.Api/Controllers/Api/TimelinesController.cs similarity index 70% rename from src/Ghosts.Api/Controllers/TimelinesController.cs rename to src/Ghosts.Api/Controllers/Api/TimelinesController.cs index bd4c11f9..abbde858 100644 --- a/src/Ghosts.Api/Controllers/TimelinesController.cs +++ b/src/Ghosts.Api/Controllers/Api/TimelinesController.cs @@ -9,11 +9,13 @@ using Microsoft.AspNetCore.Mvc; using Swashbuckle.AspNetCore.Annotations; -namespace ghosts.api.Controllers +namespace ghosts.api.Controllers.Api { /// /// Get or update a machine timeline via the API /// + [Produces("application/json")] + [Route("api/[controller]")] public class TimelinesController : Controller { private readonly ITimelineService _timelineService; @@ -33,15 +35,9 @@ public TimelinesController(ITimelineService timelineService, IMachineTimelinesSe /// Cancellation token /// MachineTimelines [ProducesResponseType(typeof(MachineTimeline), 200)] + [SwaggerOperation("TimelinesGetByMachineId")] [HttpGet("timelines/{machineId}")] - public async Task Timeline([FromRoute] Guid machineId, CancellationToken ct) - { - return Ok(await _machineTimelinesService.GetByMachineIdAsync(machineId, ct)); - } - - [ProducesResponseType(typeof(MachineTimeline), 200)] - [HttpGet("timelines/updates")] - public async Task TimelineUpdates([FromRoute] Guid machineId, CancellationToken ct) + public async Task TimelinesGetByMachineId([FromRoute] Guid machineId, CancellationToken ct) { return Ok(await _machineTimelinesService.GetByMachineIdAsync(machineId, ct)); } @@ -55,8 +51,9 @@ public async Task TimelineUpdates([FromRoute] Guid machineId, Can /// Cancellation token /// MachineTimeline [ProducesResponseType(typeof(MachineTimeline), 200)] + [SwaggerOperation("TimelinesGetByMachineIdAndTimelineId")] [HttpGet("timelines/{machineId}/{timelineId}")] - public async Task TimelineById([FromRoute] Guid machineId, [FromRoute] Guid timelineId, CancellationToken ct) + public async Task TimelinesGetByMachineIdAndTimelineId([FromRoute] Guid machineId, [FromRoute] Guid timelineId, CancellationToken ct) { return Ok(await _machineTimelinesService.GetByMachineIdAndTimelineIdAsync(machineId, timelineId, ct)); } @@ -68,17 +65,17 @@ public async Task TimelineById([FromRoute] Guid machineId, [FromR /// Cancellation token /// 204 No content [HttpPost("timelines")] - // [ProducesResponseType(typeof(Task), (int) HttpStatusCode.NoContent)] Swagger hates this https://stackoverflow.com/questions/35605427/swagger-ui-freezes-after-api-fetch-and-browser-crashes - [SwaggerOperation(OperationId = "createTimeline")] - public async Task Timeline([FromBody] MachineUpdateViewModel machineUpdate, CancellationToken ct) + // [ProducesResponseType(typeof(IActionResult), (int) HttpStatusCode.NoContent)] Swagger hates this https://stackoverflow.com/questions/35605427/swagger-ui-freezes-after-api-fetch-and-browser-crashes + [SwaggerOperation("TimelinesCreate")] + public async Task TimelinesCreate([FromBody] MachineUpdateViewModel machineUpdate, CancellationToken ct) { await _timelineService.UpdateAsync(machineUpdate, ct); return NoContent(); } [HttpPost("timelines/{machineId}/{timelineId}/stop")] - [SwaggerOperation(OperationId = "stopTimeline")] - public async Task Timeline([FromRoute] Guid machineId, [FromRoute] Guid timelineId, CancellationToken ct) + [SwaggerOperation("TimelinesStop")] + public async Task TimelinesStop([FromRoute] Guid machineId, [FromRoute] Guid timelineId, CancellationToken ct) { await _timelineService.StopAsync(machineId, timelineId, ct); return NoContent(); diff --git a/src/Ghosts.Api/Controllers/TrackablesController.cs b/src/Ghosts.Api/Controllers/Api/TrackablesController.cs similarity index 88% rename from src/Ghosts.Api/Controllers/TrackablesController.cs rename to src/Ghosts.Api/Controllers/Api/TrackablesController.cs index 43bfd9ae..98e0eefd 100644 --- a/src/Ghosts.Api/Controllers/TrackablesController.cs +++ b/src/Ghosts.Api/Controllers/Api/TrackablesController.cs @@ -5,8 +5,9 @@ using System.Threading.Tasks; using ghosts.api.Infrastructure.Services; using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; -namespace ghosts.api.Controllers +namespace ghosts.api.Controllers.Api { [Produces("application/json")] [Route("api/[controller]")] @@ -25,6 +26,7 @@ public TrackablesController(ITrackableService service) /// /// Cancellation Token /// List of Trackables + [SwaggerOperation("TrackablesGetAll")] [HttpGet] public async Task GetTrackables(CancellationToken ct) { @@ -33,6 +35,7 @@ public async Task GetTrackables(CancellationToken ct) return Ok(list); } + [SwaggerOperation("TrackablesGetHistoryById")] [HttpGet("{id}")] public async Task GetTrackableHistory([FromRoute] Guid id, CancellationToken ct) { diff --git a/src/Ghosts.Api/Controllers/WebhooksController.cs b/src/Ghosts.Api/Controllers/Api/WebhooksController.cs similarity index 78% rename from src/Ghosts.Api/Controllers/WebhooksController.cs rename to src/Ghosts.Api/Controllers/Api/WebhooksController.cs index d9b96982..cb4e44d1 100755 --- a/src/Ghosts.Api/Controllers/WebhooksController.cs +++ b/src/Ghosts.Api/Controllers/Api/WebhooksController.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading; using System.Threading.Tasks; using Ghosts.Api.Infrastructure.Data; using ghosts.api.Infrastructure.Models; @@ -11,11 +10,12 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json.Linq; +using Swashbuckle.AspNetCore.Annotations; -namespace ghosts.api.Controllers +namespace ghosts.api.Controllers.Api { [Produces("application/json")] - [Route("api/webhooks")] + [Route("api/[controller]")] public class WebhooksController : Controller { private readonly ApplicationDbContext _context; @@ -31,6 +31,7 @@ public WebhooksController(ApplicationDbContext context, IBackgroundQueue service /// Gets all of the webhooks currently active on the system /// /// A list of all webhooks + [SwaggerOperation("WebhooksGetAll")] [HttpGet] public IEnumerable GetWebhooks() { @@ -42,6 +43,7 @@ public IEnumerable GetWebhooks() /// /// The webhook to retrieve /// The webhook + [SwaggerOperation("WebhooksGetById")] [HttpGet("{id}")] public async Task GetWebhook([FromRoute] Guid id) { @@ -60,6 +62,7 @@ public async Task GetWebhook([FromRoute] Guid id) /// The specific webhook to update /// The update to make /// The updated webhook + [SwaggerOperation("WebhooksUpdate")] [HttpPut("{id}")] public async Task PutWebhook([FromRoute] Guid id, [FromBody] Webhook webhook) { @@ -88,6 +91,7 @@ public async Task PutWebhook([FromRoute] Guid id, [FromBody] Webh /// /// The webhook to create /// The saved webhook + [SwaggerOperation("WebhooksCreate")] [HttpPost] public async Task PostWebhook([FromBody] Webhook webhook) { @@ -105,6 +109,7 @@ public async Task PostWebhook([FromBody] Webhook webhook) /// /// The Id of the webhook to delete /// 204 No Content + [SwaggerOperation("WebhooksDete")] [HttpDelete("{id}")] public async Task DeleteWebhook([FromRoute] Guid id) { @@ -124,6 +129,7 @@ public async Task DeleteWebhook([FromRoute] Guid id) /// /// The Id to test /// 204 No Content + [SwaggerOperation("WebhooksTest")] [HttpGet("{id}/test")] public async Task Test([FromRoute] Guid id) { @@ -145,23 +151,33 @@ public async Task Test([FromRoute] Guid id) /// The Id of the webhook /// The timeline item to hook /// 204 No Content + [SwaggerOperation("WebhooksTestById")] [HttpGet("{webhookid}/test/{historytimelineid}")] public async Task TestByID([FromRoute] Guid webhookid, int historytimelineid) { - var timeline = await _context.HistoryTimeline.FirstOrDefaultAsync(o => o.Id == historytimelineid); - - _service.Enqueue( - new QueueEntry - { - Type = QueueEntry.Types.Notification, - Payload = - new NotificationQueueEntry - { - Type = NotificationQueueEntry.NotificationType.Timeline, - Payload = (JObject) JToken.FromObject(timeline) - } - }); - + try + { + var timeline = await _context.HistoryTimeline.FirstOrDefaultAsync(o => o.Id == historytimelineid); + + _service.Enqueue( + new QueueEntry + { + Type = QueueEntry.Types.Notification, + Payload = + new NotificationQueueEntry + { + Type = NotificationQueueEntry.NotificationType.Timeline, + Payload = (JObject)JToken.FromObject(timeline) + } + }); + + + } + catch (Exception e) + { + Console.WriteLine(e.Message); + //todo log this + } return NoContent(); } diff --git a/src/Ghosts.Api/Controllers/HomeController.cs b/src/Ghosts.Api/Controllers/HomeController.cs index ea5afaf0..dd1ac540 100755 --- a/src/Ghosts.Api/Controllers/HomeController.cs +++ b/src/Ghosts.Api/Controllers/HomeController.cs @@ -6,6 +6,7 @@ using Ghosts.Domain.Code; using Microsoft.AspNetCore.Mvc; using NLog; +using Swashbuckle.AspNetCore.Annotations; namespace Ghosts.Api.Controllers { @@ -34,29 +35,32 @@ public IActionResult Index() /// Basic check information including version number, /// and a simple database connection counting machines and groups /// - [HttpGet("test")] [Produces("application/json")] [ResponseCache(Duration = 60)] + [SwaggerOperation("HomeTestApi")] + [HttpGet("test")] public IActionResult Test() { - var s = new Status(); - s.Version = ApplicationDetails.Version; - s.VersionFile = ApplicationDetails.VersionFile; - s.Created = DateTime.UtcNow; + var status = new Status + { + Version = ApplicationDetails.Version, + VersionFile = ApplicationDetails.VersionFile, + Created = DateTime.UtcNow + }; try { - s.Machines = _context.Machines.Count(); - s.Groups = _context.Groups.Count(); - s.Npcs = _context.Npcs.Count(); + status.Machines = _context.Machines.Count(); + status.Groups = _context.Groups.Count(); + status.Npcs = _context.Npcs.Count(); } catch (Exception e) { - _log.Error(e); - throw; + _log.Error(e, "An error occurred while counting database entities."); + return StatusCode(500, "Internal server error"); } - return Json(s); + return Json(status); } public class Status @@ -69,4 +73,4 @@ public class Status public DateTime Created { get; set; } } } -} \ No newline at end of file +} diff --git a/src/Ghosts.Api/Controllers/MachineUpdatesController.cs b/src/Ghosts.Api/Controllers/MachineUpdatesController.cs deleted file mode 100755 index 8960eef8..00000000 --- a/src/Ghosts.Api/Controllers/MachineUpdatesController.cs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using ghosts.api.Infrastructure.Models; -using ghosts.api.Infrastructure.Services; -using Ghosts.Api.ViewModels; -using Ghosts.Domain; -using Microsoft.AspNetCore.Mvc; -using NLog; - -namespace Ghosts.Api.Controllers -{ - /// - /// Enter a machine command, so that the next time a machine checks in, - /// it executes the indicated MachineUpdate.Type command - /// - [Produces("application/json")] - [Route("api/[controller]")] - public class MachineUpdatesController : Controller - { - private static readonly Logger _log = LogManager.GetCurrentClassLogger(); - private readonly IBackgroundQueue _queue; - private readonly IMachineUpdateService _updateService; - - public MachineUpdatesController(IMachineUpdateService updateService, IBackgroundQueue queue) - { - _updateService = updateService; - _queue = queue; - } - - /// - /// Sends a command for machine to perform, - /// e.g. health or timeline updates, or post back current timeline - /// - /// The saved MachineUpdate record - [HttpPost] - [ProducesResponseType(200)] - [ProducesResponseType(401)] - [ProducesResponseType(404)] - public async Task Create([FromBody] MachineUpdate machineUpdate, CancellationToken ct) - { - var o = await _updateService.CreateAsync(machineUpdate, ct); - return Ok(o); - } - - /// - /// Send a new timeline to an entire group of machines - /// - /// Group Id - /// The update to send - /// Cancellation token - /// 204 No content - [HttpPost("group/{groupId}")] - public async Task GroupUpdate([FromRoute] int groupId, [FromBody] MachineUpdateViewModel machineUpdate, CancellationToken ct) - { - await this._updateService.UpdateGroupAsync(groupId, machineUpdate, ct); - return NoContent(); - } - - [HttpGet("{updateId}")] - public async Task GetById([FromRoute] int updateId, CancellationToken ct) - { - return await this._updateService.GetById(updateId, ct); - } - - [HttpGet("machine/{machineId}")] - public async Task> GetByMachineId([FromRoute] Guid machineId, CancellationToken ct) - { - return await this._updateService.GetByMachineId(machineId, ct); - } - - [HttpGet("type/{type}")] - public async Task> GetByType([FromRoute] UpdateClientConfig.UpdateType type, CancellationToken ct) - { - return await this._updateService.GetByType(type, ct); - } - - [HttpGet("status/{status}")] - public async Task> GetByStatus([FromRoute] StatusType status, CancellationToken ct) - { - return await this._updateService.GetByStatus(status, ct); - } - } -} \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Controllers/ViewActivitiesController.cs b/src/Ghosts.Api/Controllers/ViewActivitiesController.cs similarity index 83% rename from src/Ghosts.Api/Areas/Animator/Controllers/ViewActivitiesController.cs rename to src/Ghosts.Api/Controllers/ViewActivitiesController.cs index 5076dee5..2a63957f 100644 --- a/src/Ghosts.Api/Areas/Animator/Controllers/ViewActivitiesController.cs +++ b/src/Ghosts.Api/Controllers/ViewActivitiesController.cs @@ -1,15 +1,13 @@ using System; using System.Linq; -using ghosts.api.Areas.Animator.Infrastructure.Models; using Ghosts.Api.Infrastructure.Data; using Microsoft.AspNetCore.Mvc; -namespace ghosts.api.Areas.Animator.Controllers; +namespace ghosts.api.Controllers; [Controller] [Produces("application/json")] -[Area("Animator")] -[Route("animator/view-activities")] +[Route("view-activities")] [ApiExplorerSettings(IgnoreApi = true)] public class ViewActivitiesController : Controller { diff --git a/src/Ghosts.Api/Areas/Animator/Controllers/ViewRelationshipsController.cs b/src/Ghosts.Api/Controllers/ViewRelationshipsController.cs similarity index 94% rename from src/Ghosts.Api/Areas/Animator/Controllers/ViewRelationshipsController.cs rename to src/Ghosts.Api/Controllers/ViewRelationshipsController.cs index 99cb6f64..9efb3cdd 100644 --- a/src/Ghosts.Api/Areas/Animator/Controllers/ViewRelationshipsController.cs +++ b/src/Ghosts.Api/Controllers/ViewRelationshipsController.cs @@ -6,12 +6,10 @@ using ghosts.api.Areas.Animator.Infrastructure.Models; using Ghosts.Api.Infrastructure.Data; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -namespace ghosts.api.Areas.Animator.Controllers; +namespace ghosts.api.Controllers; -[Area("Animator")] -[Route("animator/view-relationships")] +[Route("view-relationships")] [Controller] [Produces("application/json")] [ApiExplorerSettings(IgnoreApi = true)] diff --git a/src/Ghosts.Api/Areas/Animator/Controllers/ViewSocialController.cs b/src/Ghosts.Api/Controllers/ViewSocialController.cs similarity index 93% rename from src/Ghosts.Api/Areas/Animator/Controllers/ViewSocialController.cs rename to src/Ghosts.Api/Controllers/ViewSocialController.cs index 03ccee99..cc91f594 100644 --- a/src/Ghosts.Api/Areas/Animator/Controllers/ViewSocialController.cs +++ b/src/Ghosts.Api/Controllers/ViewSocialController.cs @@ -2,21 +2,14 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using Ghosts.Api; -using ghosts.api.Areas.Animator.Infrastructure.Animations; -using ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions; -using ghosts.api.Areas.Animator.Infrastructure.Models; using Ghosts.Api.Infrastructure; using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json; using NLog; -namespace ghosts.api.Areas.Animator.Controllers; +namespace ghosts.api.Controllers; -[Area("Animator")] -[Route("animator/view-social")] +[Route("view-social")] [ApiExplorerSettings(IgnoreApi = true)] public class ViewSocialController : Controller { diff --git a/src/Ghosts.Api/Areas/Animator/Hubs/ActivityHub.cs b/src/Ghosts.Api/Hubs/ActivityHub.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Hubs/ActivityHub.cs rename to src/Ghosts.Api/Hubs/ActivityHub.cs diff --git a/src/Ghosts.Api/Areas/Animator/Hubs/ConnectionMapping.cs b/src/Ghosts.Api/Hubs/ConnectionMapping.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Hubs/ConnectionMapping.cs rename to src/Ghosts.Api/Hubs/ConnectionMapping.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs similarity index 95% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs rename to src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs index 0d3c537d..7e2ba51f 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Net; using System.Net.Http; @@ -9,13 +10,16 @@ using System.Text; using System.Text.Json; using System.Threading.Tasks; +using Ghosts.Animator; +using ghosts.api.Areas.Animator.Hubs; using ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions.Chat.Mattermost; using ghosts.api.Areas.Animator.Infrastructure.ContentServices; -using ghosts.api.Areas.Animator.Infrastructure.ContentServices.Ollama; using ghosts.api.Areas.Animator.Infrastructure.Extensions; using ghosts.api.Areas.Animator.Infrastructure.Models; +using Ghosts.Api.Infrastructure.Data; using Ghosts.Api.Infrastructure.Extensions; using Ghosts.Domain.Code.Helpers; +using Microsoft.AspNetCore.SignalR; using NLog; namespace ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions.Chat; @@ -29,13 +33,18 @@ public class ChatClient private string _token; private string UserId { get; set; } private IFormatterService _formatterService; + + private readonly ApplicationDbContext _context; + private IHubContext _activityHubContext; - public ChatClient(ChatJobConfiguration config, IFormatterService formatterService) + public ChatClient(ChatJobConfiguration config, IFormatterService formatterService, IHubContext activityHubContext, ApplicationDbContext context) { _configuration = config; this._baseUrl = _configuration.Chat.BaseUrl; this._client = new HttpClient(); this._formatterService = formatterService; + this._context = context; + this._activityHubContext = activityHubContext; } private async Task AdminLogin() @@ -428,11 +437,11 @@ await this.CreateUser(new UserCreate }); } - await this.StepEx(random, username, _configuration.Chat.DefaultUserPassword); + await this.StepEx(random, agent.Id, username, _configuration.Chat.DefaultUserPassword); } } - private async Task StepEx(Random random, string username, string password) + private async Task StepEx(Random random, Guid NpcId, string username, string password) { _log.Trace($"Managing {username}..."); @@ -557,6 +566,17 @@ private async Task StepEx(Random random, string username, string password) { var post = await this.CreatePost(randomChannelToPostTo, message); _log.Info($"{prompt}|SENT|{post.Message}"); + + + //post to hub + await this._activityHubContext.Clients.All.SendAsync("show", + 1, + NpcId, + "chat", + message, + DateTime.Now.ToString(CultureInfo.InvariantCulture) + ); + } else { diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/ChatConfiguration.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/ChatConfiguration.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/ChatConfiguration.cs rename to src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/ChatConfiguration.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Channel.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Channel.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Channel.cs rename to src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Channel.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Post.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Post.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Post.cs rename to src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Post.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Team.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Team.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Team.cs rename to src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Team.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/User.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/User.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/User.cs rename to src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/User.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs similarity index 98% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs rename to src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs index 1c7d427c..009ad211 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs @@ -49,7 +49,7 @@ public ChatJob(ApplicationSettings configuration, IServiceScopeFactory scopeFact this._formatterService = new ContentCreationService(_configuration.AnimatorSettings.Animations.Chat.ContentEngine).FormatterService; - this._chatClient = new ChatClient(chatConfiguration, this._formatterService); + this._chatClient = new ChatClient(chatConfiguration, this._formatterService, activityHubContext, this._context); while (!_cancellationToken.IsCancellationRequested) { diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/FullAutonomyJob.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/FullAutonomyJob.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/FullAutonomyJob.cs rename to src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/FullAutonomyJob.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/SocialBeliefJob.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialBeliefJob.cs similarity index 80% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/SocialBeliefJob.cs rename to src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialBeliefJob.cs index 2314f8ab..6fd1736a 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/SocialBeliefJob.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialBeliefJob.cs @@ -29,13 +29,14 @@ public class SocialBeliefJob public static string[] Beliefs = { - "Strong passwords are essential.", "Regular software updates matter.", "Public Wi-Fi is risky.", - "Antivirus software is a must.", - "Encryption protects data.", "Phishing attacks are common.", "Two-factor authentication helps.", - "Social engineering is a threat.", - "IoT devices can be vulnerable.", "Cyberwarfare affects nations.", "Ransomware can cripple businesses.", - "Insider threats are real.", - "Dark web is a breeding ground.", "DDoS attacks disrupt services.", "Hacktivists promote causes." + // "Strong passwords are essential.", "Regular software updates matter.", "Public Wi-Fi is risky.", + // "Antivirus software is a must.", + // "Encryption protects data.", "Phishing attacks are common.", "Two-factor authentication helps.", + // "Social engineering is a threat.", + // "IoT devices can be vulnerable.", "Cyberwarfare affects nations.", "Ransomware can cripple businesses.", + // "Insider threats are real.", + // "Dark web is a breeding ground.", "DDoS attacks disrupt services.", "Hacktivists promote causes." + "I should vote for candidate A", "I should vote for candidate B" }; public SocialBeliefJob(ApplicationSettings configuration, IServiceScopeFactory scopeFactory, Random random, @@ -106,7 +107,10 @@ private void Step(NpcRecord npc) } npc.NpcSocialGraph = graph; - this._context.SaveChanges(); + this._context.Npcs.Update(npc); // Explicitly set the state to Modified + var o = this._context.SaveChanges(); + Console.WriteLine($"{o} rows were affected."); + _log.Trace($"Social graph saved for {npc.NpcProfile.Name}..."); } @@ -148,10 +152,12 @@ private void Step(NpcRecord npc) newBelief.Step, newBelief.To.ToString(), "belief", - $"{graph.Name} has deeper belief in {newBelief.Name}", - DateTime.Now.ToString(CultureInfo.InvariantCulture) - ); + $"{graph.Name} has updated posterior of {Math.Round(newBelief.Posterior, 2)} in {newBelief.Name}", + DateTime.Now.ToString(CultureInfo.InvariantCulture), cancellationToken: _cancellationToken); + + this._context.Npcs.Update(npc); // Explicitly set the state to Modified + var affectedRows = this._context.SaveChanges(); + Console.WriteLine($"{affectedRows} rows were affected."); - this._context.SaveChanges(); } } \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/SocialGraphJob.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialGraphJob.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationDefinitions/SocialGraphJob.cs rename to src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialGraphJob.cs diff --git a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs new file mode 100644 index 00000000..0b8d2349 --- /dev/null +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs @@ -0,0 +1,219 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using Ghosts.Animator.Extensions; +using ghosts.api.Areas.Animator.Hubs; +using ghosts.api.Areas.Animator.Infrastructure.ContentServices; +using ghosts.api.Areas.Animator.Infrastructure.Models; +using Ghosts.Api.Infrastructure; +using Ghosts.Api.Infrastructure.Data; +using ghosts.api.Infrastructure.Models; +using ghosts.api.Infrastructure.Services; +using Ghosts.Domain; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using NLog; +using RestSharp; + +namespace ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions +{ + public class SocialSharingJob + { + private static readonly Logger _log = LogManager.GetCurrentClassLogger(); + private readonly ApplicationSettings _configuration; + private readonly Random _random; + private int _currentStep; + private readonly IHubContext _activityHubContext; + private readonly CancellationToken _cancellationToken; + private readonly ApplicationDbContext _context; + private readonly IMachineUpdateService _updateService; + private readonly IFormatterService _formatterService; + + public SocialSharingJob(ApplicationSettings configuration, IServiceScopeFactory scopeFactory, Random random, + IHubContext activityHubContext, CancellationToken cancellationToken) + { + try + { + this._activityHubContext = activityHubContext; + this._configuration = configuration; + this._random = random; + + using var innerScope = scopeFactory.CreateScope(); + this._context = innerScope.ServiceProvider.GetRequiredService(); + + this._cancellationToken = cancellationToken; + this._updateService = innerScope.ServiceProvider.GetRequiredService(); + + _formatterService = + new ContentCreationService(_configuration.AnimatorSettings.Animations.Chat.ContentEngine).FormatterService; + + if (!_configuration.AnimatorSettings.Animations.SocialSharing.IsInteracting) + { + _log.Trace($"Social sharing is not interacting. Exiting..."); + return; + } + + RunAsync().GetAwaiter().GetResult(); + } + catch (ThreadInterruptedException e) + { + _log.Info("Social sharing thread interrupted!"); + _log.Error(e); + } + catch (Exception e) + { + _log.Error(e); + } + _log.Info("Social sharing job complete. Exiting..."); + } + + private async Task RunAsync() + { + while (!this._cancellationToken.IsCancellationRequested) + { + if (this._currentStep > _configuration.AnimatorSettings.Animations.SocialSharing.MaximumSteps) + { + _log.Trace($"Maximum steps met: {this._currentStep - 1}. Social sharing is exiting..."); + return; + } + + await this.Step(); + await Task.Delay(this._configuration.AnimatorSettings.Animations.SocialSharing.TurnLength, this._cancellationToken); + this._currentStep++; + } + } + + private async Task Step() + { + _log.Trace("Social sharing step proceeding..."); + + //take some random NPCs + var activities = new List(); + var rawAgents = this._context.Npcs.ToList(); + if (!rawAgents.Any()) + { + _log.Warn("No NPCs found. Is this correct?"); + return; + } + _log.Trace($"Found {rawAgents.Count()} raw agents..."); + + var agents = rawAgents.Shuffle(_random).Take(_random.Next(5, 20)).ToList(); + _log.Trace($"Processing {agents.Count()} agents..."); + foreach (var agent in agents) + { + _log.Trace($"Processing agent {agent.NpcProfile.Email}..."); + var tweetText = await this._formatterService.GenerateTweet(agent); + if (string.IsNullOrEmpty(tweetText)) + { + _log.Trace($"Content service generated no payload..."); + return; + } + + activities.Add(new NpcActivity { ActivityType = NpcActivity.ActivityTypes.SocialMediaPost, NpcId = agent.Id, CreatedUtc = DateTime.UtcNow, Detail = tweetText }); + + // the payloads to socializer are a bit randomized + var userFormValue = new[] { "user", "usr", "u", "uid", "user_id", "u_id" }.RandomFromStringArray(); + var messageFormValue = + new[] { "message", "msg", "m", "message_id", "msg_id", "msg_text", "text", "payload" } + .RandomFromStringArray(); + + if (_configuration.AnimatorSettings.Animations.SocialSharing.IsSendingTimelinesDirectToSocializer) + { + var client = new RestClient(_configuration.AnimatorSettings.Animations.SocialSharing.PostUrl); + var request = new RestRequest("/", Method.Post) + { + RequestFormat = DataFormat.Json + }; + request.AddParameter(userFormValue, agent.NpcProfile.Name.ToString()); + request.AddParameter(messageFormValue, tweetText); + + try + { + var response = client.Execute(request); + if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.NoContent) + { + throw (new Exception( + $"Socializer responded with {response.StatusCode} to the request agent: {agent.NpcProfile.Name} text: {tweetText}")); + } + } + catch (Exception e) + { + _log.Error( + $"Could not post timeline command to Socializer {_configuration.AnimatorSettings.Animations.SocialSharing.PostUrl}: {e}"); + } + } + + if (_configuration.AnimatorSettings.Animations.SocialSharing.IsSendingTimelinesToGhostsApi) + { + var payload = new + { + Uri = _configuration.AnimatorSettings.Animations.SocialSharing.PostUrl, + Category = "social", + Method = "POST", + Headers = new Dictionary + { + { "u", agent.NpcProfile.Email } + }, + FormValues = new Dictionary + { + { userFormValue, agent.NpcProfile.Email }, + { messageFormValue, tweetText } + } + }; + + var t = new Timeline(); + t.Id = Guid.NewGuid(); + t.Status = Timeline.TimelineStatus.Run; + var th = new TimelineHandler(); + th.HandlerType = HandlerType.BrowserFirefox; + th.Initial = "about:blank"; + th.UtcTimeOn = new TimeSpan(0, 0, 0); + th.UtcTimeOff = new TimeSpan(23, 59, 59); + th.HandlerArgs = new Dictionary(); + th.HandlerArgs.Add("isheadless", "false"); + th.Loop = false; + var te = new TimelineEvent(); + te.Command = "browse"; + te.CommandArgs = new List(); + te.CommandArgs.Add(JsonConvert.SerializeObject(payload)); + te.DelayAfter = 0; + te.DelayBefore = 0; + th.TimeLineEvents.Add(te); + t.TimeLineHandlers.Add(th); + + var machineUpdate = new MachineUpdate(); + if (agent.MachineId.HasValue) + { + machineUpdate.MachineId = agent.MachineId.Value; + } + + machineUpdate.Update = t; //JsonConvert.SerializeObject(t); + machineUpdate.Username = agent.NpcProfile.Email; + machineUpdate.Status = StatusType.Active; + machineUpdate.Type = UpdateClientConfig.UpdateType.TimelinePartial; + + _ = await _updateService.CreateAsync(machineUpdate, _cancellationToken); + } + + //post to hub + await this._activityHubContext.Clients.All.SendAsync("show", + "1", + agent.Id.ToString(), + "social", + tweetText, + DateTime.Now.ToString(CultureInfo.InvariantCulture), + cancellationToken: _cancellationToken); + } + + await this._context.NpcActivities.AddRangeAsync(activities, _cancellationToken); + await this._context.SaveChangesAsync(this._cancellationToken); + } + } +} diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationsManager.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationsManager.cs similarity index 99% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationsManager.cs rename to src/Ghosts.Api/Infrastructure/Animations/AnimationsManager.cs index ed6d611b..cd021f59 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/Animations/AnimationsManager.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationsManager.cs @@ -291,7 +291,7 @@ private void Run(AnimationConfiguration animationConfiguration) } break; - case "SOCIALBELIEFS": + case "SOCIALBELIEF": var beliefSettings = JsonConvert.DeserializeObject(animationConfiguration .JobConfiguration); settings.AnimatorSettings.Animations.SocialBelief = beliefSettings; diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Bayes.cs b/src/Ghosts.Api/Infrastructure/Bayes.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Bayes.cs rename to src/Ghosts.Api/Infrastructure/Bayes.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/ContentCreationService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/ContentCreationService.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/ContentCreationService.cs rename to src/Ghosts.Api/Infrastructure/ContentServices/ContentCreationService.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/GenericContentHelpers.cs b/src/Ghosts.Api/Infrastructure/ContentServices/GenericContentHelpers.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/GenericContentHelpers.cs rename to src/Ghosts.Api/Infrastructure/ContentServices/GenericContentHelpers.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/IContentService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/IContentService.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/IContentService.cs rename to src/Ghosts.Api/Infrastructure/ContentServices/IContentService.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/IFormatterService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/IFormatterService.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/IFormatterService.cs rename to src/Ghosts.Api/Infrastructure/ContentServices/IFormatterService.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Native/NativeContentFormatterService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/Native/NativeContentFormatterService.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Native/NativeContentFormatterService.cs rename to src/Ghosts.Api/Infrastructure/ContentServices/Native/NativeContentFormatterService.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Ollama/OllamaConnectorService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/Ollama/OllamaConnectorService.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Ollama/OllamaConnectorService.cs rename to src/Ghosts.Api/Infrastructure/ContentServices/Ollama/OllamaConnectorService.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs similarity index 96% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs rename to src/Ghosts.Api/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs index 2a9ab4a2..443be8f3 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs +++ b/src/Ghosts.Api/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs @@ -82,15 +82,13 @@ public async Task GenerateNextAction(NpcRecord npc, string history) var prompt = await File.ReadAllTextAsync(promptPath); var messages = new StringBuilder(); - foreach (var p in prompt.Split(System.Environment.NewLine)) + foreach (var p in prompt.Split(Environment.NewLine)) { - var s = p.Replace("[[flattenedAgent]]", flattenedAgent[..3050]); + var s = p.Replace("[[flattenedAgent]]", flattenedAgent); s = s.Replace("[[history]]", history); messages.Append(s).Append(' '); } - // _log.Trace(messages.ToString()); - return await _connectorService.ExecuteQuery(messages.ToString()); } } \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/OpenAi/OpenAIConnectorService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIConnectorService.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/OpenAi/OpenAIConnectorService.cs rename to src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIConnectorService.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/OpenAi/OpenAIFormatterService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIFormatterService.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/OpenAi/OpenAIFormatterService.cs rename to src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIFormatterService.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/OpenAi/OpenAIHelpers.cs b/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIHelpers.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/OpenAi/OpenAIHelpers.cs rename to src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIHelpers.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Shadows/ShadowsConnectorService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/Shadows/ShadowsConnectorService.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Shadows/ShadowsConnectorService.cs rename to src/Ghosts.Api/Infrastructure/ContentServices/Shadows/ShadowsConnectorService.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Shadows/ShadowsFormatterService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/Shadows/ShadowsFormatterService.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/ContentServices/Shadows/ShadowsFormatterService.cs rename to src/Ghosts.Api/Infrastructure/ContentServices/Shadows/ShadowsFormatterService.cs diff --git a/src/Ghosts.Api/Infrastructure/Data/ApplicationDbContext.cs b/src/Ghosts.Api/Infrastructure/Data/ApplicationDbContext.cs index 69fff684..92489c34 100644 --- a/src/Ghosts.Api/Infrastructure/Data/ApplicationDbContext.cs +++ b/src/Ghosts.Api/Infrastructure/Data/ApplicationDbContext.cs @@ -52,6 +52,9 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) base.OnModelCreating(modelBuilder); // Add your customizations after calling base.OnModelCreating(modelBuilder); + modelBuilder.ApplyConfiguration(new MachineUpdateConfiguration()); + + modelBuilder.Entity().Property(o => o.NpcProfile).HasColumnType("jsonb"); modelBuilder.Entity().Property(o => o.NpcSocialGraph).HasColumnType("jsonb"); diff --git a/src/Ghosts.Api/Infrastructure/Extensions/JsonExtensions.cs b/src/Ghosts.Api/Infrastructure/Extensions/JsonExtensions.cs new file mode 100644 index 00000000..86d90383 --- /dev/null +++ b/src/Ghosts.Api/Infrastructure/Extensions/JsonExtensions.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Ghosts.Api.Infrastructure.Extensions; + +public static class JsonExtensions +{ + public static bool ContainsInvalidUnicode(this T o) + { + var jsonString = JsonConvert.SerializeObject(o); + return jsonString.Contains("\\u0000"); + } +} \ No newline at end of file diff --git a/src/Ghosts.Api/Infrastructure/Extensions/StringExtensions.cs b/src/Ghosts.Api/Infrastructure/Extensions/StringExtensions.cs index db697d77..c06ed376 100644 --- a/src/Ghosts.Api/Infrastructure/Extensions/StringExtensions.cs +++ b/src/Ghosts.Api/Infrastructure/Extensions/StringExtensions.cs @@ -5,6 +5,9 @@ using System.Linq; using System.Text.RegularExpressions; using ghosts.api.Areas.Animator.Infrastructure.Extensions; +using Newtonsoft.Json; +using NPOI.SS.Formula.Functions; +using Match = System.Text.RegularExpressions.Match; namespace Ghosts.Api.Infrastructure.Extensions { @@ -65,6 +68,7 @@ public static string Clean(this string message, IEnumerable list, Random public static string CreateUsernameFromEmail(this string email) { + if (string.IsNullOrEmpty(email)) return string.Empty; return email.Split('@')[0].Replace(".mil", "").Replace(".civ", "").Replace(".ctr", ""); } diff --git a/src/Ghosts.Api/Infrastructure/Filters/CustomDocumentFilter.cs b/src/Ghosts.Api/Infrastructure/Filters/CustomDocumentFilter.cs new file mode 100644 index 00000000..f9df2397 --- /dev/null +++ b/src/Ghosts.Api/Infrastructure/Filters/CustomDocumentFilter.cs @@ -0,0 +1,26 @@ +using System.Linq; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace Ghosts.Api.Infrastructure.Filters; + +public class CustomDocumentFilter : IDocumentFilter +{ + public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) + { + foreach (var path in swaggerDoc.Paths) + { + foreach (var operation in path.Value.Operations) + { + var actionDescriptor = context.ApiDescriptions + .FirstOrDefault(desc => desc.RelativePath == path.Key.Substring(1)) + ?.ActionDescriptor; + + if (actionDescriptor != null && actionDescriptor.RouteValues.TryGetValue("action", out var value)) + { + operation.Value.OperationId = value; + } + } + } + } +} \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/EnclaveReducedCsv.cs b/src/Ghosts.Api/Infrastructure/Models/EnclaveReducedCsv.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Models/EnclaveReducedCsv.cs rename to src/Ghosts.Api/Infrastructure/Models/EnclaveReducedCsv.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/GenerationConfiguration.cs b/src/Ghosts.Api/Infrastructure/Models/GenerationConfiguration.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Models/GenerationConfiguration.cs rename to src/Ghosts.Api/Infrastructure/Models/GenerationConfiguration.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/InsiderThreatGenerationConfiguration.cs b/src/Ghosts.Api/Infrastructure/Models/InsiderThreatGenerationConfiguration.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Models/InsiderThreatGenerationConfiguration.cs rename to src/Ghosts.Api/Infrastructure/Models/InsiderThreatGenerationConfiguration.cs diff --git a/src/Ghosts.Api/Infrastructure/Models/MachineGroup.cs b/src/Ghosts.Api/Infrastructure/Models/MachineGroup.cs index 3c082ead..8effeae2 100644 --- a/src/Ghosts.Api/Infrastructure/Models/MachineGroup.cs +++ b/src/Ghosts.Api/Infrastructure/Models/MachineGroup.cs @@ -15,10 +15,11 @@ public class Group public Group() { GroupMachines = new List(); - Machines = new List(); } - [Key] public int Id { get; set; } + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } [Required] public string Name { get; set; } @@ -26,13 +27,13 @@ public Group() [JsonConverter(typeof(StringEnumConverter))] public StatusType Status { get; set; } - - [NotMapped] public IList Machines { get; set; } } [Table("group_machines")] public class GroupMachine { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } [ForeignKey("GroupId")] public int GroupId { get; set; } diff --git a/src/Ghosts.Api/Infrastructure/Models/MachineUpdate.cs b/src/Ghosts.Api/Infrastructure/Models/MachineUpdate.cs index 5dc0a56f..8f61710e 100644 --- a/src/Ghosts.Api/Infrastructure/Models/MachineUpdate.cs +++ b/src/Ghosts.Api/Infrastructure/Models/MachineUpdate.cs @@ -3,6 +3,8 @@ using System; using System.ComponentModel.DataAnnotations.Schema; using Ghosts.Domain; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -16,17 +18,18 @@ public class MachineUpdate public Guid MachineId { get; set; } public string Username { get; set; } - + [JsonConverter(typeof(StringEnumConverter))] public UpdateClientConfig.UpdateType Type { get; set; } public DateTime ActiveUtc { get; set; } public DateTime CreatedUtc { get; set; } + [JsonConverter(typeof(StringEnumConverter))] public StatusType Status { get; set; } - public string Update { get; set; } - + public Timeline Update { get; set; } + public MachineUpdate() { var now = DateTime.UtcNow; @@ -34,4 +37,17 @@ public MachineUpdate() this.CreatedUtc = now; } } + + public class MachineUpdateConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + // Configure the Update property to be stored as JSON in the database + builder.Property(e => e.Update) + .HasConversion( + v => JsonConvert.SerializeObject(v, Formatting.None), + v => JsonConvert.DeserializeObject(v)) + .HasColumnName("update"); + } + } } \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPC.cs b/src/Ghosts.Api/Infrastructure/Models/NPC.cs similarity index 93% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPC.cs rename to src/Ghosts.Api/Infrastructure/Models/NPC.cs index 6f699e79..2a9e2440 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPC.cs +++ b/src/Ghosts.Api/Infrastructure/Models/NPC.cs @@ -46,11 +46,15 @@ public class NpcRecord public static NpcRecord TransformToNpc(NpcProfile o) { + if (o == null) return new NpcRecord(); + var n = new NpcRecord { - NpcProfile = o + NpcProfile = o, + NpcSocialGraph = new NpcSocialGraph(), + Id = o.Id }; - n.Id = n.NpcProfile.Id; + return n; } diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPCIpAddress.cs b/src/Ghosts.Api/Infrastructure/Models/NPCIpAddress.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPCIpAddress.cs rename to src/Ghosts.Api/Infrastructure/Models/NPCIpAddress.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPCNameId.cs b/src/Ghosts.Api/Infrastructure/Models/NPCNameId.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPCNameId.cs rename to src/Ghosts.Api/Infrastructure/Models/NPCNameId.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPCReduced.cs b/src/Ghosts.Api/Infrastructure/Models/NPCReduced.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPCReduced.cs rename to src/Ghosts.Api/Infrastructure/Models/NPCReduced.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPCToCsv.cs b/src/Ghosts.Api/Infrastructure/Models/NPCToCsv.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NPCToCsv.cs rename to src/Ghosts.Api/Infrastructure/Models/NPCToCsv.cs diff --git a/src/Ghosts.Api/Infrastructure/Models/NPCToInsiderThreatCsv.cs b/src/Ghosts.Api/Infrastructure/Models/NPCToInsiderThreatCsv.cs new file mode 100644 index 00000000..9ee61b82 --- /dev/null +++ b/src/Ghosts.Api/Infrastructure/Models/NPCToInsiderThreatCsv.cs @@ -0,0 +1,525 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using FileHelpers; +using Ghosts.Animator; +using Ghosts.Animator.Extensions; +using Ghosts.Animator.Models.InsiderThreat; + +namespace ghosts.api.Areas.Animator.Infrastructure.Models; + +[DelimitedRecord(",")] +public class NPCToInsiderThreatCsv +{ + [FieldQuoted] public Guid Id { get; set; } + [FieldQuoted] public string Hostname { get; set; } + [FieldQuoted] public string DNS { get; set; } + [FieldQuoted] public string OpenVPNUsername { get; set; } + [FieldQuoted] public string OpenVPNPassword { get; set; } + [FieldQuoted] public string GmailUsername { get; set; } + [FieldQuoted] public string GmailPassword { get; set; } + [FieldQuoted] public string NmailUser { get; set; } + [FieldQuoted] public string NmailPassword { get; set; } + [FieldQuoted] public string IPAddress { get; set; } + [FieldQuoted] public string DomainUser { get; set; } + [FieldQuoted] public string FirstName { get; set; } + [FieldQuoted] public string LastName { get; set; } + [FieldQuoted] public string Password { get; set; } + [FieldQuoted] public string Company { get; set; } + [FieldQuoted] public string StartDate { get; set; } + [FieldQuoted] public string Department { get; set; } + [FieldQuoted] public string Organization { get; set; } + [FieldQuoted] public string JobTitle { get; set; } + [FieldQuoted] public int JobLevel { get; set; } + [FieldQuoted] public string Salary { get; set; } + + [FieldConverter(typeof(EmptyGuidConverter))] + [FieldQuoted] + public Guid Manager { get; set; } + + [FieldQuoted] public string EmailSuffix { get; set; } + [FieldQuoted] public string Email { get; set; } + [FieldQuoted] public string Type { get; set; } + [FieldQuoted] public string Address { get; set; } + [FieldQuoted] public string City { get; set; } + [FieldQuoted] public string Phone { get; set; } + [FieldQuoted] public string State { get; set; } + [FieldQuoted] public string Zip { get; set; } + [FieldQuoted] public string Country { get; set; } + [FieldQuoted] public string EmploymentStatus { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool Disgruntled { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool Demoted { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool MissedRaises { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool TeamLayoffs { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool NotifiedOfTermination { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool AnnouncesTermination { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool AnnouncesResignation { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool Threats { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool MissedPromotion { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool Insubordination { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool Absenteeism { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool HRComplaints { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool ITPolicyViolations { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool IPPolicyViolations { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool DrugAlcoholAbuse { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool CoworkerConflict { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool EAPReferral { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool AccessRevoked { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool UnauthorizedCodingChange { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool UnauthorizedAccessChange { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool FinancialProblems { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool ArrestRecord { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool GamblingHistory { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool ServiceAccountUse { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool RemoteAccess { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool BackdoorAccountUse { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool SolicitedByCompetitor { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool AfterHoursLogin { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool PrivilegeCreep { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool FileExtensionModification { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool FileHeaderModification { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool FileContentModification { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool FileTypeModification { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool SensitiveInformationCopied { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool ScreenShots { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool ZipFile { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool Encryption { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool DocumentMarkingTampering { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool Steganography { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool LogDeletion { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool ConcealmentInformation { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool SaleAttempt { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool Scanner { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool CloudStorage { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool RemovableMedia { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool Print { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool NetworkShare { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool PersonalEmailAccount { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool EmailToConspirator { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool DNSExfiltrationTool { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool FileDeletion { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool RecentHRTicket { get; set; } + + [FieldConverter(typeof(TrueFalseToXConverter))] + [FieldQuoted] + public bool BackgroundCkResult { get; set; } + + [FieldQuoted] public int InterpersonalSkills { get; set; } + [FieldQuoted] public int AdherenceToPolicy { get; set; } + [FieldQuoted] public int EnthusiasmAndAttitude { get; set; } + [FieldQuoted] public int OpenToFeedback { get; set; } + [FieldQuoted] public int GeneralPerformance { get; set; } + [FieldQuoted] public int OverallPerformance { get; set; } + + public static IEnumerable ConvertToCsv(IEnumerable npcs) + { + var finalList = new List(); + foreach (var n in npcs) + { + if (n.NpcProfile == null || n.NpcProfile.Accounts == null || n.NpcProfile.Address == null) continue; + + var events = n.NpcProfile.InsiderThreat.GetAllEvents(); + + var i = AnimatorRandom.Rand.Next(0, 99); + var o = new NPCToInsiderThreatCsv + { + Id = n.Id, + Hostname = $"user{i}", + DNS = $"FIN-USR-{i}" + }; + + foreach (var account in n.NpcProfile.Accounts.Where(x => + x.Url != null && x.Url.ToLower().Contains("openvpn"))) + { + o.OpenVPNUsername = account.Username; + o.OpenVPNPassword = account.Password; + } + + // o.HRMUserID + // o.HRMManagerID + // o.TestCase + // o.ExampleCase + + foreach (var account in + n.NpcProfile.Accounts.Where(x => x.Url != null && x.Url.ToLower().Contains("gmail"))) + { + o.GmailUsername = account.Username; + o.GmailPassword = account.Password; + } + + foreach (var account in + n.NpcProfile.Accounts.Where(x => x.Url != null && x.Url.ToLower().Contains("nmail"))) + { + o.NmailUser = account.Username; + o.NmailPassword = account.Password; + } + + o.IPAddress = n.NpcProfile.Workstation.IPAddress; + + o.DomainUser = n.NpcProfile.Workstation.Username; + o.FirstName = n.NpcProfile.Name.First; + o.LastName = n.NpcProfile.Name.Last; + o.Password = n.NpcProfile.Workstation.Password; + o.Type = "User"; + if (n.NpcProfile.Employment.EmploymentRecords != null && n.NpcProfile.Employment.EmploymentRecords.Any()) + { + var currentEmployer = n.NpcProfile.Employment.EmploymentRecords.LastOrDefault(); + o.EmploymentStatus = "Employed"; + o.Company = currentEmployer?.Company; + o.StartDate = currentEmployer?.StartDate.ToString(CultureInfo.InvariantCulture); + o.Department = currentEmployer?.Department; + o.Organization = currentEmployer?.Organization; + o.JobTitle = currentEmployer?.JobTitle; + o.JobLevel = currentEmployer.Level; + o.Salary = currentEmployer?.Salary.ToString(CultureInfo.InvariantCulture); + o.Manager = currentEmployer.Manager; + if (o.JobLevel > 2) + { + if (AnimatorRandom.Rand.Next(0, 100) > 50) + { + o.Type = "Administrator"; + } + } + } + else + { + o.EmploymentStatus = "Unemployed"; + } + + o.EmailSuffix = n.NpcProfile.Email.After("@"); + o.Email = n.NpcProfile.Email; + + o.Address = n.NpcProfile.Address.FirstOrDefault()?.Address1; + o.City = n.NpcProfile.Address.FirstOrDefault()?.City; + o.Phone = n.NpcProfile.CellPhone; + o.State = n.NpcProfile.Address.FirstOrDefault()?.State; + o.Zip = n.NpcProfile.Address.FirstOrDefault()?.PostalCode; + o.Country = "US"; + var relatedEvents = events as RelatedEvent[] ?? events.ToArray(); + if (!relatedEvents.Any()) continue; + try + { + o.Demoted = relatedEvents.Any(x => + x.Description.Contains("Demoted", StringComparison.CurrentCultureIgnoreCase)); + o.Disgruntled = relatedEvents.Length > 3; + o.MissedRaises = relatedEvents.Any(x => + x.Description.Contains("Missed raise", StringComparison.CurrentCultureIgnoreCase)); + o.TeamLayoffs = relatedEvents.Any(x => + x.Description.Contains("Team layoffs", StringComparison.CurrentCultureIgnoreCase)); + o.NotifiedOfTermination = relatedEvents.Any(x => + x.Description.Contains("Notified of termination", StringComparison.CurrentCultureIgnoreCase)); + o.AnnouncesTermination = relatedEvents.Any(x => + x.Description.Contains("Announces Termination", StringComparison.CurrentCultureIgnoreCase)); + o.AnnouncesResignation = relatedEvents.Any(x => + x.Description.Contains("Announces Resignation", StringComparison.CurrentCultureIgnoreCase)); + o.Threats = relatedEvents.Any(x => + x.Description.Contains("Threatening", StringComparison.CurrentCultureIgnoreCase)) || + relatedEvents.Any(x => + x.Description.Contains("threatened", StringComparison.CurrentCultureIgnoreCase)); + o.MissedPromotion = relatedEvents.Any(x => + x.Description.Contains("Missed Promotion", StringComparison.CurrentCultureIgnoreCase)); + o.Insubordination = relatedEvents.Any(x => + x.Description.Contains("insubordinate", StringComparison.CurrentCultureIgnoreCase)); + o.Absenteeism = relatedEvents.Any(x => + x.Description.Contains("missed work", StringComparison.CurrentCultureIgnoreCase)); + o.HRComplaints = relatedEvents.Any(x => + x.Description.Contains("Human Resource Complaint", StringComparison.CurrentCultureIgnoreCase)); + o.ITPolicyViolations = relatedEvents.Any(x => + x.Description.Contains("Employee violated company IT policy", + StringComparison.CurrentCultureIgnoreCase)); + o.IPPolicyViolations = relatedEvents.Any(x => + x.Description.Contains("Compliance Violation", StringComparison.CurrentCultureIgnoreCase)); + o.DrugAlcoholAbuse = n.NpcProfile.InsiderThreat.SubstanceAbuseAndAddictiveBehaviors.RelatedEvents.Any(); + o.CoworkerConflict = relatedEvents.Any(x => + x.Description.Contains("coworker", StringComparison.CurrentCultureIgnoreCase)); + o.EAPReferral = relatedEvents.Any(x => + x.Description.Contains("EAP Referral", StringComparison.CurrentCultureIgnoreCase)); + o.AccessRevoked = relatedEvents.Any(x => + x.Description.Contains("Access Revoked", StringComparison.CurrentCultureIgnoreCase)); + o.UnauthorizedCodingChange = relatedEvents.Any(x => + x.Description.Contains("unauthorized changes to a code base", + StringComparison.CurrentCultureIgnoreCase)); + o.UnauthorizedAccessChange = relatedEvents.Any(x => + x.Description.Contains("unauthorized changes to access", + StringComparison.CurrentCultureIgnoreCase)); + o.FinancialProblems = relatedEvents.Any(x => + x.Description.Contains("Financial Problems", + StringComparison.CurrentCultureIgnoreCase)) || + n.NpcProfile.InsiderThreat.FinancialConsiderations.RelatedEvents.Any(); + o.ArrestRecord = relatedEvents.Any(x => + x.Description.Contains("arrest", StringComparison.CurrentCultureIgnoreCase)); + o.GamblingHistory = relatedEvents.Any(x => + x.Description.Contains("gambling", StringComparison.CurrentCultureIgnoreCase)); + o.ServiceAccountUse = relatedEvents.Any(x => + x.Description.Contains("service account", StringComparison.CurrentCultureIgnoreCase)); + o.RemoteAccess = relatedEvents.Any(x => + x.Description.Contains("Virtual Access Anomaly", StringComparison.CurrentCultureIgnoreCase)); + o.BackdoorAccountUse = relatedEvents.Any(x => + x.Description.Contains("backdoor account", StringComparison.CurrentCultureIgnoreCase)); + o.SolicitedByCompetitor = relatedEvents.Any(x => + x.Description.Contains("Solicited by Competitor", StringComparison.CurrentCultureIgnoreCase)); + o.AfterHoursLogin = relatedEvents.Any(x => + x.Description.Contains("After Hours Login", StringComparison.CurrentCultureIgnoreCase)); + o.PrivilegeCreep = relatedEvents.Any(x => + x.Description.Contains("Misusing Privileged Function", StringComparison.CurrentCultureIgnoreCase)); + o.FileExtensionModification = relatedEvents.Any(x => + x.Description.Contains("modified file extension", StringComparison.CurrentCultureIgnoreCase)); + o.FileHeaderModification = relatedEvents.Any(x => + x.Description.Contains("modified file header", StringComparison.CurrentCultureIgnoreCase)); + o.FileContentModification = relatedEvents.Any(x => + x.Description.Contains("altered document", StringComparison.CurrentCultureIgnoreCase)); + o.FileTypeModification = relatedEvents.Any(x => + x.Description.Contains("modified file extension", StringComparison.CurrentCultureIgnoreCase)); + o.SensitiveInformationCopied = relatedEvents.Any(x => + x.Description.Contains("copied sensitive information", StringComparison.CurrentCultureIgnoreCase)); + o.ScreenShots = relatedEvents.Any(x => + x.Description.Contains("took screenshots", StringComparison.CurrentCultureIgnoreCase)); + o.ZipFile = relatedEvents.Any(x => + x.Description.Contains("compressed files", StringComparison.CurrentCultureIgnoreCase)); + o.Encryption = relatedEvents.Any(x => + x.Description.Contains("encrypted files", StringComparison.CurrentCultureIgnoreCase)); + o.DocumentMarkingTampering = relatedEvents.Any(x => + x.Description.Contains("altered document markings", StringComparison.CurrentCultureIgnoreCase)); + o.Steganography = relatedEvents.Any(x => + x.Description.Contains("used steganography", StringComparison.CurrentCultureIgnoreCase)); + o.LogDeletion = relatedEvents.Any(x => + x.Description.Contains("deleted logs", StringComparison.CurrentCultureIgnoreCase)); + o.ConcealmentInformation = relatedEvents.Any(x => + x.Description.Contains("concealed actions", StringComparison.CurrentCultureIgnoreCase)); + o.SaleAttempt = relatedEvents.Any(x => + x.Description.Contains("Information Sale Attempt", StringComparison.CurrentCultureIgnoreCase)); + o.Scanner = relatedEvents.Any(x => + x.Description.Contains("scanned files", StringComparison.CurrentCultureIgnoreCase)); + o.CloudStorage = relatedEvents.Any(x => + x.Description.Contains("cloud storage", StringComparison.CurrentCultureIgnoreCase)); + o.RemovableMedia = relatedEvents.Any(x => + x.Description.Contains("removable media device", StringComparison.CurrentCultureIgnoreCase)); + o.Print = relatedEvents.Any(x => + x.Description.Contains("printed sensitive files", StringComparison.CurrentCultureIgnoreCase)); + o.NetworkShare = relatedEvents.Any(x => + x.Description.Contains("unauthorized changes", StringComparison.CurrentCultureIgnoreCase)); + o.PersonalEmailAccount = relatedEvents.Any(x => + x.Description.Contains("personal email account", StringComparison.CurrentCultureIgnoreCase)); + o.EmailToConspirator = relatedEvents.Any(x => + x.Description.Contains("Email to Conspirator", StringComparison.CurrentCultureIgnoreCase)); + o.DNSExfiltrationTool = relatedEvents.Any(x => + x.Description.Contains("dns exfiltration", StringComparison.CurrentCultureIgnoreCase)); + o.FileDeletion = relatedEvents.Any(x => + x.Description.Contains("deleted files", StringComparison.CurrentCultureIgnoreCase)); + o.RecentHRTicket = + relatedEvents.Any(x => x.Reported > DateTime.Now.AddYears(-1)); //reported in the last year + o.BackgroundCkResult = n.NpcProfile.InsiderThreat.IsBackgroundCheckStatusClear; + o.InterpersonalSkills = n.NpcProfile.MentalHealth.InterpersonalSkills; + o.AdherenceToPolicy = n.NpcProfile.MentalHealth.AdherenceToPolicy; + o.EnthusiasmAndAttitude = n.NpcProfile.MentalHealth.EnthusiasmAndAttitude; + o.OpenToFeedback = n.NpcProfile.MentalHealth.OpenToFeedback; + o.GeneralPerformance = n.NpcProfile.MentalHealth.GeneralPerformance; + o.OverallPerformance = n.NpcProfile.MentalHealth.OverallPerformance; + } + catch (Exception e) + { + //todo log this + Console.WriteLine(e); + } + finalList.Add(o); + } + + foreach (var npc in finalList.Where(x => x.Manager != Guid.Empty)) + { + var manager = finalList.FirstOrDefault(x => x.Id == npc.Manager); + if (manager == null) continue; + if (npc.Company != manager.Company || npc.Department != manager.Department) + { + npc.Manager = Guid.Empty; + } + } + + return finalList; + } +} + +public class TrueFalseToXConverter : ConverterBase +{ + public override object StringToField(string o) + { + return o.Equals("X", StringComparison.InvariantCultureIgnoreCase); + } + + public override string FieldToString(object o) + { + return Convert.ToBoolean(o) ? "X" : string.Empty; + } +} + +public class EmptyGuidConverter : ConverterBase +{ + public override object StringToField(string o) + { + return o.Equals(Guid.Empty.ToString(), StringComparison.InvariantCultureIgnoreCase); + } + + public override string FieldToString(object o) + { + var x = Guid.Parse(o.ToString() ?? ""); + return x == Guid.Empty ? "" : x.ToString(); + } +} \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NpcActivity.cs b/src/Ghosts.Api/Infrastructure/Models/NpcActivity.cs similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NpcActivity.cs rename to src/Ghosts.Api/Infrastructure/Models/NpcActivity.cs diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NpcSocialGraph.cs b/src/Ghosts.Api/Infrastructure/Models/NpcSocialGraph.cs similarity index 93% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NpcSocialGraph.cs rename to src/Ghosts.Api/Infrastructure/Models/NpcSocialGraph.cs index bd8f7f82..ad3b901b 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/NpcSocialGraph.cs +++ b/src/Ghosts.Api/Infrastructure/Models/NpcSocialGraph.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using Newtonsoft.Json; namespace ghosts.api.Areas.Animator.Infrastructure.Models; @@ -73,12 +74,13 @@ public class Belief public decimal Likelihood { get; set; } public decimal Posterior { get; set; } - public Belief(Guid to, Guid from, string name, long currentStep, decimal likelihood, decimal posterior) + [JsonConstructor] + public Belief(Guid to, Guid from, string name, long step, decimal likelihood, decimal posterior) { this.From = from; this.To = to; this.Name = name; - this.Step = currentStep; + this.Step = step; this.Likelihood = likelihood; this.Posterior = posterior; } @@ -93,4 +95,5 @@ public static string ToHeader() return "To,From,Name,Step,Likelihood,Posterior"; } } + } \ No newline at end of file diff --git a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/TfVarsConfiguration.cs b/src/Ghosts.Api/Infrastructure/Models/TfVarsConfiguration.cs similarity index 74% rename from src/Ghosts.Api/Areas/Animator/Infrastructure/Models/TfVarsConfiguration.cs rename to src/Ghosts.Api/Infrastructure/Models/TfVarsConfiguration.cs index eaa64b7e..cbcc97c1 100644 --- a/src/Ghosts.Api/Areas/Animator/Infrastructure/Models/TfVarsConfiguration.cs +++ b/src/Ghosts.Api/Infrastructure/Models/TfVarsConfiguration.cs @@ -15,6 +15,19 @@ public class TfVarsConfiguration public string Gateway { get; set; } public string Mask { get; set; } + public bool IsValid() + { + if (string.IsNullOrEmpty(this.IpAddressLow) + || string.IsNullOrEmpty(this.IpAddressHigh) + || string.IsNullOrEmpty(this.Campaign) + || string.IsNullOrEmpty(this.Enclave) + || string.IsNullOrEmpty(this.Team) + || string.IsNullOrEmpty(this.Gateway) + || string.IsNullOrEmpty(this.Mask)) + return false; + return true; + } + public IList GetIpPool() { var pool = new List(); @@ -24,20 +37,21 @@ public IList GetIpPool() var low = Convert.ToInt32(lowArr[lowArr.GetUpperBound(0)]); var high = Convert.ToInt32(highArr[highArr.GetUpperBound(0)]); - + for (var i = low; i < high; i++) { pool.Add(ReplaceLastOccurrence(this.IpAddressLow, low.ToString(), i.ToString())); } + pool.Add(this.IpAddressHigh); return pool; } - + private static string ReplaceLastOccurrence(string Source, string Find, string Replace) { var place = Source.LastIndexOf(Find, StringComparison.CurrentCultureIgnoreCase); - if(place == -1) + if (place == -1) return Source; var result = Source.Remove(place, Find.Length).Insert(place, Replace); diff --git a/src/Ghosts.Api/Infrastructure/Services/MachineGroupService.cs b/src/Ghosts.Api/Infrastructure/Services/MachineGroupService.cs index 8c95d9eb..0e59ed22 100644 --- a/src/Ghosts.Api/Infrastructure/Services/MachineGroupService.cs +++ b/src/Ghosts.Api/Infrastructure/Services/MachineGroupService.cs @@ -34,17 +34,7 @@ public MachineGroupService(ApplicationDbContext context) public async Task> GetAsync(string q, CancellationToken ct) { - var list = await _context.Groups.Include(o => o.GroupMachines).ToListAsync(ct); - foreach (var group in list) - foreach (var machineMapping in group.GroupMachines) - { - var machine = await _context.Machines.FirstOrDefaultAsync(m => m.Id == machineMapping.MachineId && m.Status == StatusType.Active, ct); - if (machine == null) - continue; - group.Machines.Add(machine); - } - - return list; + return await _context.Groups.Include(o => o.GroupMachines).ToListAsync(ct); } public async Task GetAsync(int id, CancellationToken ct) @@ -76,7 +66,7 @@ public async Task UpdateAsync(Group model, CancellationToken ct) this._context.GroupMachines.Remove(g); } - if (model.GroupMachines.Count > 0) + if (model.GroupMachines != null && model.GroupMachines.Count > 0) { // Add new GroupMachines from the model foreach (var g in model.GroupMachines) @@ -88,10 +78,6 @@ public async Task UpdateAsync(Group model, CancellationToken ct) } } } - else - { - originalRecord.Machines.Clear(); - } // Update properties of the original record to match those of the model // Assuming Group has properties Name and Description @@ -125,18 +111,26 @@ public async Task DeleteAsync(int id, CancellationToken ct) public async Task> GetActivity(int id, int skip, int take, CancellationToken ct) { + if (take < 1) + take = 20; + var machineGroup = await _context.Groups.Include(o => o.GroupMachines).FirstOrDefaultAsync(o => o.Id == id, ct); + if (machineGroup == null) return new List(); + var machineIds = machineGroup.GroupMachines.Select(m => m.MachineId).ToList(); - + if (machineIds.Count < 1) return new List(); + try { - return (from o in _context.HistoryTimeline where machineIds.Contains(o.MachineId) select o).Skip(skip).Take(take).ToList(); + return (from o in _context.HistoryTimeline where machineIds.Contains(o.MachineId) select o) + .OrderByDescending(x => x.CreatedUtc).Skip(skip).Take(take).ToList(); } catch (Exception e) { - _log.Debug(e); - throw; + _log.Error(e); } + + return new List(); } } } \ No newline at end of file diff --git a/src/Ghosts.Api/Infrastructure/Services/MachineService.cs b/src/Ghosts.Api/Infrastructure/Services/MachineService.cs index 0e3ada5a..0a09e718 100755 --- a/src/Ghosts.Api/Infrastructure/Services/MachineService.cs +++ b/src/Ghosts.Api/Infrastructure/Services/MachineService.cs @@ -250,6 +250,9 @@ public async Task> GetMachineHistoryHealth(Guid id, Cancella public async Task> GetActivity(Guid id, int skip, int take, CancellationToken ct) { + if (take < 1) + take = 25; + var machine = await _context.Machines.FirstOrDefaultAsync(o => o.Id == id, ct); if (machine == null) { diff --git a/src/Ghosts.Api/Infrastructure/Services/MachineUpdateService.cs b/src/Ghosts.Api/Infrastructure/Services/MachineUpdateService.cs index 5a387e8f..a84689f7 100644 --- a/src/Ghosts.Api/Infrastructure/Services/MachineUpdateService.cs +++ b/src/Ghosts.Api/Infrastructure/Services/MachineUpdateService.cs @@ -11,6 +11,7 @@ using Ghosts.Domain; using Microsoft.EntityFrameworkCore; using NLog; +using NPOI.OpenXmlFormats.Wordprocessing; namespace ghosts.api.Infrastructure.Services { @@ -109,6 +110,12 @@ public async Task> GetByStatus(StatusType status, Can public async Task CreateAsync(MachineUpdate model, CancellationToken ct) { + var machineUpdate = await this.GetById(model.Id, ct); + if (machineUpdate != null) + return machineUpdate; + + model.Update.Id = Guid.NewGuid(); + _context.MachineUpdates.Add(model); await _context.SaveChangesAsync(ct); return model; diff --git a/src/Ghosts.Api/Infrastructure/Services/NpcService.cs b/src/Ghosts.Api/Infrastructure/Services/NpcService.cs new file mode 100644 index 00000000..c561840c --- /dev/null +++ b/src/Ghosts.Api/Infrastructure/Services/NpcService.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Ghosts.Animator; +using Ghosts.Animator.Models; +using ghosts.api.Areas.Animator.Infrastructure.Models; +using Ghosts.Api.Infrastructure.Data; +using Microsoft.EntityFrameworkCore; +using NLog; + +namespace ghosts.api.Infrastructure.Services; + +public interface INpcService +{ + public Task> GetAll(); + public Task> GetEnclave(string campaign, string enclave); + public Task> GetListAsync(); + public Task> GetTeam(string campaign, string enclave, string team); + public Task GetById(Guid id); + public Task> Create(GenerationConfiguration config, CancellationToken ct); + public Task CreateOne(); + public Task DeleteById(Guid id); + public Task> GetKeys(string key); + public Task SyncWithMachineUsernames(); +} + +public class NpcService : INpcService +{ + private static readonly Logger _log = LogManager.GetCurrentClassLogger(); + private readonly ApplicationDbContext _context; + + public NpcService(ApplicationDbContext context) + { + _context = context; + } + + public async Task> GetAll() + { + return await this._context.Npcs.ToListAsync(); + } + + public async Task> GetEnclave(string campaign, string enclave) + { + return await _context.Npcs.Where(x => x.Campaign == campaign && x.Enclave == enclave).ToListAsync(); + } + + public async Task> GetListAsync() + { + return await this._context.Npcs + .Select(item => new NpcNameId + { + Id = item.Id, + Name = $"{item.NpcProfile.Name.First} {item.NpcProfile.Name.Last}" + }) + .ToListAsync(); + } + + public async Task> GetListAsync(string campaign) + { + return await this._context.Npcs + .Where(x=>x.Campaign == campaign) + .Select(item => new NpcNameId + { + Id = item.Id, + Name = $"{item.NpcProfile.Name.First} {item.NpcProfile.Name.Last}" + }) + .ToListAsync(); + } + + public async Task> GetTeam(string campaign, string enclave, string team) + { + return await this._context.Npcs.Where(x => x.Campaign == campaign && x.Enclave == enclave && x.Team == team).ToListAsync(); + } + + public async Task GetById(Guid id) + { + return await this._context.Npcs.FirstOrDefaultAsync(x => x.Id == id); + } + + public async Task CreateOne() + { + var npc = NpcRecord.TransformToNpc(Npc.Generate(MilitaryUnits.GetServiceBranch())); + npc.Id = npc.NpcProfile.Id; + this._context.Npcs.Add(npc); + await this._context.SaveChangesAsync(); + return npc; + } + + public async Task> Create(GenerationConfiguration config, CancellationToken ct) + { + var t = new Stopwatch(); + t.Start(); + + var createdNpcs = new List(); + foreach (var enclave in config.Enclaves) + { + if (enclave.Teams == null) continue; + foreach (var team in enclave.Teams) + { + if (team.Npcs == null) continue; + if (team.Npcs.Number > 25) + { + _log.Warn("Cannot generate more than 25 NPCs at a time, sorry."); + team.Npcs.Number = 25; + } + for (var i = 0; i < team.Npcs.Number; i++) + { + var last = t.ElapsedMilliseconds; + var branch = team.Npcs.Configuration?.Branch ?? MilitaryUnits.GetServiceBranch(); + var npc = NpcRecord.TransformToNpc(Npc.Generate(new NpcGenerationConfiguration + { Branch = branch, PreferenceSettings = team.PreferenceSettings })); + npc.Id = npc.NpcProfile.Id; + npc.Team = team.Name; + npc.Campaign = config.Campaign; + npc.Enclave = enclave.Name; + + this._context.Npcs.Add(npc); + createdNpcs.Add(npc); + _log.Trace($"{i} generated in {t.ElapsedMilliseconds - last} ms"); + } + } + } + + await this._context.SaveChangesAsync(ct); + + t.Stop(); + _log.Trace($"{createdNpcs.Count} NPCs generated in {t.ElapsedMilliseconds} ms"); + + return createdNpcs; + } + + public async Task> GetKeys(string key) + { + if (key == null) + return new List(); + + return key.ToLower() switch + { + "campaign" => await _context.Npcs.Where(x => x.Campaign != null).Select(x => x.Campaign).Distinct().ToListAsync(), + "enclave" => await _context.Npcs.Where(x => x.Enclave != null).Select(x => x.Enclave).Distinct().ToListAsync(), + "team" => await _context.Npcs.Where(x => x.Team != null).Select(x => x.Team).Distinct().ToListAsync(), + _ => null + }; + } + + public async Task DeleteById(Guid id) + { + var o = await this._context.Npcs.FindAsync(id); + if (o != null) + { + this._context.Npcs.Remove(o); + await this._context.SaveChangesAsync(); + } + } + + public async Task SyncWithMachineUsernames() + { + var machines = this._context.Machines.ToList(); + var npcs = this._context.Npcs.ToArray(); + + foreach (var machine in machines) + { + if (npcs.Any(x => x.MachineId == machine.Id)) + continue; + if (npcs.Any(x => string.Equals(x.NpcProfile.Name.ToString()?.Replace(" ", "."), + machine.CurrentUsername, StringComparison.InvariantCultureIgnoreCase))) + continue; + + var npc = NpcRecord.TransformToNpc(Npc.Generate(MilitaryUnits.GetServiceBranch(), machine.CurrentUsername)); + + //todo: need to be sure user is aligned with the machine currentusername + + npc.Id = npc.NpcProfile.Id; + npc.MachineId = machine.Id; + this._context.Npcs.Add(npc); + _log.Trace($"NPC created for {machine.CurrentUsername}..."); + } + + await this._context.SaveChangesAsync(); + _log.Trace($"NPCs created for each username in machines"); + } +} \ No newline at end of file diff --git a/src/Ghosts.Api/Infrastructure/Services/QueueSyncService.cs b/src/Ghosts.Api/Infrastructure/Services/QueueSyncService.cs index 3dc92929..0e432128 100755 --- a/src/Ghosts.Api/Infrastructure/Services/QueueSyncService.cs +++ b/src/Ghosts.Api/Infrastructure/Services/QueueSyncService.cs @@ -383,6 +383,8 @@ private async Task ProcessMachine(IServiceScope scope, ApplicationDbContext cont internal static async void HandleWebhook(Webhook webhook, NotificationQueueEntry payload) { + if (webhook == null || payload == null) return; + string formattedResponse; if (payload.Type == NotificationQueueEntry.NotificationType.TimelineDelivered) { @@ -394,6 +396,7 @@ internal static async void HandleWebhook(Webhook webhook, NotificationQueueEntry // Serialize our concrete class into a JSON String formattedResponse = webhook.PostbackFormat; + if(string.IsNullOrEmpty(formattedResponse)) return; var isValid = false; var reg = new Regex(@"\[(.*?)\]"); diff --git a/src/Ghosts.Api/Infrastructure/Services/TimelineService.cs b/src/Ghosts.Api/Infrastructure/Services/TimelineService.cs index 9da1be39..4f0ee4bf 100644 --- a/src/Ghosts.Api/Infrastructure/Services/TimelineService.cs +++ b/src/Ghosts.Api/Infrastructure/Services/TimelineService.cs @@ -29,6 +29,8 @@ public TimelineService(ApplicationDbContext context) public async Task UpdateAsync(MachineUpdateViewModel machineUpdateViewModel, CancellationToken ct) { + if (machineUpdateViewModel == null) return; + var machineUpdate = machineUpdateViewModel.ToMachineUpdate(); _context.MachineUpdates.Add(machineUpdate); @@ -61,7 +63,7 @@ public async Task StopAsync(Guid machineId, Guid timelineId, CancellationToken c var o = new MachineUpdate { Status = StatusType.Active, - Update = JsonConvert.SerializeObject(timeline), + Update = timeline, //JsonConvert.SerializeObject(timeline), ActiveUtc = DateTime.UtcNow, CreatedUtc = DateTime.UtcNow, MachineId = machineId, diff --git a/src/Ghosts.Api/Startup.cs b/src/Ghosts.Api/Startup.cs index 32f7f01b..c7039104 100755 --- a/src/Ghosts.Api/Startup.cs +++ b/src/Ghosts.Api/Startup.cs @@ -1,18 +1,17 @@ -// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. - using System; using System.IO; using System.Reflection; using System.Text.Json.Serialization; using ghosts.api.Areas.Animator.Hubs; using ghosts.api.Areas.Animator.Infrastructure.Animations; -using ghosts.api.Areas.Animator.Infrastructure.Services; using Ghosts.Api.Hubs; using Ghosts.Api.Infrastructure.Data; using Ghosts.Api.Infrastructure.Extensions; +using Ghosts.Api.Infrastructure.Filters; using ghosts.api.Infrastructure.Services; using Ghosts.Api.ViewModels; using Ghosts.Domain.Code; +using Ghosts.Domain.Code.Helpers; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; @@ -22,7 +21,9 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.OpenApi.Models; +using Newtonsoft.Json.Converters; using Swashbuckle.AspNetCore.Filters; +using Swashbuckle.AspNetCore.Newtonsoft; namespace Ghosts.Api { @@ -39,7 +40,6 @@ public Startup(IConfiguration configuration) public void ConfigureServices(IServiceCollection services) { - //services.AddDbContext(opt => opt.UseInMemoryDatabase("ghosts")); services.AddDbContext(options => options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"))); services.TryAddTransient(); @@ -63,16 +63,16 @@ public void ConfigureServices(IServiceCollection services) Name = "Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms" } }); - + // Set the comments path for the Swagger JSON and UI. var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); + c.DocumentFilter(); c.IncludeXmlComments(xmlPath); c.ExampleFilters(); }); + services.AddSwaggerGenNewtonsoftSupport(); // explicit opt-in - needs to be placed after AddSwaggerGen() services.AddSwaggerExamplesFromAssemblies(Assembly.GetEntryAssembly()); - services.AddSwaggerExamplesFromAssemblyOf(); - // Add application services. services.AddScoped(); @@ -91,7 +91,11 @@ public void ConfigureServices(IServiceCollection services) services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter())); - services.AddMvc().AddNewtonsoftJson(); + services.AddMvc().AddNewtonsoftJson(options => + { + options.SerializerSettings.Converters.Add(new TimeSpanConverter()); + options.SerializerSettings.Converters.Add(new StringEnumConverter()); + }); services.AddSignalR(); services.AddControllersWithViews().AddRazorRuntimeCompilation(); @@ -132,4 +136,4 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) }); } } -} \ No newline at end of file +} diff --git a/src/Ghosts.Api/ViewModels/MachineUpdateViewModel.cs b/src/Ghosts.Api/ViewModels/MachineUpdateViewModel.cs index fdfc8c7c..9968e1de 100644 --- a/src/Ghosts.Api/ViewModels/MachineUpdateViewModel.cs +++ b/src/Ghosts.Api/ViewModels/MachineUpdateViewModel.cs @@ -27,7 +27,7 @@ public MachineUpdate ToMachineUpdate() { CreatedUtc = DateTime.UtcNow, Status = Status, - Update = JsonConvert.SerializeObject(Update), + Update = Update, //JsonConvert.SerializeObject(Update), MachineId = MachineId, Type = Type, ActiveUtc = ActiveUtc @@ -56,7 +56,7 @@ public MachineUpdateViewModel GetExamples() { HandlerType = HandlerType.BrowserFirefox, Initial = "https://cmu.edu", - UtcTimeOn = TimeSpan.Parse("0000:00"), + UtcTimeOn = TimeSpan.Parse("00:00:00"), UtcTimeOff = TimeSpan.Parse("23:59:59"), Loop = true, TimeLineEvents = new List diff --git a/src/Ghosts.Api/Areas/Animator/Views/Animations/Index.cshtml b/src/Ghosts.Api/Views/Animations/Index.cshtml similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Views/Animations/Index.cshtml rename to src/Ghosts.Api/Views/Animations/Index.cshtml diff --git a/src/Ghosts.Api/Areas/Animator/Views/Animations/Started.cshtml b/src/Ghosts.Api/Views/Animations/Started.cshtml similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Views/Animations/Started.cshtml rename to src/Ghosts.Api/Views/Animations/Started.cshtml diff --git a/src/Ghosts.Api/Views/Shared/_Layout.cshtml b/src/Ghosts.Api/Views/Shared/_Layout.cshtml index 605a57b0..dc92ff5f 100644 --- a/src/Ghosts.Api/Views/Shared/_Layout.cshtml +++ b/src/Ghosts.Api/Views/Shared/_Layout.cshtml @@ -31,16 +31,16 @@ diff --git a/src/Ghosts.Api/Areas/Animator/Views/ViewActivities/Index.cshtml b/src/Ghosts.Api/Views/ViewActivities/Index.cshtml similarity index 93% rename from src/Ghosts.Api/Areas/Animator/Views/ViewActivities/Index.cshtml rename to src/Ghosts.Api/Views/ViewActivities/Index.cshtml index a0a84700..2a409e5e 100644 --- a/src/Ghosts.Api/Areas/Animator/Views/ViewActivities/Index.cshtml +++ b/src/Ghosts.Api/Views/ViewActivities/Index.cshtml @@ -6,7 +6,7 @@
    -

    Animator Activities

    +

    Activities

    @@ -58,6 +58,8 @@ var icon = ""; if (type === "belief") icon = ""; + else if (type === "chat") + icon = ""; else if (type === "knowledge") icon = ""; else if (type === "relationship") diff --git a/src/Ghosts.Api/Areas/Animator/Views/ViewActivities/detail.cshtml b/src/Ghosts.Api/Views/ViewActivities/detail.cshtml similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Views/ViewActivities/detail.cshtml rename to src/Ghosts.Api/Views/ViewActivities/detail.cshtml diff --git a/src/Ghosts.Api/Areas/Animator/Views/ViewRelationships/Index.cshtml b/src/Ghosts.Api/Views/ViewRelationships/Index.cshtml similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Views/ViewRelationships/Index.cshtml rename to src/Ghosts.Api/Views/ViewRelationships/Index.cshtml diff --git a/src/Ghosts.Api/Areas/Animator/Views/ViewRelationships/Profile.cshtml b/src/Ghosts.Api/Views/ViewRelationships/Profile.cshtml similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Views/ViewRelationships/Profile.cshtml rename to src/Ghosts.Api/Views/ViewRelationships/Profile.cshtml diff --git a/src/Ghosts.Api/Areas/Animator/Views/ViewSocial/Detail.cshtml b/src/Ghosts.Api/Views/ViewSocial/Detail.cshtml similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Views/ViewSocial/Detail.cshtml rename to src/Ghosts.Api/Views/ViewSocial/Detail.cshtml diff --git a/src/Ghosts.Api/Areas/Animator/Views/ViewSocial/Index.cshtml b/src/Ghosts.Api/Views/ViewSocial/Index.cshtml similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Views/ViewSocial/Index.cshtml rename to src/Ghosts.Api/Views/ViewSocial/Index.cshtml diff --git a/src/Ghosts.Api/Areas/Animator/Views/ViewSocial/Interactions.cshtml b/src/Ghosts.Api/Views/ViewSocial/Interactions.cshtml similarity index 100% rename from src/Ghosts.Api/Areas/Animator/Views/ViewSocial/Interactions.cshtml rename to src/Ghosts.Api/Views/ViewSocial/Interactions.cshtml diff --git a/src/Ghosts.Api/appsettings.json b/src/Ghosts.Api/appsettings.json index 0aae7809..c461e9f0 100755 --- a/src/Ghosts.Api/appsettings.json +++ b/src/Ghosts.Api/appsettings.json @@ -5,7 +5,10 @@ "Logging": { "IncludeScopes": false, "LogLevel": { - "Default": "Warning" + "Default": "Information", + "Microsoft": "Warning", + "System": "Warning", + "Microsoft.EntityFrameworkCore.Database.Command": "Information" } }, "ApplicationSettings": { diff --git a/src/Ghosts.Api/config/photos/default.png b/src/Ghosts.Api/config/photos/default.png new file mode 100644 index 0000000000000000000000000000000000000000..03fe3cc74e8a797c7c71139c3df58b355ee21cfa GIT binary patch literal 86914 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∾VRZ9ubJ&wkz2owbAVPsimtC#y~)16Z*gkrgSp zJ#T_{oL^hO2JrP6fD9MTC81DL+~DYH=7CX;#pT)!ZK_>FE5Y5U;2&rbwCtu?Oqc^9 z-YWu!f$4i!B=CcP&xpLff5g{|dZbR)JFRp7xY{4JkH`Qdf$P0hW7P3yJ18|#e@p~1{OBgY zVBli_+^@&&h!eE9-4fS6pR_V?9Wwy)V%U6KB~89D z)`Z#F{}1m!0K$z0XutJtm9#+d?Jyy6)SEBiEf1Bu1=&ScD0?{Ga~K&+&>MmlfiPzZ zfa+hnD&=ar1owfR2*R`th#D#zlnFuYg^-bP`gdmNIBXK4w?hYnLg4xn!lK4yfS7gr z{kzu&Y0&|<^@qmQrxvTud1<9Dw6LX$B8T{5YEGG`HRMBFGl&5#p39KCsA znWFsXAZOZkeHB<%U8OElv|QDHRTv~k4P z#_zt!_B5a?@OfIqR|(Wbr1SU~+4-;7&TQnZ%g1zH6M)C$jyXu99Ey<-z)#2r^GTq> z0)VU_S`6H?FQCpr4$a<*QTOGSETJ6qtrzmHGFaW_kE8l{8pox-2PyZ@V%CdD0E%7` zw9FZ-QsE(&G4-%sNX4}VJb(tcKQx0*_G`E(PufZBQ|KYneFqlo4TD?UgwZZXC;_)- z9;w1j@g33q2D@5J3IInNP8KP;?Q(DlbBaGDj!c1r8gn@HXSNHx8xgqPcR0Zt$}=lq z)-Y>3Qe`!X{Ved&2&z`bAU7!vf%Tiu3f()_ZYJ2{Vs8PQkN4CIQezxd5K`zamBt2{7ks)$=kQld$g-Hw`kG)IMvk)0WI05(KL-2)tOoW(`WUbm+SIdT zuL^Fu17oGtt>kYvMfv09mtw;lMnMGa@#$=}ZV7%ntE{)|Z5#64H6XUM%5|2h+ZD2AhGCJZ}lg zWI#j;puFhw&)Dv)lh_V5#%ZV^ht7t@;kmr4CKeM^S!b+^T-Po$E)73TlUrgo_MEVX zCuo%rWMPx93F=TYo-jlc@>W<+qnKdzV#Ig5ArjnfB~@N!U^{}9MT5SIP^m(<7gyQ< z1aL+TVI_s~gji{CCQrq!5%QDz?)Z%ZTCw)gA&1bT^F1cT@~%E}5C&r(6-7HnsmrPT z1YLzqF11AQwFm4(mh_O;#`*|Tut&unAFaR!l0>K*I8plfrzOG=eai&h4J$3X!lexK z3eVrG0e9fU)Oo!-JhDXV`I=9*UWe>30sZVncBW(NMOEgqMWpkP9c|@oxHg@rL9KF9 ziVO(LB&pKfcj-A33ltlqBwcQ=WN?dhEUz-9C_6|Hg(`tcdD2WFeblH9CU0_!cpNgh zYs_lm(kIR9Af8Hd$ux)|cazvwK#--Gq$?;RsGB}L(qx)vTAoRQPD0-S(73%AnK#S? ziDE#woluxvG(;-3YTD%rJw=WM0xPVU_DU_fttv4EQQksX?qiR#UI*Ij}p= zh~;d@*4EkNNrs2~;~Ss40SR)5b_f1+q6Dz=J9nE5h)zGAXrZW^xIA(l-CHU05YP$d zAj_J#6bRF7in{hU5kdj+9KnF8RHPitN+0h7NU_33#b$hr_l3>6Hya6XP$lu`fzLwM zT>&$mqWdM9E%pXzQ - - - - - + + + + + + - - + + @@ -51,10 +52,6 @@ - - - - <_ContentIncludedByDefault Remove="Areas\Animator\config\address_international_cities.json" /> <_ContentIncludedByDefault Remove="Areas\Animator\config\bmi.json" /> @@ -101,11 +98,29 @@ <_ContentIncludedByDefault Remove="Areas\Animator\config\us_population_data.json" /> <_ContentIncludedByDefault Remove="output\socialgraph\social_graph.json" /> <_ContentIncludedByDefault Remove="_output\socialgraph\social_graph.json" /> + <_ContentIncludedByDefault Remove="Areas\Animator\Views\ViewActivities\detail.cshtml" /> + <_ContentIncludedByDefault Remove="Areas\Animator\Views\ViewActivities\Index.cshtml" /> + <_ContentIncludedByDefault Remove="Areas\Animator\Views\ViewRelationships\Index.cshtml" /> + <_ContentIncludedByDefault Remove="Areas\Animator\Views\ViewRelationships\Profile.cshtml" /> + <_ContentIncludedByDefault Remove="Areas\Animator\Views\ViewSocial\Detail.cshtml" /> + <_ContentIncludedByDefault Remove="Areas\Animator\Views\ViewSocial\Index.cshtml" /> + <_ContentIncludedByDefault Remove="Areas\Animator\Views\ViewSocial\Interactions.cshtml" /> + <_ContentIncludedByDefault Remove="Areas\Animator\Views\Home\Index.cshtml" /> + <_ContentIncludedByDefault Remove="Areas\Animator\Views\_ViewStart.cshtml" /> + + + + + + + + + @@ -134,5 +149,8 @@ PreserveNewest + + PreserveNewest + diff --git a/src/Ghosts.Domain/Code/ApplicationDetails.cs b/src/Ghosts.Domain/Code/ApplicationDetails.cs index 48e0e9f9..1cbc943b 100755 --- a/src/Ghosts.Domain/Code/ApplicationDetails.cs +++ b/src/Ghosts.Domain/Code/ApplicationDetails.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; using System.IO; +using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using NLog; @@ -100,14 +101,15 @@ private static string Clean(string x) /// public static class ConfigurationFiles { - public static string Path => InstalledPath + $"{System.IO.Path.DirectorySeparatorChar}config{System.IO.Path.DirectorySeparatorChar}"; + public static string InstallPath => InstalledPath + $"{System.IO.Path.DirectorySeparatorChar}config{System.IO.Path.DirectorySeparatorChar}"; - public static string Application => Clean(Path + "application.json"); - public static string Health => Clean(Path + "health.json"); - public static string Timeline => Clean(Path + "timeline.json"); + public static string DefaultNpcImage => Clean(Path.Combine(InstallPath, "photos", "default.png")); + public static string Application => Clean(InstallPath + "application.json"); + public static string Health => Clean(InstallPath + "health.json"); + public static string Timeline => Clean(InstallPath + "timeline.json"); - public static string DenyList => Clean(Path + "denylist.txt"); - public static string EmailsFooter => Clean(Path + "emails-footer.txt"); + public static string DenyList => Clean(InstallPath + "denylist.txt"); + public static string EmailsFooter => Clean(InstallPath + "emails-footer.txt"); public static string EmailContent(string raw) => Determine(raw, "email-content.csv"); public static string EmailReply(string raw) => Determine(raw, "email-reply.csv"); @@ -129,7 +131,7 @@ public static class ConfigurationFiles private static string Determine(string raw, string defaultValue) { - return !string.IsNullOrEmpty(raw) ? raw : Clean(Path + defaultValue); + return !string.IsNullOrEmpty(raw) ? raw : Clean(InstallPath + defaultValue); } } diff --git a/src/Ghosts.Domain/Code/Helpers/TimeSpanConverter.cs b/src/Ghosts.Domain/Code/Helpers/TimeSpanConverter.cs new file mode 100644 index 00000000..f85b641b --- /dev/null +++ b/src/Ghosts.Domain/Code/Helpers/TimeSpanConverter.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Ghosts.Domain.Code.Helpers +{ + public class TimeSpanConverter : JsonConverter + { + ///

    + /// Format: Hours:Minutes:Seconds + /// + private const string TimeSpanFormatString = @"hh\:mm\:ss"; + + public override void WriteJson(JsonWriter writer, TimeSpan value, JsonSerializer serializer) + { + var timespanFormatted = value.ToString(TimeSpanFormatString); + writer.WriteValue(timespanFormatted); + } + + public override TimeSpan ReadJson(JsonReader reader, Type objectType, TimeSpan existingValue, bool hasExistingValue, JsonSerializer serializer) + { + try + { + TimeSpan.TryParseExact((string)reader.Value, TimeSpanFormatString, null, out var parsedTimeSpan); + return parsedTimeSpan; + } + catch + { + return TimeSpan.Zero; + } + } + } + + public class TimeSpanArrayConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, TimeSpan[] value, JsonSerializer serializer) + { + if (value == null || value.Length == 0) + { + writer.WriteNull(); + } + else + { + writer.WriteStartArray(); + foreach (var timeSpan in value) + { + writer.WriteValue(timeSpan.ToString(@"hh\:mm\:ss")); + } + writer.WriteEndArray(); + } + } + + public override TimeSpan[] ReadJson(JsonReader reader, Type objectType, TimeSpan[] existingValue, bool hasExistingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + { + return null; + } + + var timeSpans = new List(); + while (reader.Read()) + { + if (reader.TokenType == JsonToken.EndArray) + { + break; + } + + if (reader.TokenType == JsonToken.String) + { + if (TimeSpan.TryParseExact((string)reader.Value, @"hh\:mm\:ss", null, out var timeSpan)) + { + timeSpans.Add(timeSpan); + } + } + } + + return timeSpans.ToArray(); + } + } +} diff --git a/src/Ghosts.Domain/Messages/Timeline.cs b/src/Ghosts.Domain/Messages/Timeline.cs index 3d5202aa..bb13b5a8 100755 --- a/src/Ghosts.Domain/Messages/Timeline.cs +++ b/src/Ghosts.Domain/Messages/Timeline.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using Ghosts.Domain.Code; +using Ghosts.Domain.Code.Helpers; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -59,10 +60,16 @@ public TimelineHandler() /// public string Initial { get; set; } + [JsonConverter(typeof(TimeSpanConverter))] + [JsonProperty(TypeNameHandling = TypeNameHandling.All)] public TimeSpan UtcTimeOn { get; set; } + + [JsonConverter(typeof(TimeSpanConverter))] + [JsonProperty(TypeNameHandling = TypeNameHandling.All)] public TimeSpan UtcTimeOff { get; set; } - [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(TimeSpanArrayConverter))] + [JsonProperty(TypeNameHandling = TypeNameHandling.All, NullValueHandling = NullValueHandling.Ignore)] public TimeSpan[] UtcTimeBlocks { get; set; } //not required currently (2.4) diff --git a/src/ghosts.client.linux/Health/Check.cs b/src/ghosts.client.linux/Health/Check.cs index 3b6f029b..99a1e14c 100644 --- a/src/ghosts.client.linux/Health/Check.cs +++ b/src/ghosts.client.linux/Health/Check.cs @@ -30,7 +30,7 @@ public void Run() try { // now watch that file for changes - var watcher = new FileSystemWatcher(ApplicationDetails.ConfigurationFiles.Path); + var watcher = new FileSystemWatcher(ApplicationDetails.ConfigurationFiles.InstallPath); watcher.Filter = Path.GetFileName(ApplicationDetails.ConfigurationFiles.Health); _log.Trace($"watching {watcher.Path}"); watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.FileName | NotifyFilters.Size; From c48633727f8b48b32af7919a832e616a2a2fa8a9 Mon Sep 17 00:00:00 2001 From: Dustin Updyke Date: Thu, 6 Jun 2024 09:56:40 -0400 Subject: [PATCH 2/3] 8.1 updates and api clean up --- src/Ghosts.Animator/ghosts.animator.csproj | 6 +- .../Controllers/AnimationsController.cs | 4 +- .../Api/AnimationJobsController.cs | 2 +- .../Api/MachineUpdatesController.cs | 3 + .../Controllers/Api/NpcsController.cs | 1 + .../Controllers/Api/NpcsGenerateController.cs | 1 + .../Controllers/ViewActivitiesController.cs | 2 + .../ViewRelationshipsController.cs | 1 + src/Ghosts.Api/Hubs/ActivityHub.cs | 4 +- src/Ghosts.Api/Hubs/ConnectionMapping.cs | 4 +- .../AnimationDefinitions/Chat/ChatClient.cs | 13 +- .../Chat/ChatConfiguration.cs | 2 +- .../Chat/Mattermost/Channel.cs | 29 +- .../Chat/Mattermost/Post.cs | 2 +- .../Chat/Mattermost/Team.cs | 2 +- .../Chat/Mattermost/User.cs | 2 +- .../AnimationDefinitions/ChatJob.cs | 10 +- .../AnimationDefinitions/FullAutonomyJob.cs | 7 +- .../AnimationDefinitions/SocialBeliefJob.cs | 7 +- .../AnimationDefinitions/SocialGraphJob.cs | 6 +- .../AnimationDefinitions/SocialSharingJob.cs | 7 +- .../Animations/AnimationsManager.cs | 6 +- src/Ghosts.Api/Infrastructure/ApIDetails.cs | 1 - .../ContentServices/ContentCreationService.cs | 10 +- .../ContentServices/GenericContentHelpers.cs | 4 +- .../ContentServices/IContentService.cs | 4 +- .../ContentServices/IFormatterService.cs | 6 +- .../Native/NativeContentFormatterService.cs | 6 +- .../Ollama/OllamaConnectorService.cs | 2 +- .../Ollama/OllamaFormatterService.cs | 6 +- .../OpenAi/OpenAIConnectorService.cs | 4 +- .../OpenAi/OpenAIFormatterService.cs | 6 +- .../ContentServices/OpenAi/OpenAIHelpers.cs | 4 +- .../Shadows/ShadowsConnectorService.cs | 2 +- .../Shadows/ShadowsFormatterService.cs | 6 +- src/Ghosts.Api/Infrastructure/Examples.cs | 50 ++ src/Ghosts.Api/Infrastructure/Exceptions.cs | 16 - .../Extensions/DateTimeExtensions.cs | 4 +- .../Extensions/DictionaryExtensions.cs | 2 + .../Extensions/EnumeratorExtensions.cs | 4 +- .../Extensions/JsonExtensions.cs | 2 + .../Extensions/StringExtensions.cs | 2 +- .../Extensions/ZipExtensions.cs | 2 + .../Filters/CustomDocumentFilter.cs | 2 + src/Ghosts.Api/Infrastructure/GroupNames.cs | 4 +- .../Models/EnclaveReducedCsv.cs | 2 +- .../Models/GenerationConfiguration.cs | 2 +- .../InsiderThreatGenerationConfiguration.cs | 1 + src/Ghosts.Api/Infrastructure/Models/NPC.cs | 5 +- .../Infrastructure/Models/NPCIpAddress.cs | 2 +- .../Infrastructure/Models/NPCNameId.cs | 2 +- .../Infrastructure/Models/NPCReduced.cs | 2 +- .../Infrastructure/Models/NPCToCsv.cs | 2 +- .../Models/NPCToInsiderThreatCsv.cs | 2 +- .../Infrastructure/Models/NpcActivity.cs | 2 +- .../Infrastructure/Models/NpcSocialGraph.cs | 2 +- .../Models/TfVarsConfiguration.cs | 2 +- .../Services/MachineUpdateService.cs | 1 - .../Infrastructure/Services/NpcService.cs | 1 + .../Services/TimelineService.cs | 2 +- .../Services/TrackableService.cs | 4 - .../Infrastructure/WebRequestReader.cs | 2 +- src/Ghosts.Api/Program.cs | 3 +- src/Ghosts.Api/Startup.cs | 13 +- src/Ghosts.Api/Views/Animations/Index.cshtml | 4 +- .../Views/Animations/Started.cshtml | 2 +- .../Views/ViewActivities/Index.cshtml | 2 +- .../Views/ViewActivities/detail.cshtml | 2 +- .../Views/ViewRelationships/Profile.cshtml | 2 +- src/Ghosts.Api/Views/ViewSocial/Detail.cshtml | 2 +- src/Ghosts.Api/Views/ViewSocial/Index.cshtml | 2 +- src/Ghosts.Api/appsettings.json | 2 +- .../config/timelines/BrowserFirefox.json | 519 +----------------- src/Ghosts.Api/ghosts.api.csproj | 2 +- src/Ghosts.Domain/ghosts.domain.csproj | 2 +- .../Handlers/BrowserFirefox.cs | 7 + 76 files changed, 210 insertions(+), 660 deletions(-) create mode 100644 src/Ghosts.Api/Infrastructure/Examples.cs delete mode 100644 src/Ghosts.Api/Infrastructure/Exceptions.cs diff --git a/src/Ghosts.Animator/ghosts.animator.csproj b/src/Ghosts.Animator/ghosts.animator.csproj index 72cf8922..2db9895f 100644 --- a/src/Ghosts.Animator/ghosts.animator.csproj +++ b/src/Ghosts.Animator/ghosts.animator.csproj @@ -4,8 +4,8 @@ Ghosts.Animator ghosts.animator - 1.1.1.0 - 1.1.1.0 + 1.2.1.0 + 1.2.1.0 GHOSTS Development Team @ Carnegie Mellon University Carnegie Mellon University @@ -17,7 +17,7 @@ - + diff --git a/src/Ghosts.Api/Controllers/AnimationsController.cs b/src/Ghosts.Api/Controllers/AnimationsController.cs index 4151530f..047e61cf 100644 --- a/src/Ghosts.Api/Controllers/AnimationsController.cs +++ b/src/Ghosts.Api/Controllers/AnimationsController.cs @@ -1,7 +1,9 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System.Threading; using Ghosts.Api; -using ghosts.api.Areas.Animator.Infrastructure.Animations; using Ghosts.Api.Infrastructure; +using ghosts.api.Infrastructure.Animations; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using NLog; diff --git a/src/Ghosts.Api/Controllers/Api/AnimationJobsController.cs b/src/Ghosts.Api/Controllers/Api/AnimationJobsController.cs index 9aad418a..03eee64f 100644 --- a/src/Ghosts.Api/Controllers/Api/AnimationJobsController.cs +++ b/src/Ghosts.Api/Controllers/Api/AnimationJobsController.cs @@ -1,7 +1,7 @@ // Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. using System; -using ghosts.api.Areas.Animator.Infrastructure.Animations; +using ghosts.api.Infrastructure.Animations; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; diff --git a/src/Ghosts.Api/Controllers/Api/MachineUpdatesController.cs b/src/Ghosts.Api/Controllers/Api/MachineUpdatesController.cs index 89f45132..ea572f0c 100755 --- a/src/Ghosts.Api/Controllers/Api/MachineUpdatesController.cs +++ b/src/Ghosts.Api/Controllers/Api/MachineUpdatesController.cs @@ -3,6 +3,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using ghosts.api.Infrastructure; using ghosts.api.Infrastructure.Models; using ghosts.api.Infrastructure.Services; using Ghosts.Api.ViewModels; @@ -10,6 +11,7 @@ using Microsoft.AspNetCore.Mvc; using NLog; using Swashbuckle.AspNetCore.Annotations; +using Swashbuckle.AspNetCore.Filters; namespace ghosts.api.Controllers.Api { @@ -37,6 +39,7 @@ public MachineUpdatesController(IMachineUpdateService updateService) [ProducesResponseType(200)] [ProducesResponseType(401)] [ProducesResponseType(404)] + [SwaggerRequestExample(typeof(MachineUpdate), typeof(MachineUpdateExample))] [SwaggerOperation("MachineUpdatesCreate")] [HttpPost] public async Task Create([FromBody] MachineUpdate machineUpdate, CancellationToken ct) diff --git a/src/Ghosts.Api/Controllers/Api/NpcsController.cs b/src/Ghosts.Api/Controllers/Api/NpcsController.cs index 729ca3ac..3616b5e4 100644 --- a/src/Ghosts.Api/Controllers/Api/NpcsController.cs +++ b/src/Ghosts.Api/Controllers/Api/NpcsController.cs @@ -15,6 +15,7 @@ using ghosts.api.Areas.Animator.Infrastructure.Models; using Ghosts.Api.Infrastructure.Data; using Ghosts.Api.Infrastructure.Extensions; +using ghosts.api.Infrastructure.Models; using ghosts.api.Infrastructure.Services; using Ghosts.Domain.Code; using Microsoft.AspNetCore.Mvc; diff --git a/src/Ghosts.Api/Controllers/Api/NpcsGenerateController.cs b/src/Ghosts.Api/Controllers/Api/NpcsGenerateController.cs index aa0b035e..26e552f1 100644 --- a/src/Ghosts.Api/Controllers/Api/NpcsGenerateController.cs +++ b/src/Ghosts.Api/Controllers/Api/NpcsGenerateController.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using ghosts.api.Areas.Animator.Infrastructure.Models; +using ghosts.api.Infrastructure.Models; using ghosts.api.Infrastructure.Services; using Microsoft.AspNetCore.Mvc; using NLog; diff --git a/src/Ghosts.Api/Controllers/ViewActivitiesController.cs b/src/Ghosts.Api/Controllers/ViewActivitiesController.cs index 2a63957f..43cf2336 100644 --- a/src/Ghosts.Api/Controllers/ViewActivitiesController.cs +++ b/src/Ghosts.Api/Controllers/ViewActivitiesController.cs @@ -1,3 +1,5 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System; using System.Linq; using Ghosts.Api.Infrastructure.Data; diff --git a/src/Ghosts.Api/Controllers/ViewRelationshipsController.cs b/src/Ghosts.Api/Controllers/ViewRelationshipsController.cs index 9efb3cdd..8e29418c 100644 --- a/src/Ghosts.Api/Controllers/ViewRelationshipsController.cs +++ b/src/Ghosts.Api/Controllers/ViewRelationshipsController.cs @@ -5,6 +5,7 @@ using System.Text; using ghosts.api.Areas.Animator.Infrastructure.Models; using Ghosts.Api.Infrastructure.Data; +using ghosts.api.Infrastructure.Models; using Microsoft.AspNetCore.Mvc; namespace ghosts.api.Controllers; diff --git a/src/Ghosts.Api/Hubs/ActivityHub.cs b/src/Ghosts.Api/Hubs/ActivityHub.cs index 829dd20e..d722a8e6 100644 --- a/src/Ghosts.Api/Hubs/ActivityHub.cs +++ b/src/Ghosts.Api/Hubs/ActivityHub.cs @@ -1,3 +1,5 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System; using System.Globalization; using System.Threading.Tasks; @@ -5,7 +7,7 @@ using Microsoft.AspNetCore.SignalR; using NLog; -namespace ghosts.api.Areas.Animator.Hubs; +namespace ghosts.api.Hubs; public class ActivityHub : Hub { diff --git a/src/Ghosts.Api/Hubs/ConnectionMapping.cs b/src/Ghosts.Api/Hubs/ConnectionMapping.cs index 909e54fd..825ebfed 100644 --- a/src/Ghosts.Api/Hubs/ConnectionMapping.cs +++ b/src/Ghosts.Api/Hubs/ConnectionMapping.cs @@ -1,7 +1,9 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System.Collections.Generic; using System.Linq; -namespace ghosts.api.Areas.Animator.Hubs; +namespace ghosts.api.Hubs; public class ConnectionMapping { diff --git a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs index 7e2ba51f..b4d9797f 100644 --- a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/ChatClient.cs @@ -10,19 +10,18 @@ using System.Text; using System.Text.Json; using System.Threading.Tasks; -using Ghosts.Animator; -using ghosts.api.Areas.Animator.Hubs; -using ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions.Chat.Mattermost; -using ghosts.api.Areas.Animator.Infrastructure.ContentServices; -using ghosts.api.Areas.Animator.Infrastructure.Extensions; -using ghosts.api.Areas.Animator.Infrastructure.Models; +using ghosts.api.Hubs; +using ghosts.api.Infrastructure.Animations.AnimationDefinitions.Chat.Mattermost; +using ghosts.api.Infrastructure.ContentServices; using Ghosts.Api.Infrastructure.Data; +using ghosts.api.Infrastructure.Extensions; using Ghosts.Api.Infrastructure.Extensions; +using ghosts.api.Infrastructure.Models; using Ghosts.Domain.Code.Helpers; using Microsoft.AspNetCore.SignalR; using NLog; -namespace ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions.Chat; +namespace ghosts.api.Infrastructure.Animations.AnimationDefinitions.Chat; public class ChatClient { diff --git a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/ChatConfiguration.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/ChatConfiguration.cs index 3dc291ef..9e19b695 100644 --- a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/ChatConfiguration.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/ChatConfiguration.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; -namespace ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions.Chat; +namespace ghosts.api.Infrastructure.Animations.AnimationDefinitions.Chat; public class ChatJobConfiguration { diff --git a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Channel.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Channel.cs index dcf3d7bb..b5b7b83f 100644 --- a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Channel.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Channel.cs @@ -4,13 +4,13 @@ using System.Collections.Generic; using System.Text.Json.Serialization; -namespace ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions.Chat.Mattermost; +namespace ghosts.api.Infrastructure.Animations.AnimationDefinitions.Chat.Mattermost; public class Channel { [JsonPropertyName("id")] public string Id { get; set; } - [JsonPropertyName("create_at")] public object CreateAt { get; set; } - [JsonPropertyName("update_at")] public object UpdateAt { get; set; } + [JsonPropertyName("create_at")] public long CreateAt { get; set; } + [JsonPropertyName("update_at")] public long UpdateAt { get; set; } [JsonPropertyName("delete_at")] public int DeleteAt { get; set; } [JsonPropertyName("team_id")] public string TeamId { get; set; } [JsonPropertyName("type")] public string Type { get; set; } @@ -18,31 +18,20 @@ public class Channel [JsonPropertyName("name")] public string Name { get; set; } [JsonPropertyName("header")] public string Header { get; set; } [JsonPropertyName("purpose")] public string Purpose { get; set; } - [JsonPropertyName("last_post_at")] public object LastPostAt { get; set; } + [JsonPropertyName("last_post_at")] public long LastPostAt { get; set; } [JsonPropertyName("total_msg_count")] public int TotalMsgCount { get; set; } [JsonPropertyName("extra_update_at")] public int ExtraUpdateAt { get; set; } [JsonPropertyName("creator_id")] public string CreatorId { get; set; } [JsonPropertyName("scheme_id")] public string SchemeId { get; set; } [JsonPropertyName("props")] public object Props { get; set; } - - [JsonPropertyName("group_constrained")] - public bool? GroupConstrained { get; set; } - + [JsonPropertyName("group_constrained")] public bool? GroupConstrained { get; set; } [JsonPropertyName("shared")] public object Shared { get; set; } - - [JsonPropertyName("total_msg_count_root")] - public int TotalMsgCountRoot { get; set; } - + [JsonPropertyName("total_msg_count_root")] public int TotalMsgCountRoot { get; set; } [JsonPropertyName("policy_id")] public object PolicyId { get; set; } - - [JsonPropertyName("last_root_post_at")] - public object LastRootPostAt { get; set; } - - [JsonPropertyName("team_display_name")] - public string TeamDisplayName { get; set; } - + [JsonPropertyName("last_root_post_at")] public long LastRootPostAt { get; set; } + [JsonPropertyName("team_display_name")] public string TeamDisplayName { get; set; } [JsonPropertyName("team_name")] public string TeamName { get; set; } - [JsonPropertyName("team_update_at")] public object TeamUpdateAt { get; set; } + [JsonPropertyName("team_update_at")] public long TeamUpdateAt { get; set; } } public class ChannelHistory diff --git a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Post.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Post.cs index c9932bf9..5b347c8f 100644 --- a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Post.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Post.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text.Json.Serialization; -namespace ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions.Chat.Mattermost; +namespace ghosts.api.Infrastructure.Animations.AnimationDefinitions.Chat.Mattermost; public class PostResponse { diff --git a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Team.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Team.cs index e62de1f7..3c3c4eee 100644 --- a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Team.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/Team.cs @@ -5,7 +5,7 @@ #pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. -namespace ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions.Chat.Mattermost; +namespace ghosts.api.Infrastructure.Animations.AnimationDefinitions.Chat.Mattermost; public class Team { diff --git a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/User.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/User.cs index cf759271..d309c571 100644 --- a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/User.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/Chat/Mattermost/User.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; -namespace ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions.Chat.Mattermost; +namespace ghosts.api.Infrastructure.Animations.AnimationDefinitions.Chat.Mattermost; public class User { diff --git a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs index 009ad211..4d09f6b9 100644 --- a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/ChatJob.cs @@ -6,18 +6,16 @@ using System.Text.Json; using System.Threading; using Ghosts.Animator.Extensions; -using ghosts.api.Areas.Animator.Hubs; -using ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions.Chat; -using ghosts.api.Areas.Animator.Infrastructure.ContentServices; -using ghosts.api.Areas.Animator.Infrastructure.ContentServices.Ollama; -using ghosts.api.Areas.Animator.Infrastructure.Models; +using ghosts.api.Hubs; using Ghosts.Api.Infrastructure; +using ghosts.api.Infrastructure.Animations.AnimationDefinitions.Chat; +using ghosts.api.Infrastructure.ContentServices; using Ghosts.Api.Infrastructure.Data; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.DependencyInjection; using NLog; -namespace ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions; +namespace ghosts.api.Infrastructure.Animations.AnimationDefinitions; public class ChatJob { diff --git a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/FullAutonomyJob.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/FullAutonomyJob.cs index 841cb152..d64cec69 100644 --- a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/FullAutonomyJob.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/FullAutonomyJob.cs @@ -7,16 +7,15 @@ using System.Linq; using System.Threading; using Ghosts.Animator.Extensions; -using ghosts.api.Areas.Animator.Hubs; -using ghosts.api.Areas.Animator.Infrastructure.ContentServices; -using ghosts.api.Areas.Animator.Infrastructure.Models; +using ghosts.api.Hubs; using Ghosts.Api.Infrastructure; +using ghosts.api.Infrastructure.ContentServices; using Ghosts.Api.Infrastructure.Data; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.DependencyInjection; using NLog; -namespace ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions; +namespace ghosts.api.Infrastructure.Animations.AnimationDefinitions; public class FullAutonomyJob { diff --git a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialBeliefJob.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialBeliefJob.cs index 6fd1736a..d461a406 100644 --- a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialBeliefJob.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialBeliefJob.cs @@ -6,15 +6,16 @@ using System.Linq; using System.Threading; using Ghosts.Animator.Extensions; -using ghosts.api.Areas.Animator.Hubs; -using ghosts.api.Areas.Animator.Infrastructure.Models; +using ghosts.api.Areas.Animator.Infrastructure; +using ghosts.api.Hubs; using Ghosts.Api.Infrastructure; using Ghosts.Api.Infrastructure.Data; +using ghosts.api.Infrastructure.Models; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.DependencyInjection; using NLog; -namespace ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions; +namespace ghosts.api.Infrastructure.Animations.AnimationDefinitions; public class SocialBeliefJob { diff --git a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialGraphJob.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialGraphJob.cs index fb7e362f..4f2a25b9 100644 --- a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialGraphJob.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialGraphJob.cs @@ -9,17 +9,17 @@ using System.Threading; using System.Threading.Tasks; using Ghosts.Animator.Extensions; -using ghosts.api.Areas.Animator.Hubs; -using ghosts.api.Areas.Animator.Infrastructure.Models; +using ghosts.api.Hubs; using Ghosts.Api.Infrastructure; using Ghosts.Api.Infrastructure.Data; +using ghosts.api.Infrastructure.Models; using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using NLog; using Weighted_Randomizer; -namespace ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions; +namespace ghosts.api.Infrastructure.Animations.AnimationDefinitions; public class SocialGraphJob { diff --git a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs index 0b8d2349..d7dfa25d 100644 --- a/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationDefinitions/SocialSharingJob.cs @@ -8,10 +8,9 @@ using System.Threading; using System.Threading.Tasks; using Ghosts.Animator.Extensions; -using ghosts.api.Areas.Animator.Hubs; -using ghosts.api.Areas.Animator.Infrastructure.ContentServices; -using ghosts.api.Areas.Animator.Infrastructure.Models; +using ghosts.api.Hubs; using Ghosts.Api.Infrastructure; +using ghosts.api.Infrastructure.ContentServices; using Ghosts.Api.Infrastructure.Data; using ghosts.api.Infrastructure.Models; using ghosts.api.Infrastructure.Services; @@ -22,7 +21,7 @@ using NLog; using RestSharp; -namespace ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions +namespace ghosts.api.Infrastructure.Animations.AnimationDefinitions { public class SocialSharingJob { diff --git a/src/Ghosts.Api/Infrastructure/Animations/AnimationsManager.cs b/src/Ghosts.Api/Infrastructure/Animations/AnimationsManager.cs index cd021f59..9f19c5a5 100644 --- a/src/Ghosts.Api/Infrastructure/Animations/AnimationsManager.cs +++ b/src/Ghosts.Api/Infrastructure/Animations/AnimationsManager.cs @@ -7,9 +7,9 @@ using System.Threading; using System.Threading.Tasks; using Ghosts.Api; -using ghosts.api.Areas.Animator.Hubs; -using ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationDefinitions; +using ghosts.api.Hubs; using Ghosts.Api.Infrastructure; +using ghosts.api.Infrastructure.Animations.AnimationDefinitions; using ghosts.api.Infrastructure.Extensions; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.DependencyInjection; @@ -18,7 +18,7 @@ using Newtonsoft.Json.Converters; using NLog; -namespace ghosts.api.Areas.Animator.Infrastructure.Animations; +namespace ghosts.api.Infrastructure.Animations; public interface IManageableHostedService : IHostedService { diff --git a/src/Ghosts.Api/Infrastructure/ApIDetails.cs b/src/Ghosts.Api/Infrastructure/ApIDetails.cs index 575894f8..89c690b4 100755 --- a/src/Ghosts.Api/Infrastructure/ApIDetails.cs +++ b/src/Ghosts.Api/Infrastructure/ApIDetails.cs @@ -29,7 +29,6 @@ public static void LoadConfiguration() config.GetSection("InitSettings").Bind(initConfig); Program.ApplicationSettings = appConfig; - Program.InitSettings = initConfig; } } } \ No newline at end of file diff --git a/src/Ghosts.Api/Infrastructure/ContentServices/ContentCreationService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/ContentCreationService.cs index ad13b6fc..1170440d 100644 --- a/src/Ghosts.Api/Infrastructure/ContentServices/ContentCreationService.cs +++ b/src/Ghosts.Api/Infrastructure/ContentServices/ContentCreationService.cs @@ -2,14 +2,14 @@ using System; using System.Threading.Tasks; -using ghosts.api.Areas.Animator.Infrastructure.ContentServices.Ollama; -using ghosts.api.Areas.Animator.Infrastructure.ContentServices.OpenAi; -using ghosts.api.Areas.Animator.Infrastructure.ContentServices.Shadows; -using ghosts.api.Areas.Animator.Infrastructure.Models; using Ghosts.Api.Infrastructure; +using ghosts.api.Infrastructure.ContentServices.Ollama; +using ghosts.api.Infrastructure.ContentServices.OpenAi; +using ghosts.api.Infrastructure.ContentServices.Shadows; +using ghosts.api.Infrastructure.Models; using NLog; -namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices; +namespace ghosts.api.Infrastructure.ContentServices; public class ContentCreationService { diff --git a/src/Ghosts.Api/Infrastructure/ContentServices/GenericContentHelpers.cs b/src/Ghosts.Api/Infrastructure/ContentServices/GenericContentHelpers.cs index 60f47ac6..43605379 100644 --- a/src/Ghosts.Api/Infrastructure/ContentServices/GenericContentHelpers.cs +++ b/src/Ghosts.Api/Infrastructure/ContentServices/GenericContentHelpers.cs @@ -1,9 +1,9 @@ // Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. -using ghosts.api.Areas.Animator.Infrastructure.Models; +using ghosts.api.Infrastructure.Models; using Newtonsoft.Json; -namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices; +namespace ghosts.api.Infrastructure.ContentServices; public class GenericContentHelpers { diff --git a/src/Ghosts.Api/Infrastructure/ContentServices/IContentService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/IContentService.cs index 1050ba16..f2617764 100644 --- a/src/Ghosts.Api/Infrastructure/ContentServices/IContentService.cs +++ b/src/Ghosts.Api/Infrastructure/ContentServices/IContentService.cs @@ -1,6 +1,8 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System.Threading.Tasks; -namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices; +namespace ghosts.api.Infrastructure.ContentServices; public interface IContentService { diff --git a/src/Ghosts.Api/Infrastructure/ContentServices/IFormatterService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/IFormatterService.cs index 86c0e06c..edd213db 100644 --- a/src/Ghosts.Api/Infrastructure/ContentServices/IFormatterService.cs +++ b/src/Ghosts.Api/Infrastructure/ContentServices/IFormatterService.cs @@ -1,7 +1,9 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System.Threading.Tasks; -using ghosts.api.Areas.Animator.Infrastructure.Models; +using ghosts.api.Infrastructure.Models; -namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices; +namespace ghosts.api.Infrastructure.ContentServices; public interface IFormatterService { diff --git a/src/Ghosts.Api/Infrastructure/ContentServices/Native/NativeContentFormatterService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/Native/NativeContentFormatterService.cs index 9ea6a741..5366c021 100644 --- a/src/Ghosts.Api/Infrastructure/ContentServices/Native/NativeContentFormatterService.cs +++ b/src/Ghosts.Api/Infrastructure/ContentServices/Native/NativeContentFormatterService.cs @@ -1,13 +1,15 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System; using System.Linq; using System.Threading.Tasks; using Ghosts.Animator; using Ghosts.Animator.Extensions; using Ghosts.Animator.Models; -using ghosts.api.Areas.Animator.Infrastructure.Models; +using ghosts.api.Infrastructure.Models; using NLog; -namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.Native; +namespace ghosts.api.Infrastructure.ContentServices.Native; public class NativeContentFormatterService : IFormatterService { diff --git a/src/Ghosts.Api/Infrastructure/ContentServices/Ollama/OllamaConnectorService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/Ollama/OllamaConnectorService.cs index d53860c9..aba829c4 100644 --- a/src/Ghosts.Api/Infrastructure/ContentServices/Ollama/OllamaConnectorService.cs +++ b/src/Ghosts.Api/Infrastructure/ContentServices/Ollama/OllamaConnectorService.cs @@ -13,7 +13,7 @@ using NLog; using JsonSerializer = System.Text.Json.JsonSerializer; -namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.Ollama; +namespace ghosts.api.Infrastructure.ContentServices.Ollama; public class OllamaConnectorService : IContentService { diff --git a/src/Ghosts.Api/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs index 443be8f3..2d0fc638 100644 --- a/src/Ghosts.Api/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs +++ b/src/Ghosts.Api/Infrastructure/ContentServices/Ollama/OllamaFormatterService.cs @@ -1,13 +1,15 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System; using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; -using ghosts.api.Areas.Animator.Infrastructure.Models; using Ghosts.Api.Infrastructure; +using ghosts.api.Infrastructure.Models; using NLog; -namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.Ollama; +namespace ghosts.api.Infrastructure.ContentServices.Ollama; public class OllamaFormatterService : IFormatterService { diff --git a/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIConnectorService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIConnectorService.cs index 2c8dbf7c..e9851400 100644 --- a/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIConnectorService.cs +++ b/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIConnectorService.cs @@ -1,3 +1,5 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System.Collections.Generic; using System.Linq; using System.Net; @@ -9,7 +11,7 @@ using OpenAI.Managers; using OpenAI.ObjectModels.RequestModels; -namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.OpenAi; +namespace ghosts.api.Infrastructure.ContentServices.OpenAi; public class OpenAiConnectorService : IContentService { diff --git a/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIFormatterService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIFormatterService.cs index 53ad4bf4..ef370800 100644 --- a/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIFormatterService.cs +++ b/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIFormatterService.cs @@ -1,11 +1,13 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -using ghosts.api.Areas.Animator.Infrastructure.Models; +using ghosts.api.Infrastructure.Models; using NLog; using OpenAI.ObjectModels.RequestModels; -namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.OpenAi; +namespace ghosts.api.Infrastructure.ContentServices.OpenAi; public class OpenAiFormatterService : IFormatterService { diff --git a/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIHelpers.cs b/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIHelpers.cs index d0ebb7c5..3f2c3494 100644 --- a/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIHelpers.cs +++ b/src/Ghosts.Api/Infrastructure/ContentServices/OpenAi/OpenAIHelpers.cs @@ -1,6 +1,8 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System; -namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.OpenAi; +namespace ghosts.api.Infrastructure.ContentServices.OpenAi; public static class OpenAiHelpers { diff --git a/src/Ghosts.Api/Infrastructure/ContentServices/Shadows/ShadowsConnectorService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/Shadows/ShadowsConnectorService.cs index a62c080c..565d018e 100644 --- a/src/Ghosts.Api/Infrastructure/ContentServices/Shadows/ShadowsConnectorService.cs +++ b/src/Ghosts.Api/Infrastructure/ContentServices/Shadows/ShadowsConnectorService.cs @@ -13,7 +13,7 @@ using NLog; using JsonSerializer = System.Text.Json.JsonSerializer; -namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.Shadows; +namespace ghosts.api.Infrastructure.ContentServices.Shadows; public class ShadowsConnectorService : IContentService { diff --git a/src/Ghosts.Api/Infrastructure/ContentServices/Shadows/ShadowsFormatterService.cs b/src/Ghosts.Api/Infrastructure/ContentServices/Shadows/ShadowsFormatterService.cs index 83a4cd77..bdd1bd70 100644 --- a/src/Ghosts.Api/Infrastructure/ContentServices/Shadows/ShadowsFormatterService.cs +++ b/src/Ghosts.Api/Infrastructure/ContentServices/Shadows/ShadowsFormatterService.cs @@ -1,13 +1,15 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System; using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; -using ghosts.api.Areas.Animator.Infrastructure.Models; using Ghosts.Api.Infrastructure; +using ghosts.api.Infrastructure.Models; using NLog; -namespace ghosts.api.Areas.Animator.Infrastructure.ContentServices.Shadows; +namespace ghosts.api.Infrastructure.ContentServices.Shadows; public class ShadowsFormatterService : IFormatterService { diff --git a/src/Ghosts.Api/Infrastructure/Examples.cs b/src/Ghosts.Api/Infrastructure/Examples.cs new file mode 100644 index 00000000..7eb5d0e3 --- /dev/null +++ b/src/Ghosts.Api/Infrastructure/Examples.cs @@ -0,0 +1,50 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + +using System; +using System.IO; +using Ghosts.Api.Infrastructure.Data; +using ghosts.api.Infrastructure.Models; +using Ghosts.Domain; +using Ghosts.Domain.Code; +using System.Linq; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using Swashbuckle.AspNetCore.Filters; + +namespace ghosts.api.Infrastructure; + +public class MachineUpdateExample : IExamplesProvider +{ + private readonly IServiceProvider _serviceProvider; + + public MachineUpdateExample(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public MachineUpdate GetExamples() + { + using var scope = _serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); + var machineId = context.Machines + .Select(m => (Guid?)m.Id) // Cast to nullable Guid + .FirstOrDefaultAsync() + .Result ?? Guid.Empty; // Default to Guid.Empty if no machine found + + var o = File.ReadAllText(Path.Combine(ApplicationDetails.InstalledPath, "config", "timelines", "BrowserFirefox.json")); + var timeline = JsonConvert.DeserializeObject(o); + timeline.Id = Guid.NewGuid(); + timeline.Status = Timeline.TimelineStatus.Run; + + return new MachineUpdate + { + MachineId = machineId, + ActiveUtc = DateTime.UtcNow, + CreatedUtc = DateTime.UtcNow, + Status = StatusType.Active, + Type = UpdateClientConfig.UpdateType.TimelinePartial, + Update = timeline + }; + } +} diff --git a/src/Ghosts.Api/Infrastructure/Exceptions.cs b/src/Ghosts.Api/Infrastructure/Exceptions.cs deleted file mode 100644 index 89066cb5..00000000 --- a/src/Ghosts.Api/Infrastructure/Exceptions.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. - -using System; - -namespace Ghosts.Api.Infrastructure -{ - public class Exceptions - { - public class GhostsClientFormattingException : ArgumentException - { - public GhostsClientFormattingException() { } - - public GhostsClientFormattingException(string message) : base(message) { } - } - } -} \ No newline at end of file diff --git a/src/Ghosts.Api/Infrastructure/Extensions/DateTimeExtensions.cs b/src/Ghosts.Api/Infrastructure/Extensions/DateTimeExtensions.cs index f10b591f..f2bdc3b2 100644 --- a/src/Ghosts.Api/Infrastructure/Extensions/DateTimeExtensions.cs +++ b/src/Ghosts.Api/Infrastructure/Extensions/DateTimeExtensions.cs @@ -1,6 +1,8 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System; -namespace ghosts.api.Areas.Animator.Infrastructure.Extensions; +namespace ghosts.api.Infrastructure.Extensions; public static class DateTimeExtensions { diff --git a/src/Ghosts.Api/Infrastructure/Extensions/DictionaryExtensions.cs b/src/Ghosts.Api/Infrastructure/Extensions/DictionaryExtensions.cs index 77acf441..b1efb7f3 100644 --- a/src/Ghosts.Api/Infrastructure/Extensions/DictionaryExtensions.cs +++ b/src/Ghosts.Api/Infrastructure/Extensions/DictionaryExtensions.cs @@ -1,3 +1,5 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System.Collections.Generic; using System.Text; diff --git a/src/Ghosts.Api/Infrastructure/Extensions/EnumeratorExtensions.cs b/src/Ghosts.Api/Infrastructure/Extensions/EnumeratorExtensions.cs index fe76fc41..8d513152 100644 --- a/src/Ghosts.Api/Infrastructure/Extensions/EnumeratorExtensions.cs +++ b/src/Ghosts.Api/Infrastructure/Extensions/EnumeratorExtensions.cs @@ -1,7 +1,9 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System; using System.Collections.Generic; -namespace ghosts.api.Areas.Animator.Infrastructure.Extensions; +namespace ghosts.api.Infrastructure.Extensions; public static class EnumeratorExtensions { diff --git a/src/Ghosts.Api/Infrastructure/Extensions/JsonExtensions.cs b/src/Ghosts.Api/Infrastructure/Extensions/JsonExtensions.cs index 86d90383..73296996 100644 --- a/src/Ghosts.Api/Infrastructure/Extensions/JsonExtensions.cs +++ b/src/Ghosts.Api/Infrastructure/Extensions/JsonExtensions.cs @@ -1,3 +1,5 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using Newtonsoft.Json; namespace Ghosts.Api.Infrastructure.Extensions; diff --git a/src/Ghosts.Api/Infrastructure/Extensions/StringExtensions.cs b/src/Ghosts.Api/Infrastructure/Extensions/StringExtensions.cs index c06ed376..ceaf2e8a 100644 --- a/src/Ghosts.Api/Infrastructure/Extensions/StringExtensions.cs +++ b/src/Ghosts.Api/Infrastructure/Extensions/StringExtensions.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; -using ghosts.api.Areas.Animator.Infrastructure.Extensions; +using ghosts.api.Infrastructure.Extensions; using Newtonsoft.Json; using NPOI.SS.Formula.Functions; using Match = System.Text.RegularExpressions.Match; diff --git a/src/Ghosts.Api/Infrastructure/Extensions/ZipExtensions.cs b/src/Ghosts.Api/Infrastructure/Extensions/ZipExtensions.cs index ed9f2916..0c88a54c 100644 --- a/src/Ghosts.Api/Infrastructure/Extensions/ZipExtensions.cs +++ b/src/Ghosts.Api/Infrastructure/Extensions/ZipExtensions.cs @@ -1,3 +1,5 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System.IO; using System.IO.Compression; diff --git a/src/Ghosts.Api/Infrastructure/Filters/CustomDocumentFilter.cs b/src/Ghosts.Api/Infrastructure/Filters/CustomDocumentFilter.cs index f9df2397..1d0f7ec0 100644 --- a/src/Ghosts.Api/Infrastructure/Filters/CustomDocumentFilter.cs +++ b/src/Ghosts.Api/Infrastructure/Filters/CustomDocumentFilter.cs @@ -1,3 +1,5 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System.Linq; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; diff --git a/src/Ghosts.Api/Infrastructure/GroupNames.cs b/src/Ghosts.Api/Infrastructure/GroupNames.cs index 5d176a48..15912b82 100644 --- a/src/Ghosts.Api/Infrastructure/GroupNames.cs +++ b/src/Ghosts.Api/Infrastructure/GroupNames.cs @@ -11,7 +11,7 @@ namespace Ghosts.Api.Infrastructure { public static class GroupNames { - private static readonly Logger log = LogManager.GetCurrentClassLogger(); + private static readonly Logger _log = LogManager.GetCurrentClassLogger(); private static string FormatToken(List delimeters, ApplicationSettings.GroupingOptions.GroupingDefinitionOption d, string o) { @@ -84,7 +84,7 @@ public static IEnumerable GetGroupNames(Machine machine) } catch (Exception e) { - log.Trace(e); + _log.Trace(e); } return list; diff --git a/src/Ghosts.Api/Infrastructure/Models/EnclaveReducedCsv.cs b/src/Ghosts.Api/Infrastructure/Models/EnclaveReducedCsv.cs index 8b6c7683..abb5c634 100644 --- a/src/Ghosts.Api/Infrastructure/Models/EnclaveReducedCsv.cs +++ b/src/Ghosts.Api/Infrastructure/Models/EnclaveReducedCsv.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Linq; -namespace ghosts.api.Areas.Animator.Infrastructure.Models; +namespace ghosts.api.Infrastructure.Models; public class EnclaveReducedCsv { diff --git a/src/Ghosts.Api/Infrastructure/Models/GenerationConfiguration.cs b/src/Ghosts.Api/Infrastructure/Models/GenerationConfiguration.cs index 05c08662..5e93a242 100644 --- a/src/Ghosts.Api/Infrastructure/Models/GenerationConfiguration.cs +++ b/src/Ghosts.Api/Infrastructure/Models/GenerationConfiguration.cs @@ -6,7 +6,7 @@ using Ghosts.Animator.Models; using Swashbuckle.AspNetCore.Filters; -namespace ghosts.api.Areas.Animator.Infrastructure.Models; +namespace ghosts.api.Infrastructure.Models; /// /// The configuration for generating a large number of NPCs for your scenario diff --git a/src/Ghosts.Api/Infrastructure/Models/InsiderThreatGenerationConfiguration.cs b/src/Ghosts.Api/Infrastructure/Models/InsiderThreatGenerationConfiguration.cs index fb89e67f..d04725c9 100644 --- a/src/Ghosts.Api/Infrastructure/Models/InsiderThreatGenerationConfiguration.cs +++ b/src/Ghosts.Api/Infrastructure/Models/InsiderThreatGenerationConfiguration.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using Ghosts.Animator.Enums; using Ghosts.Animator.Models; +using ghosts.api.Infrastructure.Models; using Swashbuckle.AspNetCore.Filters; namespace ghosts.api.Areas.Animator.Infrastructure.Models; diff --git a/src/Ghosts.Api/Infrastructure/Models/NPC.cs b/src/Ghosts.Api/Infrastructure/Models/NPC.cs index 2a9e2440..24a951db 100644 --- a/src/Ghosts.Api/Infrastructure/Models/NPC.cs +++ b/src/Ghosts.Api/Infrastructure/Models/NPC.cs @@ -1,15 +1,14 @@ // Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. using System; -using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; -using System.Text.Json; using AutoMapper; using Ghosts.Animator.Models; +using ghosts.api.Areas.Animator.Infrastructure.Models; -namespace ghosts.api.Areas.Animator.Infrastructure.Models; +namespace ghosts.api.Infrastructure.Models; [Table("npcs")] public class NpcRecord diff --git a/src/Ghosts.Api/Infrastructure/Models/NPCIpAddress.cs b/src/Ghosts.Api/Infrastructure/Models/NPCIpAddress.cs index ada2e7e4..d22bf7c7 100644 --- a/src/Ghosts.Api/Infrastructure/Models/NPCIpAddress.cs +++ b/src/Ghosts.Api/Infrastructure/Models/NPCIpAddress.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -namespace ghosts.api.Areas.Animator.Infrastructure.Models; +namespace ghosts.api.Infrastructure.Models; [Table("ips")] public class NPCIpAddress diff --git a/src/Ghosts.Api/Infrastructure/Models/NPCNameId.cs b/src/Ghosts.Api/Infrastructure/Models/NPCNameId.cs index 54f13c44..3cd6212a 100644 --- a/src/Ghosts.Api/Infrastructure/Models/NPCNameId.cs +++ b/src/Ghosts.Api/Infrastructure/Models/NPCNameId.cs @@ -2,7 +2,7 @@ using System; -namespace ghosts.api.Areas.Animator.Infrastructure.Models; +namespace ghosts.api.Infrastructure.Models; public class NpcNameId { diff --git a/src/Ghosts.Api/Infrastructure/Models/NPCReduced.cs b/src/Ghosts.Api/Infrastructure/Models/NPCReduced.cs index 7942cd51..2531ee08 100644 --- a/src/Ghosts.Api/Infrastructure/Models/NPCReduced.cs +++ b/src/Ghosts.Api/Infrastructure/Models/NPCReduced.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Reflection; -namespace ghosts.api.Areas.Animator.Infrastructure.Models; +namespace ghosts.api.Infrastructure.Models; [Obsolete("This will move to an Automapper map from NPC to NpcProfileSummary class")] public class NPCReduced diff --git a/src/Ghosts.Api/Infrastructure/Models/NPCToCsv.cs b/src/Ghosts.Api/Infrastructure/Models/NPCToCsv.cs index 3ec361df..5049e4e3 100644 --- a/src/Ghosts.Api/Infrastructure/Models/NPCToCsv.cs +++ b/src/Ghosts.Api/Infrastructure/Models/NPCToCsv.cs @@ -3,7 +3,7 @@ using System; using FileHelpers; -namespace ghosts.api.Areas.Animator.Infrastructure.Models; +namespace ghosts.api.Infrastructure.Models; [DelimitedRecord(",")] public class NPCToCsv diff --git a/src/Ghosts.Api/Infrastructure/Models/NPCToInsiderThreatCsv.cs b/src/Ghosts.Api/Infrastructure/Models/NPCToInsiderThreatCsv.cs index 9ee61b82..9f399109 100644 --- a/src/Ghosts.Api/Infrastructure/Models/NPCToInsiderThreatCsv.cs +++ b/src/Ghosts.Api/Infrastructure/Models/NPCToInsiderThreatCsv.cs @@ -9,7 +9,7 @@ using Ghosts.Animator.Extensions; using Ghosts.Animator.Models.InsiderThreat; -namespace ghosts.api.Areas.Animator.Infrastructure.Models; +namespace ghosts.api.Infrastructure.Models; [DelimitedRecord(",")] public class NPCToInsiderThreatCsv diff --git a/src/Ghosts.Api/Infrastructure/Models/NpcActivity.cs b/src/Ghosts.Api/Infrastructure/Models/NpcActivity.cs index f2887286..fa984341 100644 --- a/src/Ghosts.Api/Infrastructure/Models/NpcActivity.cs +++ b/src/Ghosts.Api/Infrastructure/Models/NpcActivity.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -namespace ghosts.api.Areas.Animator.Infrastructure.Models; +namespace ghosts.api.Infrastructure.Models; [Table("npc_activity")] public class NpcActivity diff --git a/src/Ghosts.Api/Infrastructure/Models/NpcSocialGraph.cs b/src/Ghosts.Api/Infrastructure/Models/NpcSocialGraph.cs index ad3b901b..d26deab2 100644 --- a/src/Ghosts.Api/Infrastructure/Models/NpcSocialGraph.cs +++ b/src/Ghosts.Api/Infrastructure/Models/NpcSocialGraph.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace ghosts.api.Areas.Animator.Infrastructure.Models; +namespace ghosts.api.Infrastructure.Models; public class NpcSocialGraph { diff --git a/src/Ghosts.Api/Infrastructure/Models/TfVarsConfiguration.cs b/src/Ghosts.Api/Infrastructure/Models/TfVarsConfiguration.cs index cbcc97c1..403c2d28 100644 --- a/src/Ghosts.Api/Infrastructure/Models/TfVarsConfiguration.cs +++ b/src/Ghosts.Api/Infrastructure/Models/TfVarsConfiguration.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; -namespace ghosts.api.Areas.Animator.Infrastructure.Models; +namespace ghosts.api.Infrastructure.Models; public class TfVarsConfiguration { diff --git a/src/Ghosts.Api/Infrastructure/Services/MachineUpdateService.cs b/src/Ghosts.Api/Infrastructure/Services/MachineUpdateService.cs index a84689f7..becf5c88 100644 --- a/src/Ghosts.Api/Infrastructure/Services/MachineUpdateService.cs +++ b/src/Ghosts.Api/Infrastructure/Services/MachineUpdateService.cs @@ -11,7 +11,6 @@ using Ghosts.Domain; using Microsoft.EntityFrameworkCore; using NLog; -using NPOI.OpenXmlFormats.Wordprocessing; namespace ghosts.api.Infrastructure.Services { diff --git a/src/Ghosts.Api/Infrastructure/Services/NpcService.cs b/src/Ghosts.Api/Infrastructure/Services/NpcService.cs index c561840c..a84dad07 100644 --- a/src/Ghosts.Api/Infrastructure/Services/NpcService.cs +++ b/src/Ghosts.Api/Infrastructure/Services/NpcService.cs @@ -8,6 +8,7 @@ using Ghosts.Animator.Models; using ghosts.api.Areas.Animator.Infrastructure.Models; using Ghosts.Api.Infrastructure.Data; +using ghosts.api.Infrastructure.Models; using Microsoft.EntityFrameworkCore; using NLog; diff --git a/src/Ghosts.Api/Infrastructure/Services/TimelineService.cs b/src/Ghosts.Api/Infrastructure/Services/TimelineService.cs index 4f0ee4bf..64dce530 100644 --- a/src/Ghosts.Api/Infrastructure/Services/TimelineService.cs +++ b/src/Ghosts.Api/Infrastructure/Services/TimelineService.cs @@ -63,7 +63,7 @@ public async Task StopAsync(Guid machineId, Guid timelineId, CancellationToken c var o = new MachineUpdate { Status = StatusType.Active, - Update = timeline, //JsonConvert.SerializeObject(timeline), + Update = timeline, ActiveUtc = DateTime.UtcNow, CreatedUtc = DateTime.UtcNow, MachineId = machineId, diff --git a/src/Ghosts.Api/Infrastructure/Services/TrackableService.cs b/src/Ghosts.Api/Infrastructure/Services/TrackableService.cs index 37489a23..8cb5b559 100755 --- a/src/Ghosts.Api/Infrastructure/Services/TrackableService.cs +++ b/src/Ghosts.Api/Infrastructure/Services/TrackableService.cs @@ -5,11 +5,9 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Ghosts.Api; using Ghosts.Api.Infrastructure.Data; using ghosts.api.Infrastructure.Models; using Microsoft.EntityFrameworkCore; -using NLog; namespace ghosts.api.Infrastructure.Services { @@ -21,9 +19,7 @@ public interface ITrackableService public class TrackableService : ITrackableService { - private static readonly Logger _log = LogManager.GetCurrentClassLogger(); private readonly ApplicationDbContext _context; - private readonly int _lookBack = Program.ApplicationSettings.LookbackRecords; public TrackableService(ApplicationDbContext context) { diff --git a/src/Ghosts.Api/Infrastructure/WebRequestReader.cs b/src/Ghosts.Api/Infrastructure/WebRequestReader.cs index 1691af43..8787eea6 100644 --- a/src/Ghosts.Api/Infrastructure/WebRequestReader.cs +++ b/src/Ghosts.Api/Infrastructure/WebRequestReader.cs @@ -26,7 +26,7 @@ public static Machine GetMachine(HttpContext context) HostIp = context.Request.Headers["ghosts-ip"], CurrentUsername = CheckIfBase64Encoded(context.Request.Headers["ghosts-user"]), ClientVersion = context.Request.Headers["ghosts-version"], - IPAddress = context.Connection.RemoteIpAddress.ToString(), + IPAddress = context.Connection.RemoteIpAddress?.ToString(), StatusUp = Machine.UpDownStatus.Up }; diff --git a/src/Ghosts.Api/Program.cs b/src/Ghosts.Api/Program.cs index 1127e752..53d0b081 100755 --- a/src/Ghosts.Api/Program.cs +++ b/src/Ghosts.Api/Program.cs @@ -17,8 +17,7 @@ public class Program private static readonly Logger _log = LogManager.GetCurrentClassLogger(); public static ApplicationSettings ApplicationSettings { get; set; } - public static InitOptions InitSettings { get; set; } - + public static void Main(string[] args) { Console.WriteLine(ApplicationDetails.Header); diff --git a/src/Ghosts.Api/Startup.cs b/src/Ghosts.Api/Startup.cs index c7039104..fbf41665 100755 --- a/src/Ghosts.Api/Startup.cs +++ b/src/Ghosts.Api/Startup.cs @@ -1,15 +1,17 @@ +// Copyright 2017 Carnegie Mellon University. All Rights Reserved. See LICENSE.md file for terms. + using System; using System.IO; using System.Reflection; using System.Text.Json.Serialization; -using ghosts.api.Areas.Animator.Hubs; -using ghosts.api.Areas.Animator.Infrastructure.Animations; +using ghosts.api.Hubs; using Ghosts.Api.Hubs; +using ghosts.api.Infrastructure; +using ghosts.api.Infrastructure.Animations; using Ghosts.Api.Infrastructure.Data; using Ghosts.Api.Infrastructure.Extensions; using Ghosts.Api.Infrastructure.Filters; using ghosts.api.Infrastructure.Services; -using Ghosts.Api.ViewModels; using Ghosts.Domain.Code; using Ghosts.Domain.Code.Helpers; using Microsoft.AspNetCore.Builder; @@ -23,7 +25,6 @@ using Microsoft.OpenApi.Models; using Newtonsoft.Json.Converters; using Swashbuckle.AspNetCore.Filters; -using Swashbuckle.AspNetCore.Newtonsoft; namespace Ghosts.Api { @@ -84,6 +85,9 @@ public void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddScoped(); + services.AddScoped(); + services.AddSwaggerExamplesFromAssemblyOf(); + services.AddSingleton(); services.AddSingleton(); @@ -132,7 +136,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseSwaggerUI(c => { c.SwaggerEndpoint($"/swagger/v{ApiVersion}/swagger.json", $"GHOSTS API v{ApiVersion}"); - // c.RoutePrefix = string.Empty; // this places the swagger file at the site root }); } } diff --git a/src/Ghosts.Api/Views/Animations/Index.cshtml b/src/Ghosts.Api/Views/Animations/Index.cshtml index c973ba15..75326ce9 100644 --- a/src/Ghosts.Api/Views/Animations/Index.cshtml +++ b/src/Ghosts.Api/Views/Animations/Index.cshtml @@ -1,5 +1,5 @@ -@using ghosts.api.Areas.Animator.Infrastructure.Animations -@model ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationConfiguration +@using ghosts.api.Infrastructure.Animations +@model ghosts.api.Infrastructure.Animations.AnimationConfiguration

    GHOSTS Animations

    diff --git a/src/Ghosts.Api/Views/Animations/Started.cshtml b/src/Ghosts.Api/Views/Animations/Started.cshtml index cacf4540..ecb83cd0 100644 --- a/src/Ghosts.Api/Views/Animations/Started.cshtml +++ b/src/Ghosts.Api/Views/Animations/Started.cshtml @@ -1,4 +1,4 @@ -@model ghosts.api.Areas.Animator.Infrastructure.Animations.AnimationConfiguration +@model ghosts.api.Infrastructure.Animations.AnimationConfiguration

    Animations!

    diff --git a/src/Ghosts.Api/Views/ViewActivities/Index.cshtml b/src/Ghosts.Api/Views/ViewActivities/Index.cshtml index 2a409e5e..703890d9 100644 --- a/src/Ghosts.Api/Views/ViewActivities/Index.cshtml +++ b/src/Ghosts.Api/Views/ViewActivities/Index.cshtml @@ -1,4 +1,4 @@ -@model IEnumerable +@model IEnumerable