il2ks 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (842) hide show
  1. il2ks-0.1.0/.dockerignore +12 -0
  2. il2ks-0.1.0/.gitattributes +2 -0
  3. il2ks-0.1.0/.github/scripts/run-installer.ps1 +40 -0
  4. il2ks-0.1.0/.github/workflows/ci.yml +125 -0
  5. il2ks-0.1.0/.github/workflows/loadtest.yml +38 -0
  6. il2ks-0.1.0/.github/workflows/release.yml +119 -0
  7. il2ks-0.1.0/.github/workflows/windows-installer.yml +232 -0
  8. il2ks-0.1.0/.gitignore +243 -0
  9. il2ks-0.1.0/.pre-commit-config.yaml +13 -0
  10. il2ks-0.1.0/.python-version +1 -0
  11. il2ks-0.1.0/CHANGELOG.md +5 -0
  12. il2ks-0.1.0/CLAUDE.md +65 -0
  13. il2ks-0.1.0/LICENSE +21 -0
  14. il2ks-0.1.0/NOTICE +93 -0
  15. il2ks-0.1.0/PKG-INFO +119 -0
  16. il2ks-0.1.0/README.md +94 -0
  17. il2ks-0.1.0/design_doc/01_context_and_goals.md +58 -0
  18. il2ks-0.1.0/design_doc/02_functional_requirements.md +322 -0
  19. il2ks-0.1.0/design_doc/03_non_functional_requirements.md +85 -0
  20. il2ks-0.1.0/design_doc/04_architecture.md +159 -0
  21. il2ks-0.1.0/design_doc/05_technical_decisions.md +406 -0
  22. il2ks-0.1.0/design_doc/06_data_model.md +280 -0
  23. il2ks-0.1.0/design_doc/07_deployment_and_installation.md +138 -0
  24. il2ks-0.1.0/design_doc/08_development_workflow.md +113 -0
  25. il2ks-0.1.0/design_doc/09_legacy_system_notes.md +97 -0
  26. il2ks-0.1.0/design_doc/10_roadmap.md +358 -0
  27. il2ks-0.1.0/design_doc/11_open_questions.md +33 -0
  28. il2ks-0.1.0/design_doc/12_korea_log_format.md +286 -0
  29. il2ks-0.1.0/design_doc/13_game_rules.md +603 -0
  30. il2ks-0.1.0/design_doc/14_ingest_internals.md +410 -0
  31. il2ks-0.1.0/design_doc/15_visual_assets.md +340 -0
  32. il2ks-0.1.0/design_doc/16_web_and_operations.md +447 -0
  33. il2ks-0.1.0/design_doc/17_achievements.md +340 -0
  34. il2ks-0.1.0/design_doc/README.md +111 -0
  35. il2ks-0.1.0/docker/.env.example +40 -0
  36. il2ks-0.1.0/docker/Dockerfile +75 -0
  37. il2ks-0.1.0/docker/compose.dev.yaml +16 -0
  38. il2ks-0.1.0/docker/compose.yaml +63 -0
  39. il2ks-0.1.0/docker/docker-entrypoint.sh +56 -0
  40. il2ks-0.1.0/docker/smoke-test.sh +119 -0
  41. il2ks-0.1.0/docs/customizing.md +352 -0
  42. il2ks-0.1.0/docs/install-docker.md +194 -0
  43. il2ks-0.1.0/docs/install-windows.md +163 -0
  44. il2ks-0.1.0/docs/install.md +302 -0
  45. il2ks-0.1.0/docs/performance-testing.md +233 -0
  46. il2ks-0.1.0/docs/releasing.md +57 -0
  47. il2ks-0.1.0/docs/reverse-proxy.md +142 -0
  48. il2ks-0.1.0/docs/settings.md +224 -0
  49. il2ks-0.1.0/docs/translating.md +208 -0
  50. il2ks-0.1.0/loadtest/locustfile.py +188 -0
  51. il2ks-0.1.0/loadtest/run.py +106 -0
  52. il2ks-0.1.0/packaging/windows/README.md +103 -0
  53. il2ks-0.1.0/packaging/windows/build.py +373 -0
  54. il2ks-0.1.0/packaging/windows/files/il2ks-admin.cmd +28 -0
  55. il2ks-0.1.0/packaging/windows/files/il2ks.cmd +10 -0
  56. il2ks-0.1.0/packaging/windows/il2ks.iss +804 -0
  57. il2ks-0.1.0/packaging/windows/pins.toml +36 -0
  58. il2ks-0.1.0/packaging/windows/quoting.py +22 -0
  59. il2ks-0.1.0/packaging/windows/winsw.py +84 -0
  60. il2ks-0.1.0/packaging/windows/zones.py +162 -0
  61. il2ks-0.1.0/pyproject.toml +140 -0
  62. il2ks-0.1.0/src/il2ks/__init__.py +3 -0
  63. il2ks-0.1.0/src/il2ks/__main__.py +7 -0
  64. il2ks-0.1.0/src/il2ks/cli.py +537 -0
  65. il2ks-0.1.0/src/il2ks/config.py +729 -0
  66. il2ks-0.1.0/src/il2ks/core/__init__.py +1 -0
  67. il2ks-0.1.0/src/il2ks/core/achievement_rules.py +83 -0
  68. il2ks-0.1.0/src/il2ks/core/achievements.py +473 -0
  69. il2ks-0.1.0/src/il2ks/core/catalog/__init__.py +1 -0
  70. il2ks-0.1.0/src/il2ks/core/catalog/data/ammo.csv +59 -0
  71. il2ks-0.1.0/src/il2ks/core/catalog/data/object_aliases.csv +2 -0
  72. il2ks-0.1.0/src/il2ks/core/catalog/data/object_names_de.csv +436 -0
  73. il2ks-0.1.0/src/il2ks/core/catalog/data/object_names_es.csv +439 -0
  74. il2ks-0.1.0/src/il2ks/core/catalog/data/object_names_fr.csv +437 -0
  75. il2ks-0.1.0/src/il2ks/core/catalog/data/object_names_pt-br.csv +439 -0
  76. il2ks-0.1.0/src/il2ks/core/catalog/data/object_names_ru.csv +470 -0
  77. il2ks-0.1.0/src/il2ks/core/catalog/data/objects.csv +490 -0
  78. il2ks-0.1.0/src/il2ks/core/catalog/data/ordnance.csv +33 -0
  79. il2ks-0.1.0/src/il2ks/core/catalog/data/payload_aliases.csv +13 -0
  80. il2ks-0.1.0/src/il2ks/core/catalog/data/payloads.csv +416 -0
  81. il2ks-0.1.0/src/il2ks/core/catalog/data/weapon_mod_names_de.csv +24 -0
  82. il2ks-0.1.0/src/il2ks/core/catalog/data/weapon_mod_names_es.csv +24 -0
  83. il2ks-0.1.0/src/il2ks/core/catalog/data/weapon_mod_names_fr.csv +24 -0
  84. il2ks-0.1.0/src/il2ks/core/catalog/data/weapon_mod_names_pt-br.csv +24 -0
  85. il2ks-0.1.0/src/il2ks/core/catalog/data/weapon_mod_names_ru.csv +24 -0
  86. il2ks-0.1.0/src/il2ks/core/catalog/data/weapon_mods.csv +34 -0
  87. il2ks-0.1.0/src/il2ks/core/catalog/loader.py +737 -0
  88. il2ks-0.1.0/src/il2ks/core/killboard.py +13 -0
  89. il2ks-0.1.0/src/il2ks/core/logparse/__init__.py +1 -0
  90. il2ks-0.1.0/src/il2ks/core/logparse/events.py +364 -0
  91. il2ks-0.1.0/src/il2ks/core/logparse/files.py +148 -0
  92. il2ks-0.1.0/src/il2ks/core/logparse/parser.py +950 -0
  93. il2ks-0.1.0/src/il2ks/core/logparse/tail.py +69 -0
  94. il2ks-0.1.0/src/il2ks/core/ratings/__init__.py +1 -0
  95. il2ks-0.1.0/src/il2ks/core/ratings/elo.py +191 -0
  96. il2ks-0.1.0/src/il2ks/core/ratings/score.py +171 -0
  97. il2ks-0.1.0/src/il2ks/core/replay/__init__.py +1 -0
  98. il2ks-0.1.0/src/il2ks/core/replay/ammo.py +604 -0
  99. il2ks-0.1.0/src/il2ks/core/replay/areas.py +66 -0
  100. il2ks-0.1.0/src/il2ks/core/replay/attack.py +166 -0
  101. il2ks-0.1.0/src/il2ks/core/replay/breakdown.py +251 -0
  102. il2ks-0.1.0/src/il2ks/core/replay/config.py +71 -0
  103. il2ks-0.1.0/src/il2ks/core/replay/credit.py +87 -0
  104. il2ks-0.1.0/src/il2ks/core/replay/damage.py +99 -0
  105. il2ks-0.1.0/src/il2ks/core/replay/fate.py +414 -0
  106. il2ks-0.1.0/src/il2ks/core/replay/hits.py +108 -0
  107. il2ks-0.1.0/src/il2ks/core/replay/judge.py +264 -0
  108. il2ks-0.1.0/src/il2ks/core/replay/kills.py +236 -0
  109. il2ks-0.1.0/src/il2ks/core/replay/live.py +142 -0
  110. il2ks-0.1.0/src/il2ks/core/replay/model.py +262 -0
  111. il2ks-0.1.0/src/il2ks/core/replay/pve.py +63 -0
  112. il2ks-0.1.0/src/il2ks/core/replay/rams.py +93 -0
  113. il2ks-0.1.0/src/il2ks/core/replay/resolve.py +223 -0
  114. il2ks-0.1.0/src/il2ks/core/replay/result.py +311 -0
  115. il2ks-0.1.0/src/il2ks/core/replay/state.py +523 -0
  116. il2ks-0.1.0/src/il2ks/core/replay/toggles.py +19 -0
  117. il2ks-0.1.0/src/il2ks/core/stat_marks.py +304 -0
  118. il2ks-0.1.0/src/il2ks/core/streaks.py +177 -0
  119. il2ks-0.1.0/src/il2ks/core/tours.py +143 -0
  120. il2ks-0.1.0/src/il2ks/data/il2ks.example.toml +329 -0
  121. il2ks-0.1.0/src/il2ks/db/__init__.py +1 -0
  122. il2ks-0.1.0/src/il2ks/db/apps.py +8 -0
  123. il2ks-0.1.0/src/il2ks/db/copy.py +30 -0
  124. il2ks-0.1.0/src/il2ks/db/migrations/0001_initial.py +3023 -0
  125. il2ks-0.1.0/src/il2ks/db/migrations/__init__.py +0 -0
  126. il2ks-0.1.0/src/il2ks/db/models.py +2039 -0
  127. il2ks-0.1.0/src/il2ks/db/reprocess_requests.py +43 -0
  128. il2ks-0.1.0/src/il2ks/db/site.py +59 -0
  129. il2ks-0.1.0/src/il2ks/db/validators.py +29 -0
  130. il2ks-0.1.0/src/il2ks/devtools/__init__.py +1 -0
  131. il2ks-0.1.0/src/il2ks/devtools/anonymize.py +73 -0
  132. il2ks-0.1.0/src/il2ks/devtools/assets.py +565 -0
  133. il2ks-0.1.0/src/il2ks/devtools/bailout_eval.py +217 -0
  134. il2ks-0.1.0/src/il2ks/devtools/bench.py +221 -0
  135. il2ks-0.1.0/src/il2ks/devtools/check.py +336 -0
  136. il2ks-0.1.0/src/il2ks/devtools/dbdump.py +40 -0
  137. il2ks-0.1.0/src/il2ks/devtools/migrations.py +154 -0
  138. il2ks-0.1.0/src/il2ks/devtools/templates.py +60 -0
  139. il2ks-0.1.0/src/il2ks/devtools/translations.py +354 -0
  140. il2ks-0.1.0/src/il2ks/exitcodes.py +7 -0
  141. il2ks-0.1.0/src/il2ks/ingest/__init__.py +1 -0
  142. il2ks-0.1.0/src/il2ks/ingest/achievements.py +479 -0
  143. il2ks-0.1.0/src/il2ks/ingest/activity.py +54 -0
  144. il2ks-0.1.0/src/il2ks/ingest/aggregates.py +647 -0
  145. il2ks-0.1.0/src/il2ks/ingest/aircraft_mods.py +166 -0
  146. il2ks-0.1.0/src/il2ks/ingest/aircraft_stats.py +788 -0
  147. il2ks-0.1.0/src/il2ks/ingest/archive.py +183 -0
  148. il2ks-0.1.0/src/il2ks/ingest/batch.py +168 -0
  149. il2ks-0.1.0/src/il2ks/ingest/builds.py +78 -0
  150. il2ks-0.1.0/src/il2ks/ingest/counters.py +135 -0
  151. il2ks-0.1.0/src/il2ks/ingest/dbutil.py +92 -0
  152. il2ks-0.1.0/src/il2ks/ingest/discover.py +187 -0
  153. il2ks-0.1.0/src/il2ks/ingest/flight_score.py +39 -0
  154. il2ks-0.1.0/src/il2ks/ingest/identity.py +97 -0
  155. il2ks-0.1.0/src/il2ks/ingest/live.py +468 -0
  156. il2ks-0.1.0/src/il2ks/ingest/lock.py +185 -0
  157. il2ks-0.1.0/src/il2ks/ingest/pairs.py +191 -0
  158. il2ks-0.1.0/src/il2ks/ingest/persist.py +911 -0
  159. il2ks-0.1.0/src/il2ks/ingest/rating_games.py +43 -0
  160. il2ks-0.1.0/src/il2ks/ingest/ratings.py +186 -0
  161. il2ks-0.1.0/src/il2ks/ingest/reprocess.py +303 -0
  162. il2ks-0.1.0/src/il2ks/ingest/reprocess_requests.py +104 -0
  163. il2ks-0.1.0/src/il2ks/ingest/rollup.py +125 -0
  164. il2ks-0.1.0/src/il2ks/ingest/rule_store.py +167 -0
  165. il2ks-0.1.0/src/il2ks/ingest/runner.py +417 -0
  166. il2ks-0.1.0/src/il2ks/ingest/score_apply.py +44 -0
  167. il2ks-0.1.0/src/il2ks/ingest/scoring.py +80 -0
  168. il2ks-0.1.0/src/il2ks/ingest/stat_marks.py +181 -0
  169. il2ks-0.1.0/src/il2ks/ingest/streaks.py +343 -0
  170. il2ks-0.1.0/src/il2ks/ingest/timeutil.py +86 -0
  171. il2ks-0.1.0/src/il2ks/ingest/tours.py +425 -0
  172. il2ks-0.1.0/src/il2ks/ingest/type_board.py +158 -0
  173. il2ks-0.1.0/src/il2ks/ingest/watch.py +153 -0
  174. il2ks-0.1.0/src/il2ks/ingest/worker.py +45 -0
  175. il2ks-0.1.0/src/il2ks/locale/de/LC_MESSAGES/django.mo +0 -0
  176. il2ks-0.1.0/src/il2ks/locale/de/LC_MESSAGES/django.po +6781 -0
  177. il2ks-0.1.0/src/il2ks/locale/es/LC_MESSAGES/django.mo +0 -0
  178. il2ks-0.1.0/src/il2ks/locale/es/LC_MESSAGES/django.po +6767 -0
  179. il2ks-0.1.0/src/il2ks/locale/fr/LC_MESSAGES/django.mo +0 -0
  180. il2ks-0.1.0/src/il2ks/locale/fr/LC_MESSAGES/django.po +6798 -0
  181. il2ks-0.1.0/src/il2ks/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  182. il2ks-0.1.0/src/il2ks/locale/pt_BR/LC_MESSAGES/django.po +6747 -0
  183. il2ks-0.1.0/src/il2ks/locale/ru/LC_MESSAGES/django.mo +0 -0
  184. il2ks-0.1.0/src/il2ks/locale/ru/LC_MESSAGES/django.po +6754 -0
  185. il2ks-0.1.0/src/il2ks/logsetup.py +186 -0
  186. il2ks-0.1.0/src/il2ks/ops/__init__.py +1 -0
  187. il2ks-0.1.0/src/il2ks/ops/admin.py +108 -0
  188. il2ks-0.1.0/src/il2ks/ops/backup.py +478 -0
  189. il2ks-0.1.0/src/il2ks/ops/checks.py +552 -0
  190. il2ks-0.1.0/src/il2ks/ops/commands.py +293 -0
  191. il2ks-0.1.0/src/il2ks/ops/dbfile.py +58 -0
  192. il2ks-0.1.0/src/il2ks/ops/detect.py +181 -0
  193. il2ks-0.1.0/src/il2ks/ops/doctor.py +54 -0
  194. il2ks-0.1.0/src/il2ks/ops/migrate.py +250 -0
  195. il2ks-0.1.0/src/il2ks/ops/prompt.py +63 -0
  196. il2ks-0.1.0/src/il2ks/ops/report.py +86 -0
  197. il2ks-0.1.0/src/il2ks/ops/serving_checks.py +267 -0
  198. il2ks-0.1.0/src/il2ks/ops/setup.py +521 -0
  199. il2ks-0.1.0/src/il2ks/ops/template.py +133 -0
  200. il2ks-0.1.0/src/il2ks/queries/__init__.py +1 -0
  201. il2ks-0.1.0/src/il2ks/queries/achievements.py +85 -0
  202. il2ks-0.1.0/src/il2ks/queries/activity.py +24 -0
  203. il2ks-0.1.0/src/il2ks/queries/aircraft.py +525 -0
  204. il2ks-0.1.0/src/il2ks/queries/ammo.py +261 -0
  205. il2ks-0.1.0/src/il2ks/queries/boards.py +180 -0
  206. il2ks-0.1.0/src/il2ks/queries/builds.py +54 -0
  207. il2ks-0.1.0/src/il2ks/queries/leaderboards.py +393 -0
  208. il2ks-0.1.0/src/il2ks/queries/live.py +114 -0
  209. il2ks-0.1.0/src/il2ks/queries/missions.py +207 -0
  210. il2ks-0.1.0/src/il2ks/queries/paging.py +15 -0
  211. il2ks-0.1.0/src/il2ks/queries/players.py +243 -0
  212. il2ks-0.1.0/src/il2ks/queries/sorties.py +217 -0
  213. il2ks-0.1.0/src/il2ks/queries/sorting.py +76 -0
  214. il2ks-0.1.0/src/il2ks/queries/stat_marks.py +29 -0
  215. il2ks-0.1.0/src/il2ks/queries/tours.py +184 -0
  216. il2ks-0.1.0/src/il2ks/rule_settings.py +219 -0
  217. il2ks-0.1.0/src/il2ks/serving/__init__.py +2 -0
  218. il2ks-0.1.0/src/il2ks/serving/_vendor/LICENSE-rjsmin-rcssmin.txt +201 -0
  219. il2ks-0.1.0/src/il2ks/serving/_vendor/__init__.py +1 -0
  220. il2ks-0.1.0/src/il2ks/serving/_vendor/rcssmin.py +436 -0
  221. il2ks-0.1.0/src/il2ks/serving/_vendor/rjsmin.py +594 -0
  222. il2ks-0.1.0/src/il2ks/serving/bootid.py +25 -0
  223. il2ks-0.1.0/src/il2ks/serving/caddy.py +219 -0
  224. il2ks-0.1.0/src/il2ks/serving/commands.py +653 -0
  225. il2ks-0.1.0/src/il2ks/serving/custom.py +395 -0
  226. il2ks-0.1.0/src/il2ks/serving/djsettings.py +130 -0
  227. il2ks-0.1.0/src/il2ks/serving/procutil.py +257 -0
  228. il2ks-0.1.0/src/il2ks/serving/secret.py +50 -0
  229. il2ks-0.1.0/src/il2ks/serving/service.py +160 -0
  230. il2ks-0.1.0/src/il2ks/serving/setup_token.py +195 -0
  231. il2ks-0.1.0/src/il2ks/serving/storage.py +70 -0
  232. il2ks-0.1.0/src/il2ks/serving/supervisor.py +269 -0
  233. il2ks-0.1.0/src/il2ks/serving/templateversions.py +303 -0
  234. il2ks-0.1.0/src/il2ks/serving/webserver.py +71 -0
  235. il2ks-0.1.0/src/il2ks/settings.py +173 -0
  236. il2ks-0.1.0/src/il2ks/urls.py +11 -0
  237. il2ks-0.1.0/src/il2ks/web/__init__.py +1 -0
  238. il2ks-0.1.0/src/il2ks/web/achievement_config.py +112 -0
  239. il2ks-0.1.0/src/il2ks/web/admin.py +802 -0
  240. il2ks-0.1.0/src/il2ks/web/admin_achievements.py +196 -0
  241. il2ks-0.1.0/src/il2ks/web/admin_config.py +8 -0
  242. il2ks-0.1.0/src/il2ks/web/admin_quips.py +170 -0
  243. il2ks-0.1.0/src/il2ks/web/admin_rules.py +178 -0
  244. il2ks-0.1.0/src/il2ks/web/admin_score.py +28 -0
  245. il2ks-0.1.0/src/il2ks/web/admin_site.py +298 -0
  246. il2ks-0.1.0/src/il2ks/web/apps.py +6 -0
  247. il2ks-0.1.0/src/il2ks/web/branding_images.py +140 -0
  248. il2ks-0.1.0/src/il2ks/web/caching.py +124 -0
  249. il2ks-0.1.0/src/il2ks/web/chart_data.py +84 -0
  250. il2ks-0.1.0/src/il2ks/web/charts.py +197 -0
  251. il2ks-0.1.0/src/il2ks/web/column_hints.py +209 -0
  252. il2ks-0.1.0/src/il2ks/web/columns.py +295 -0
  253. il2ks-0.1.0/src/il2ks/web/context_processors.py +119 -0
  254. il2ks-0.1.0/src/il2ks/web/display.py +324 -0
  255. il2ks-0.1.0/src/il2ks/web/feature_image.py +307 -0
  256. il2ks-0.1.0/src/il2ks/web/flavor.py +458 -0
  257. il2ks-0.1.0/src/il2ks/web/fonts.py +146 -0
  258. il2ks-0.1.0/src/il2ks/web/ground.py +58 -0
  259. il2ks-0.1.0/src/il2ks/web/icons.py +140 -0
  260. il2ks-0.1.0/src/il2ks/web/ingest_status.py +100 -0
  261. il2ks-0.1.0/src/il2ks/web/logo.py +128 -0
  262. il2ks-0.1.0/src/il2ks/web/medals.py +380 -0
  263. il2ks-0.1.0/src/il2ks/web/media.py +59 -0
  264. il2ks-0.1.0/src/il2ks/web/object_names.py +33 -0
  265. il2ks-0.1.0/src/il2ks/web/pve.py +84 -0
  266. il2ks-0.1.0/src/il2ks/web/quips.py +140 -0
  267. il2ks-0.1.0/src/il2ks/web/setup_forms.py +154 -0
  268. il2ks-0.1.0/src/il2ks/web/site_forms.py +473 -0
  269. il2ks-0.1.0/src/il2ks/web/sortie_view.py +870 -0
  270. il2ks-0.1.0/src/il2ks/web/static/il2ks/il2ks.js +209 -0
  271. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/README.md +130 -0
  272. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/aircraft/generic-jet.svg +1 -0
  273. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/aircraft/generic-prop.svg +1 -0
  274. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/aircraft/unknown.svg +1 -0
  275. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/brand/favicon.svg +1 -0
  276. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/brand/logo-mark.svg +1 -0
  277. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/coalition/blufor.svg +11 -0
  278. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/coalition/insignia/kpaf.svg +1 -0
  279. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/coalition/insignia/plaaf.svg +1 -0
  280. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/coalition/insignia/rokaf.svg +1 -0
  281. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/coalition/insignia/un.svg +1 -0
  282. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/coalition/insignia/usaf.svg +1 -0
  283. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/coalition/insignia/vvs.svg +1 -0
  284. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/coalition/redfor.svg +11 -0
  285. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/assist.svg +14 -0
  286. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/bailout.svg +14 -0
  287. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/bomb-release.svg +13 -0
  288. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/damaged.svg +12 -0
  289. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/destroyed.svg +11 -0
  290. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/disconnect.svg +18 -0
  291. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/friendly-fire.svg +13 -0
  292. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/kill-air.svg +16 -0
  293. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/kill-ground.svg +13 -0
  294. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/landing.svg +12 -0
  295. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/ram.svg +18 -0
  296. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/rocket-salvo.svg +13 -0
  297. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/sortie-end.svg +13 -0
  298. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/spawn.svg +13 -0
  299. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/event/takeoff.svg +12 -0
  300. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/flag/br.svg +45 -0
  301. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/flag/de.svg +5 -0
  302. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/flag/es.svg +4 -0
  303. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/flag/fr.svg +5 -0
  304. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/flag/ru.svg +5 -0
  305. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/flag/us.svg +9 -0
  306. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/ground/aaa.svg +1 -0
  307. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/ground/artillery.svg +1 -0
  308. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/ground/building.svg +18 -0
  309. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/ground/other-static.svg +19 -0
  310. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/ground/parked-aircraft.svg +11 -0
  311. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/ground/ship.svg +14 -0
  312. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/ground/tank.svg +13 -0
  313. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/ground/train.svg +17 -0
  314. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/ground/vehicle.svg +13 -0
  315. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/illustration/404.svg +1 -0
  316. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/illustration/500.svg +1 -0
  317. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/illustration/empty.svg +1 -0
  318. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/ace-in-a-day.svg +19 -0
  319. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/career-kills.svg +16 -0
  320. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/damaged-landing.svg +15 -0
  321. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/elo-peak.svg +12 -0
  322. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/first-blood.svg +11 -0
  323. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/flight-hours.svg +12 -0
  324. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/frequent-flyer.svg +12 -0
  325. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/ground-score.svg +14 -0
  326. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/ground-sortie.svg +11 -0
  327. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/landing-streak.svg +12 -0
  328. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/life-kills.svg +14 -0
  329. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/multi-kill.svg +12 -0
  330. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/ram.svg +18 -0
  331. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/regular.svg +21 -0
  332. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/shame-crashed.svg +13 -0
  333. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/shame-friendly.svg +14 -0
  334. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/shame-strafed.svg +11 -0
  335. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/shame-taxi.svg +15 -0
  336. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/sortie-kills.svg +15 -0
  337. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/strike-hunter.svg +12 -0
  338. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/survivor.svg +12 -0
  339. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/tank-buster.svg +13 -0
  340. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/tours-in-a-row.svg +12 -0
  341. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/type-veteran.svg +13 -0
  342. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/types-flown.svg +13 -0
  343. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/medal/types-with-kills.svg +16 -0
  344. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/nav/book.svg +15 -0
  345. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/nav/discord.svg +14 -0
  346. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/nav/forum.svg +12 -0
  347. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/nav/github.svg +11 -0
  348. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/nav/link.svg +13 -0
  349. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/nav/mail.svg +12 -0
  350. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/nav/patreon.svg +11 -0
  351. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/nav/steam.svg +12 -0
  352. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/nav/telegram.svg +11 -0
  353. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/nav/twitch.svg +13 -0
  354. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/nav/youtube.svg +12 -0
  355. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/outcome/bailed-out.svg +14 -0
  356. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/outcome/captured.svg +18 -0
  357. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/outcome/crashed.svg +11 -0
  358. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/outcome/dead.svg +11 -0
  359. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/outcome/disconnected.svg +18 -0
  360. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/outcome/ditched.svg +13 -0
  361. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/outcome/exited-on-ground.svg +13 -0
  362. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/outcome/in-flight.svg +12 -0
  363. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/outcome/landed.svg +12 -0
  364. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/outcome/mission-ended.svg +13 -0
  365. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/outcome/not-taken-off.svg +12 -0
  366. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/outcome/shot-down.svg +12 -0
  367. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/outcome/unknown.svg +13 -0
  368. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/outcome/wounded.svg +15 -0
  369. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/pattern/camo.svg +18 -0
  370. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/role/air-superiority.svg +14 -0
  371. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/role/attack.svg +13 -0
  372. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/accuracy.svg +13 -0
  373. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/air-kills.svg +16 -0
  374. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/assists.svg +14 -0
  375. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/bailouts.svg +14 -0
  376. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/captures.svg +18 -0
  377. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/deaths.svg +15 -0
  378. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/elo-jet.svg +12 -0
  379. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/elo-prop.svg +15 -0
  380. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/flight-time.svg +12 -0
  381. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/friendly-fire.svg +15 -0
  382. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/ground-hour.svg +13 -0
  383. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/ground-kills.svg +13 -0
  384. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/interception.svg +14 -0
  385. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/planes-lost.svg +11 -0
  386. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/play-time.svg +14 -0
  387. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/sorties.svg +12 -0
  388. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/strafed.svg +15 -0
  389. il2ks-0.1.0/src/il2ks/web/static/il2ks/img/stat/taxi-accidents.svg +16 -0
  390. il2ks-0.1.0/src/il2ks/web/static/il2ks/leaderboards.css +26 -0
  391. il2ks-0.1.0/src/il2ks/web/static/il2ks/localtime.js +68 -0
  392. il2ks-0.1.0/src/il2ks/web/static/il2ks/missions.css +65 -0
  393. il2ks-0.1.0/src/il2ks/web/static/il2ks/players.css +129 -0
  394. il2ks-0.1.0/src/il2ks/web/static/il2ks/setup.css +24 -0
  395. il2ks-0.1.0/src/il2ks/web/static/il2ks/setup.js +15 -0
  396. il2ks-0.1.0/src/il2ks/web/static/il2ks/site.css +769 -0
  397. il2ks-0.1.0/src/il2ks/web/static/il2ks/sortie.js +15 -0
  398. il2ks-0.1.0/src/il2ks/web/static/il2ks/sorties.css +83 -0
  399. il2ks-0.1.0/src/il2ks/web/static/il2ks/theme-init.js +15 -0
  400. il2ks-0.1.0/src/il2ks/web/static/il2ks/vendor/BarlowCondensed-600.woff2 +0 -0
  401. il2ks-0.1.0/src/il2ks/web/static/il2ks/vendor/BarlowCondensed-700.woff2 +0 -0
  402. il2ks-0.1.0/src/il2ks/web/static/il2ks/vendor/LICENSE-barlow-condensed-OFL.txt +93 -0
  403. il2ks-0.1.0/src/il2ks/web/static/il2ks/vendor/LICENSE-htmx.txt +13 -0
  404. il2ks-0.1.0/src/il2ks/web/static/il2ks/vendor/LICENSE-pico.md +21 -0
  405. il2ks-0.1.0/src/il2ks/web/static/il2ks/vendor/README.md +18 -0
  406. il2ks-0.1.0/src/il2ks/web/static/il2ks/vendor/htmx.min.js +1 -0
  407. il2ks-0.1.0/src/il2ks/web/static/il2ks/vendor/pico.min.css +4 -0
  408. il2ks-0.1.0/src/il2ks/web/static/il2ks_admin/ingest_status.css +15 -0
  409. il2ks-0.1.0/src/il2ks/web/static/il2ks_admin/override_warning.css +12 -0
  410. il2ks-0.1.0/src/il2ks/web/static/il2ks_admin/theme_editor.css +18 -0
  411. il2ks-0.1.0/src/il2ks/web/static/il2ks_admin/theme_editor.js +36 -0
  412. il2ks-0.1.0/src/il2ks/web/svg_symbol.py +128 -0
  413. il2ks-0.1.0/src/il2ks/web/template_versions.json +569 -0
  414. il2ks-0.1.0/src/il2ks/web/templates/404.html +17 -0
  415. il2ks-0.1.0/src/il2ks/web/templates/500.html +27 -0
  416. il2ks-0.1.0/src/il2ks/web/templates/admin/_rule_fields.html +23 -0
  417. il2ks-0.1.0/src/il2ks/web/templates/admin/base_site.html +22 -0
  418. il2ks-0.1.0/src/il2ks/web/templates/admin/il2ks_achievements.html +74 -0
  419. il2ks-0.1.0/src/il2ks/web/templates/admin/il2ks_db/tour/change_list.html +15 -0
  420. il2ks-0.1.0/src/il2ks/web/templates/admin/il2ks_index.html +55 -0
  421. il2ks-0.1.0/src/il2ks/web/templates/admin/il2ks_ingest_status.html +174 -0
  422. il2ks-0.1.0/src/il2ks/web/templates/admin/il2ks_leaderboards.html +21 -0
  423. il2ks-0.1.0/src/il2ks/web/templates/admin/il2ks_quips.html +74 -0
  424. il2ks-0.1.0/src/il2ks/web/templates/admin/il2ks_reprocess_confirm.html +23 -0
  425. il2ks-0.1.0/src/il2ks/web/templates/admin/il2ks_rules.html +21 -0
  426. il2ks-0.1.0/src/il2ks/web/templates/admin/il2ks_score.html +40 -0
  427. il2ks-0.1.0/src/il2ks/web/templates/admin/il2ks_tours.html +41 -0
  428. il2ks-0.1.0/src/il2ks/web/templates/il2ks/achievements/_award.html +5 -0
  429. il2ks-0.1.0/src/il2ks/web/templates/il2ks/achievements/_medal.html +12 -0
  430. il2ks-0.1.0/src/il2ks/web/templates/il2ks/achievements/_ribbon.html +12 -0
  431. il2ks-0.1.0/src/il2ks/web/templates/il2ks/achievements/holders.html +35 -0
  432. il2ks-0.1.0/src/il2ks/web/templates/il2ks/achievements/home_feed.html +24 -0
  433. il2ks-0.1.0/src/il2ks/web/templates/il2ks/achievements/overview.html +38 -0
  434. il2ks-0.1.0/src/il2ks/web/templates/il2ks/aircraft/detail.html +265 -0
  435. il2ks-0.1.0/src/il2ks/web/templates/il2ks/aircraft/list.html +65 -0
  436. il2ks-0.1.0/src/il2ks/web/templates/il2ks/aircraft/parts/ammo_mix_row.html +10 -0
  437. il2ks-0.1.0/src/il2ks/web/templates/il2ks/aircraft/top_elo.html +36 -0
  438. il2ks-0.1.0/src/il2ks/web/templates/il2ks/aircraft/top_ground.html +36 -0
  439. il2ks-0.1.0/src/il2ks/web/templates/il2ks/base.html +100 -0
  440. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/accordion.html +8 -0
  441. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/badge.html +6 -0
  442. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/bar_chart.html +47 -0
  443. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/breadcrumbs.html +9 -0
  444. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/col_hint.html +6 -0
  445. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/col_th.html +10 -0
  446. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/columns_picker.html +17 -0
  447. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/dropdown.html +10 -0
  448. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/empty_row.html +6 -0
  449. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/filter_bar.html +20 -0
  450. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/filter_select.html +10 -0
  451. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/filter_text.html +8 -0
  452. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/kv_list.html +7 -0
  453. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/language_menu.html +11 -0
  454. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/mod_filter.html +12 -0
  455. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/notice.html +9 -0
  456. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/online_now.html +13 -0
  457. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/online_now_body.html +47 -0
  458. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/pagination.html +16 -0
  459. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/pilot_fate.html +6 -0
  460. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/results_region.html +9 -0
  461. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/role_toggle.html +10 -0
  462. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/sort_th.html +10 -0
  463. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/stat_mark.html +9 -0
  464. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/stat_mark_note.html +5 -0
  465. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/stat_tile.html +12 -0
  466. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/tour_absent.html +11 -0
  467. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/tour_filter.html +13 -0
  468. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/tour_next.html +7 -0
  469. il2ks-0.1.0/src/il2ks/web/templates/il2ks/components/tour_select.html +23 -0
  470. il2ks-0.1.0/src/il2ks/web/templates/il2ks/home.html +109 -0
  471. il2ks-0.1.0/src/il2ks/web/templates/il2ks/home_activity.html +10 -0
  472. il2ks-0.1.0/src/il2ks/web/templates/il2ks/home_feature.html +17 -0
  473. il2ks-0.1.0/src/il2ks/web/templates/il2ks/leaderboards/home_block.html +38 -0
  474. il2ks-0.1.0/src/il2ks/web/templates/il2ks/leaderboards/ironman_running.html +26 -0
  475. il2ks-0.1.0/src/il2ks/web/templates/il2ks/leaderboards/list.html +65 -0
  476. il2ks-0.1.0/src/il2ks/web/templates/il2ks/leaderboards/table.html +105 -0
  477. il2ks-0.1.0/src/il2ks/web/templates/il2ks/missions/_player.html +7 -0
  478. il2ks-0.1.0/src/il2ks/web/templates/il2ks/missions/_rows.html +20 -0
  479. il2ks-0.1.0/src/il2ks/web/templates/il2ks/missions/detail.html +136 -0
  480. il2ks-0.1.0/src/il2ks/web/templates/il2ks/missions/list.html +44 -0
  481. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/_killboard_rows.html +10 -0
  482. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/_type_killboard.html +40 -0
  483. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/achievements.html +40 -0
  484. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail.html +59 -0
  485. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_achievements.html +20 -0
  486. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_air_section.html +31 -0
  487. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_air_split.html +8 -0
  488. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_air_tiles.html +14 -0
  489. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_aircraft.html +44 -0
  490. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_aircraft_build.html +16 -0
  491. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_charts.html +12 -0
  492. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_ground.html +29 -0
  493. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_ground_scores.html +13 -0
  494. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_ground_section.html +17 -0
  495. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_ground_tiles.html +17 -0
  496. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_header.html +26 -0
  497. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_killboard.html +34 -0
  498. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_nav.html +13 -0
  499. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_overall.html +15 -0
  500. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_pve.html +50 -0
  501. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_ratios.html +16 -0
  502. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_recent.html +40 -0
  503. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_scores.html +11 -0
  504. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_shame.html +17 -0
  505. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_star_tile.html +13 -0
  506. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_streaks.html +26 -0
  507. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_tiles.html +35 -0
  508. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_totals.html +16 -0
  509. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/detail_type_killboard.html +13 -0
  510. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/killboard.html +49 -0
  511. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/search.html +25 -0
  512. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/search_table.html +36 -0
  513. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/streak_runs.html +57 -0
  514. il2ks-0.1.0/src/il2ks/web/templates/il2ks/players/streaks.html +51 -0
  515. il2ks-0.1.0/src/il2ks/web/templates/il2ks/setup.html +136 -0
  516. il2ks-0.1.0/src/il2ks/web/templates/il2ks/setup_done.html +48 -0
  517. il2ks-0.1.0/src/il2ks/web/templates/il2ks/setup_gate.html +32 -0
  518. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/all.html +50 -0
  519. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/detail.html +32 -0
  520. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/list.html +54 -0
  521. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/aircraft_cell.html +5 -0
  522. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/all_row.html +16 -0
  523. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/ammo.html +72 -0
  524. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/damage.html +20 -0
  525. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/damage_table.html +28 -0
  526. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/header.html +44 -0
  527. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/kill_table.html +17 -0
  528. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/killed_by.html +31 -0
  529. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/kills.html +51 -0
  530. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/list_row.html +18 -0
  531. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/medals.html +16 -0
  532. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/meta.html +15 -0
  533. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/notices.html +20 -0
  534. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/summary.html +39 -0
  535. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/timeline.html +11 -0
  536. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/timeline_table.html +30 -0
  537. il2ks-0.1.0/src/il2ks/web/templates/il2ks/sorties/parts/who.html +9 -0
  538. il2ks-0.1.0/src/il2ks/web/templates/il2ks/styleguide.html +251 -0
  539. il2ks-0.1.0/src/il2ks/web/templates/il2ks_admin/theme_editor.html +22 -0
  540. il2ks-0.1.0/src/il2ks/web/templatetags/il2ks.py +884 -0
  541. il2ks-0.1.0/src/il2ks/web/templatetags/il2ks_achievements.py +85 -0
  542. il2ks-0.1.0/src/il2ks/web/templatetags/il2ks_boards.py +71 -0
  543. il2ks-0.1.0/src/il2ks/web/templatetags/il2ks_live.py +39 -0
  544. il2ks-0.1.0/src/il2ks/web/templatetags/il2ks_sorties.py +25 -0
  545. il2ks-0.1.0/src/il2ks/web/theme.py +384 -0
  546. il2ks-0.1.0/src/il2ks/web/throttle.py +76 -0
  547. il2ks-0.1.0/src/il2ks/web/urls.py +48 -0
  548. il2ks-0.1.0/src/il2ks/web/views/__init__.py +1 -0
  549. il2ks-0.1.0/src/il2ks/web/views/achievements.py +161 -0
  550. il2ks-0.1.0/src/il2ks/web/views/aircraft.py +357 -0
  551. il2ks-0.1.0/src/il2ks/web/views/boards.py +123 -0
  552. il2ks-0.1.0/src/il2ks/web/views/language.py +37 -0
  553. il2ks-0.1.0/src/il2ks/web/views/leaderboards.py +168 -0
  554. il2ks-0.1.0/src/il2ks/web/views/live.py +34 -0
  555. il2ks-0.1.0/src/il2ks/web/views/missions.py +159 -0
  556. il2ks-0.1.0/src/il2ks/web/views/players.py +162 -0
  557. il2ks-0.1.0/src/il2ks/web/views/setup.py +252 -0
  558. il2ks-0.1.0/src/il2ks/web/views/sorties.py +240 -0
  559. il2ks-0.1.0/src/il2ks/web/views/sprite.py +25 -0
  560. il2ks-0.1.0/src/il2ks/web/views/styleguide.py +152 -0
  561. il2ks-0.1.0/src/il2ks/wsgi.py +15 -0
  562. il2ks-0.1.0/tests/__init__.py +0 -0
  563. il2ks-0.1.0/tests/aircraft_pages.py +18 -0
  564. il2ks-0.1.0/tests/conftest.py +67 -0
  565. il2ks-0.1.0/tests/db_canon.py +135 -0
  566. il2ks-0.1.0/tests/e2e/__init__.py +0 -0
  567. il2ks-0.1.0/tests/e2e/branding.py +70 -0
  568. il2ks-0.1.0/tests/e2e/conftest.py +209 -0
  569. il2ks-0.1.0/tests/e2e/flow_helpers.py +123 -0
  570. il2ks-0.1.0/tests/e2e/helpers.py +57 -0
  571. il2ks-0.1.0/tests/e2e/test_accessibility.py +81 -0
  572. il2ks-0.1.0/tests/e2e/test_board_switcher.py +49 -0
  573. il2ks-0.1.0/tests/e2e/test_branding_backgrounds.py +184 -0
  574. il2ks-0.1.0/tests/e2e/test_branding_theme.py +81 -0
  575. il2ks-0.1.0/tests/e2e/test_column_hints.py +95 -0
  576. il2ks-0.1.0/tests/e2e/test_columns_picker.py +246 -0
  577. il2ks-0.1.0/tests/e2e/test_flows.py +265 -0
  578. il2ks-0.1.0/tests/e2e/test_flows_admin_and_state.py +203 -0
  579. il2ks-0.1.0/tests/e2e/test_flows_aircraft.py +268 -0
  580. il2ks-0.1.0/tests/e2e/test_flows_boards.py +204 -0
  581. il2ks-0.1.0/tests/e2e/test_flows_more.py +459 -0
  582. il2ks-0.1.0/tests/e2e/test_flows_sorties.py +79 -0
  583. il2ks-0.1.0/tests/e2e/test_flows_tours.py +54 -0
  584. il2ks-0.1.0/tests/e2e/test_frontend_performance.py +258 -0
  585. il2ks-0.1.0/tests/e2e/test_home_feature_image.py +110 -0
  586. il2ks-0.1.0/tests/e2e/test_keyboard.py +58 -0
  587. il2ks-0.1.0/tests/e2e/test_language_menu.py +26 -0
  588. il2ks-0.1.0/tests/e2e/test_localtime.py +83 -0
  589. il2ks-0.1.0/tests/e2e/test_nav_history_alignment.py +65 -0
  590. il2ks-0.1.0/tests/e2e/test_nav_layout.py +124 -0
  591. il2ks-0.1.0/tests/e2e/test_profile_roles.py +50 -0
  592. il2ks-0.1.0/tests/e2e/test_row_links.py +78 -0
  593. il2ks-0.1.0/tests/e2e/test_smoke.py +166 -0
  594. il2ks-0.1.0/tests/e2e/test_visual_qa.py +355 -0
  595. il2ks-0.1.0/tests/e2e/tweaks.py +38 -0
  596. il2ks-0.1.0/tests/e2e/world.py +275 -0
  597. il2ks-0.1.0/tests/factories.py +352 -0
  598. il2ks-0.1.0/tests/fixtures/__init__.py +0 -0
  599. il2ks-0.1.0/tests/fixtures/logs/bailout_ejection_stale_wheels.txt.zip +0 -0
  600. il2ks-0.1.0/tests/fixtures/logs/most_bailouts.txt.zip +0 -0
  601. il2ks-0.1.0/tests/fixtures/logs/no_mission_end.txt.zip +0 -0
  602. il2ks-0.1.0/tests/fixtures/logs/two_mission_ends.txt.zip +0 -0
  603. il2ks-0.1.0/tests/fixtures/logs/typical.txt.zip +0 -0
  604. il2ks-0.1.0/tests/ingest_fakes.py +144 -0
  605. il2ks-0.1.0/tests/integration/__init__.py +0 -0
  606. il2ks-0.1.0/tests/integration/test_accuracy.py +135 -0
  607. il2ks-0.1.0/tests/integration/test_achievement_config.py +230 -0
  608. il2ks-0.1.0/tests/integration/test_achievement_variant_names.py +145 -0
  609. il2ks-0.1.0/tests/integration/test_achievements.py +459 -0
  610. il2ks-0.1.0/tests/integration/test_achievements_all_time.py +227 -0
  611. il2ks-0.1.0/tests/integration/test_achievements_rollup.py +106 -0
  612. il2ks-0.1.0/tests/integration/test_achievements_second_set.py +225 -0
  613. il2ks-0.1.0/tests/integration/test_admin.py +1015 -0
  614. il2ks-0.1.0/tests/integration/test_admin_login_security.py +116 -0
  615. il2ks-0.1.0/tests/integration/test_aggregates.py +147 -0
  616. il2ks-0.1.0/tests/integration/test_aircraft_mods.py +376 -0
  617. il2ks-0.1.0/tests/integration/test_aircraft_roles.py +430 -0
  618. il2ks-0.1.0/tests/integration/test_aircraft_rollup.py +291 -0
  619. il2ks-0.1.0/tests/integration/test_aircraft_scopes.py +385 -0
  620. il2ks-0.1.0/tests/integration/test_aircraft_stats.py +462 -0
  621. il2ks-0.1.0/tests/integration/test_aircraft_tables.py +217 -0
  622. il2ks-0.1.0/tests/integration/test_aircraft_type_elo.py +206 -0
  623. il2ks-0.1.0/tests/integration/test_ammo_mixes.py +188 -0
  624. il2ks-0.1.0/tests/integration/test_ammo_persist.py +224 -0
  625. il2ks-0.1.0/tests/integration/test_ammo_pve_pages.py +205 -0
  626. il2ks-0.1.0/tests/integration/test_assist_split.py +66 -0
  627. il2ks-0.1.0/tests/integration/test_batched_level2.py +501 -0
  628. il2ks-0.1.0/tests/integration/test_branding_images.py +303 -0
  629. il2ks-0.1.0/tests/integration/test_builds.py +151 -0
  630. il2ks-0.1.0/tests/integration/test_caching.py +181 -0
  631. il2ks-0.1.0/tests/integration/test_caching_revalidation.py +62 -0
  632. il2ks-0.1.0/tests/integration/test_charts.py +234 -0
  633. il2ks-0.1.0/tests/integration/test_column_hints.py +111 -0
  634. il2ks-0.1.0/tests/integration/test_data_version_bumps.py +66 -0
  635. il2ks-0.1.0/tests/integration/test_db.py +59 -0
  636. il2ks-0.1.0/tests/integration/test_dbutil.py +150 -0
  637. il2ks-0.1.0/tests/integration/test_deprecated_filters.py +19 -0
  638. il2ks-0.1.0/tests/integration/test_dev_bench.py +54 -0
  639. il2ks-0.1.0/tests/integration/test_doctor_checks.py +473 -0
  640. il2ks-0.1.0/tests/integration/test_elo_alltime_minimum.py +91 -0
  641. il2ks-0.1.0/tests/integration/test_end_to_end.py +132 -0
  642. il2ks-0.1.0/tests/integration/test_feature_image.py +349 -0
  643. il2ks-0.1.0/tests/integration/test_flight_score.py +167 -0
  644. il2ks-0.1.0/tests/integration/test_ground_categories.py +116 -0
  645. il2ks-0.1.0/tests/integration/test_home_tour.py +207 -0
  646. il2ks-0.1.0/tests/integration/test_icon_sprite.py +102 -0
  647. il2ks-0.1.0/tests/integration/test_ingest_runner.py +600 -0
  648. il2ks-0.1.0/tests/integration/test_killboard_streaks.py +305 -0
  649. il2ks-0.1.0/tests/integration/test_killboard_tours.py +350 -0
  650. il2ks-0.1.0/tests/integration/test_language.py +301 -0
  651. il2ks-0.1.0/tests/integration/test_leaderboards.py +439 -0
  652. il2ks-0.1.0/tests/integration/test_level2_end_to_end.py +153 -0
  653. il2ks-0.1.0/tests/integration/test_level2_per_tour_order.py +136 -0
  654. il2ks-0.1.0/tests/integration/test_list_columns.py +516 -0
  655. il2ks-0.1.0/tests/integration/test_live.py +391 -0
  656. il2ks-0.1.0/tests/integration/test_live_sorties.py +753 -0
  657. il2ks-0.1.0/tests/integration/test_live_sorties_web.py +78 -0
  658. il2ks-0.1.0/tests/integration/test_live_web.py +317 -0
  659. il2ks-0.1.0/tests/integration/test_local_time_pages.py +21 -0
  660. il2ks-0.1.0/tests/integration/test_media_view.py +140 -0
  661. il2ks-0.1.0/tests/integration/test_migrate_aircraft_merge.py +112 -0
  662. il2ks-0.1.0/tests/integration/test_migrate_catalog_refresh.py +130 -0
  663. il2ks-0.1.0/tests/integration/test_mission_pages.py +278 -0
  664. il2ks-0.1.0/tests/integration/test_mission_sortie_table.py +230 -0
  665. il2ks-0.1.0/tests/integration/test_nav_history.py +76 -0
  666. il2ks-0.1.0/tests/integration/test_ops_commands.py +620 -0
  667. il2ks-0.1.0/tests/integration/test_ops_real_process.py +102 -0
  668. il2ks-0.1.0/tests/integration/test_override_banner.py +108 -0
  669. il2ks-0.1.0/tests/integration/test_pagination_sizes.py +116 -0
  670. il2ks-0.1.0/tests/integration/test_persist.py +321 -0
  671. il2ks-0.1.0/tests/integration/test_persist_combat_fields.py +83 -0
  672. il2ks-0.1.0/tests/integration/test_persist_rules.py +348 -0
  673. il2ks-0.1.0/tests/integration/test_pilot_fate_pages.py +123 -0
  674. il2ks-0.1.0/tests/integration/test_player_pages.py +555 -0
  675. il2ks-0.1.0/tests/integration/test_player_rollup.py +268 -0
  676. il2ks-0.1.0/tests/integration/test_pve_breakdown.py +107 -0
  677. il2ks-0.1.0/tests/integration/test_quips.py +249 -0
  678. il2ks-0.1.0/tests/integration/test_ratings.py +260 -0
  679. il2ks-0.1.0/tests/integration/test_reprocess_requests.py +311 -0
  680. il2ks-0.1.0/tests/integration/test_reprocess_span.py +133 -0
  681. il2ks-0.1.0/tests/integration/test_rollup.py +94 -0
  682. il2ks-0.1.0/tests/integration/test_row_links_and_flavor.py +105 -0
  683. il2ks-0.1.0/tests/integration/test_rule_settings.py +342 -0
  684. il2ks-0.1.0/tests/integration/test_rules_review12.py +264 -0
  685. il2ks-0.1.0/tests/integration/test_scores.py +200 -0
  686. il2ks-0.1.0/tests/integration/test_setup_page.py +515 -0
  687. il2ks-0.1.0/tests/integration/test_shame_quip.py +103 -0
  688. il2ks-0.1.0/tests/integration/test_skill_boards.py +261 -0
  689. il2ks-0.1.0/tests/integration/test_sortie_list.py +213 -0
  690. il2ks-0.1.0/tests/integration/test_sortie_pages.py +745 -0
  691. il2ks-0.1.0/tests/integration/test_sortie_tour.py +90 -0
  692. il2ks-0.1.0/tests/integration/test_sqlite_settings.py +84 -0
  693. il2ks-0.1.0/tests/integration/test_stat_marks.py +459 -0
  694. il2ks-0.1.0/tests/integration/test_static_minify.py +103 -0
  695. il2ks-0.1.0/tests/integration/test_streak_runs.py +262 -0
  696. il2ks-0.1.0/tests/integration/test_streak_tracks.py +466 -0
  697. il2ks-0.1.0/tests/integration/test_tour_clean_slate.py +185 -0
  698. il2ks-0.1.0/tests/integration/test_tour_pages.py +317 -0
  699. il2ks-0.1.0/tests/integration/test_tour_ratings.py +230 -0
  700. il2ks-0.1.0/tests/integration/test_tour_robustness.py +317 -0
  701. il2ks-0.1.0/tests/integration/test_tours.py +828 -0
  702. il2ks-0.1.0/tests/integration/test_tours_decisive.py +283 -0
  703. il2ks-0.1.0/tests/integration/test_tours_decisive_admin.py +71 -0
  704. il2ks-0.1.0/tests/integration/test_tours_review11.py +246 -0
  705. il2ks-0.1.0/tests/integration/test_type_killboards.py +362 -0
  706. il2ks-0.1.0/tests/integration/test_upgrade_costs.py +92 -0
  707. il2ks-0.1.0/tests/integration/test_views.py +12 -0
  708. il2ks-0.1.0/tests/integration/test_weapon_mod_names.py +58 -0
  709. il2ks-0.1.0/tests/integration/test_web_alongside_ingest.py +104 -0
  710. il2ks-0.1.0/tests/integration/test_web_foundation.py +356 -0
  711. il2ks-0.1.0/tests/legacy_aircraft_alltime.py +705 -0
  712. il2ks-0.1.0/tests/level1_oracle.py +225 -0
  713. il2ks-0.1.0/tests/live_helpers.py +65 -0
  714. il2ks-0.1.0/tests/ops_helpers.py +105 -0
  715. il2ks-0.1.0/tests/perf/conftest.py +37 -0
  716. il2ks-0.1.0/tests/perf/pages.py +57 -0
  717. il2ks-0.1.0/tests/perf/plan_variants.py +262 -0
  718. il2ks-0.1.0/tests/perf/query_plans.py +323 -0
  719. il2ks-0.1.0/tests/perf/seed.py +137 -0
  720. il2ks-0.1.0/tests/perf/test_query_plans.py +174 -0
  721. il2ks-0.1.0/tests/perf/test_server_timing.py +103 -0
  722. il2ks-0.1.0/tests/simple_reads.py +43 -0
  723. il2ks-0.1.0/tests/sortie_tours.py +17 -0
  724. il2ks-0.1.0/tests/unit/__init__.py +0 -0
  725. il2ks-0.1.0/tests/unit/catalog/__init__.py +0 -0
  726. il2ks-0.1.0/tests/unit/catalog/test_ammo_names.py +107 -0
  727. il2ks-0.1.0/tests/unit/catalog/test_data_files.py +139 -0
  728. il2ks-0.1.0/tests/unit/catalog/test_lookup.py +247 -0
  729. il2ks-0.1.0/tests/unit/catalog/test_object_names.py +130 -0
  730. il2ks-0.1.0/tests/unit/catalog/test_ordnance.py +109 -0
  731. il2ks-0.1.0/tests/unit/catalog/test_payload_lookup.py +61 -0
  732. il2ks-0.1.0/tests/unit/catalog/test_sample_coverage.py +72 -0
  733. il2ks-0.1.0/tests/unit/catalog/test_significant_mods.py +43 -0
  734. il2ks-0.1.0/tests/unit/catalog/test_weapon_mod_names.py +73 -0
  735. il2ks-0.1.0/tests/unit/catalog/test_weapon_mods.py +62 -0
  736. il2ks-0.1.0/tests/unit/ingest/__init__.py +0 -0
  737. il2ks-0.1.0/tests/unit/ingest/test_archive.py +165 -0
  738. il2ks-0.1.0/tests/unit/ingest/test_discover.py +178 -0
  739. il2ks-0.1.0/tests/unit/ingest/test_lock.py +107 -0
  740. il2ks-0.1.0/tests/unit/ingest/test_worker.py +23 -0
  741. il2ks-0.1.0/tests/unit/logparse/__init__.py +0 -0
  742. il2ks-0.1.0/tests/unit/logparse/test_event_immutability.py +14 -0
  743. il2ks-0.1.0/tests/unit/logparse/test_explosion_burst.py +187 -0
  744. il2ks-0.1.0/tests/unit/logparse/test_fast_path.py +73 -0
  745. il2ks-0.1.0/tests/unit/logparse/test_files.py +147 -0
  746. il2ks-0.1.0/tests/unit/logparse/test_parser.py +599 -0
  747. il2ks-0.1.0/tests/unit/logparse/test_real_logs.py +66 -0
  748. il2ks-0.1.0/tests/unit/logparse/test_tail.py +95 -0
  749. il2ks-0.1.0/tests/unit/ops/__init__.py +0 -0
  750. il2ks-0.1.0/tests/unit/ops/test_backup.py +529 -0
  751. il2ks-0.1.0/tests/unit/ops/test_patch_config.py +63 -0
  752. il2ks-0.1.0/tests/unit/ops/test_setup_validation.py +132 -0
  753. il2ks-0.1.0/tests/unit/ops/test_template_and_detect.py +198 -0
  754. il2ks-0.1.0/tests/unit/ratings/__init__.py +0 -0
  755. il2ks-0.1.0/tests/unit/ratings/test_elo.py +134 -0
  756. il2ks-0.1.0/tests/unit/ratings/test_score.py +188 -0
  757. il2ks-0.1.0/tests/unit/replay/__init__.py +0 -0
  758. il2ks-0.1.0/tests/unit/replay/builder.py +293 -0
  759. il2ks-0.1.0/tests/unit/replay/test_accuracy.py +87 -0
  760. il2ks-0.1.0/tests/unit/replay/test_achievement_facts.py +107 -0
  761. il2ks-0.1.0/tests/unit/replay/test_ammo.py +492 -0
  762. il2ks-0.1.0/tests/unit/replay/test_ammo_left_after_loss.py +89 -0
  763. il2ks-0.1.0/tests/unit/replay/test_attack.py +377 -0
  764. il2ks-0.1.0/tests/unit/replay/test_attack_samples.py +34 -0
  765. il2ks-0.1.0/tests/unit/replay/test_bailout_v3.py +193 -0
  766. il2ks-0.1.0/tests/unit/replay/test_capture.py +63 -0
  767. il2ks-0.1.0/tests/unit/replay/test_cleanup_damage.py +56 -0
  768. il2ks-0.1.0/tests/unit/replay/test_damage_legs.py +273 -0
  769. il2ks-0.1.0/tests/unit/replay/test_friendly_fire.py +127 -0
  770. il2ks-0.1.0/tests/unit/replay/test_ground_categories.py +69 -0
  771. il2ks-0.1.0/tests/unit/replay/test_ground_losses.py +376 -0
  772. il2ks-0.1.0/tests/unit/replay/test_gunners.py +273 -0
  773. il2ks-0.1.0/tests/unit/replay/test_interception.py +95 -0
  774. il2ks-0.1.0/tests/unit/replay/test_live.py +107 -0
  775. il2ks-0.1.0/tests/unit/replay/test_mission_result.py +56 -0
  776. il2ks-0.1.0/tests/unit/replay/test_outcomes.py +440 -0
  777. il2ks-0.1.0/tests/unit/replay/test_parachute_deaths.py +50 -0
  778. il2ks-0.1.0/tests/unit/replay/test_pilot_fate.py +367 -0
  779. il2ks-0.1.0/tests/unit/replay/test_pilot_final_pos.py +132 -0
  780. il2ks-0.1.0/tests/unit/replay/test_pilot_health.py +55 -0
  781. il2ks-0.1.0/tests/unit/replay/test_post_end_window.py +143 -0
  782. il2ks-0.1.0/tests/unit/replay/test_pve_breakdown.py +129 -0
  783. il2ks-0.1.0/tests/unit/replay/test_rams.py +186 -0
  784. il2ks-0.1.0/tests/unit/replay/test_reset_destruction.py +77 -0
  785. il2ks-0.1.0/tests/unit/replay/test_resupply.py +52 -0
  786. il2ks-0.1.0/tests/unit/replay/test_sample_distributions.py +45 -0
  787. il2ks-0.1.0/tests/unit/replay/test_streaming.py +101 -0
  788. il2ks-0.1.0/tests/unit/replay/test_timeline_hits.py +200 -0
  789. il2ks-0.1.0/tests/unit/test_achievements.py +345 -0
  790. il2ks-0.1.0/tests/unit/test_achievements_all_time.py +98 -0
  791. il2ks-0.1.0/tests/unit/test_achievements_second_set.py +238 -0
  792. il2ks-0.1.0/tests/unit/test_anonymize.py +65 -0
  793. il2ks-0.1.0/tests/unit/test_asset_inventory.py +37 -0
  794. il2ks-0.1.0/tests/unit/test_bootid.py +27 -0
  795. il2ks-0.1.0/tests/unit/test_branding_images.py +155 -0
  796. il2ks-0.1.0/tests/unit/test_caddy.py +214 -0
  797. il2ks-0.1.0/tests/unit/test_catalog_payloads.py +45 -0
  798. il2ks-0.1.0/tests/unit/test_charts.py +157 -0
  799. il2ks-0.1.0/tests/unit/test_claude_hooks.py +161 -0
  800. il2ks-0.1.0/tests/unit/test_cli.py +292 -0
  801. il2ks-0.1.0/tests/unit/test_config.py +270 -0
  802. il2ks-0.1.0/tests/unit/test_config_rules.py +52 -0
  803. il2ks-0.1.0/tests/unit/test_config_serving.py +126 -0
  804. il2ks-0.1.0/tests/unit/test_config_template.py +134 -0
  805. il2ks-0.1.0/tests/unit/test_config_tours.py +62 -0
  806. il2ks-0.1.0/tests/unit/test_custom.py +482 -0
  807. il2ks-0.1.0/tests/unit/test_dev_check.py +132 -0
  808. il2ks-0.1.0/tests/unit/test_djsettings.py +136 -0
  809. il2ks-0.1.0/tests/unit/test_flavor.py +325 -0
  810. il2ks-0.1.0/tests/unit/test_fonts.py +272 -0
  811. il2ks-0.1.0/tests/unit/test_i18n_templates.py +44 -0
  812. il2ks-0.1.0/tests/unit/test_icon_files.py +74 -0
  813. il2ks-0.1.0/tests/unit/test_local_time.py +48 -0
  814. il2ks-0.1.0/tests/unit/test_logo.py +232 -0
  815. il2ks-0.1.0/tests/unit/test_logsetup.py +180 -0
  816. il2ks-0.1.0/tests/unit/test_migration_guards.py +180 -0
  817. il2ks-0.1.0/tests/unit/test_packaging.py +105 -0
  818. il2ks-0.1.0/tests/unit/test_pilot_fate_display.py +47 -0
  819. il2ks-0.1.0/tests/unit/test_quips.py +114 -0
  820. il2ks-0.1.0/tests/unit/test_release_workflow.py +16 -0
  821. il2ks-0.1.0/tests/unit/test_rule_settings.py +178 -0
  822. il2ks-0.1.0/tests/unit/test_secret.py +59 -0
  823. il2ks-0.1.0/tests/unit/test_service.py +217 -0
  824. il2ks-0.1.0/tests/unit/test_serving_checks.py +255 -0
  825. il2ks-0.1.0/tests/unit/test_serving_commands.py +899 -0
  826. il2ks-0.1.0/tests/unit/test_setup_token.py +126 -0
  827. il2ks-0.1.0/tests/unit/test_sortie_view.py +127 -0
  828. il2ks-0.1.0/tests/unit/test_stat_marks.py +347 -0
  829. il2ks-0.1.0/tests/unit/test_streaks_core.py +227 -0
  830. il2ks-0.1.0/tests/unit/test_supervisor.py +291 -0
  831. il2ks-0.1.0/tests/unit/test_svg_symbol.py +95 -0
  832. il2ks-0.1.0/tests/unit/test_template_compile.py +50 -0
  833. il2ks-0.1.0/tests/unit/test_template_versions.py +371 -0
  834. il2ks-0.1.0/tests/unit/test_theme.py +263 -0
  835. il2ks-0.1.0/tests/unit/test_timeutil.py +99 -0
  836. il2ks-0.1.0/tests/unit/test_tours_core.py +153 -0
  837. il2ks-0.1.0/tests/unit/test_translations.py +293 -0
  838. il2ks-0.1.0/tests/unit/test_web_display.py +136 -0
  839. il2ks-0.1.0/tests/unit/test_web_missions_display.py +140 -0
  840. il2ks-0.1.0/tests/unit/test_windows_packaging.py +294 -0
  841. il2ks-0.1.0/uv.lock +2090 -0
  842. il2ks-0.1.0/vulture_whitelist.py +301 -0
@@ -0,0 +1,12 @@
1
+ # The image only needs pyproject.toml, uv.lock, README.md, LICENSE, NOTICE, src/ and docker/docker-entrypoint.sh.
2
+ # Never send the game's real logs or local state to the daemon.
3
+ *
4
+ !pyproject.toml
5
+ !uv.lock
6
+ !README.md
7
+ !LICENSE
8
+ !NOTICE
9
+ !src/**
10
+ !docker/docker-entrypoint.sh
11
+ **/__pycache__
12
+ **/*.pyc
@@ -0,0 +1,2 @@
1
+ # Shell scripts must keep LF endings or bash fails on Windows checkouts
2
+ *.sh text eol=lf
@@ -0,0 +1,40 @@
1
+ # Runs an Inno Setup installer silently with a timeout. It always prints the installer log, the il2ks logs and the process tree
2
+ # afterwards; on a timeout it also kills the installer, so a hang shows where it hangs instead of eating the job's time limit.
3
+ # Usage: run-installer.ps1 -Exe <path> -LogFile <setup log> -Arguments <installer switches...> [-TimeoutSeconds 900]
4
+ param(
5
+ [Parameter(Mandatory)] [string] $Exe,
6
+ [Parameter(Mandatory)] [string] $LogFile,
7
+ [Parameter(Mandatory)] [string[]] $Arguments,
8
+ [int] $TimeoutSeconds = 900
9
+ )
10
+ $ErrorActionPreference = 'Continue'
11
+
12
+ function Show-Diagnostics {
13
+ Write-Host "::group::installer log ($LogFile)"
14
+ if (Test-Path $LogFile) { Get-Content $LogFile -Tail 150 } else { Write-Host "(no log file)" }
15
+ Write-Host "::endgroup::"
16
+ Write-Host "::group::il2ks logs in ProgramData"
17
+ Get-ChildItem "$env:ProgramData\il2ks" -Recurse -File -ErrorAction SilentlyContinue |
18
+ Where-Object { $_.FullName -like '*\logs\*' } |
19
+ ForEach-Object { "== $($_.FullName)"; Get-Content $_.FullName -Tail 30 }
20
+ Write-Host "::endgroup::"
21
+ Write-Host "::group::process tree"
22
+ Get-CimInstance Win32_Process |
23
+ Where-Object { $_.Name -match 'il2ks|python|cmd|icacls|sc\.exe|netsh|caddy' } |
24
+ Select-Object ProcessId, ParentProcessId, Name, CommandLine | Format-List | Out-String -Width 250
25
+ Write-Host "::endgroup::"
26
+ }
27
+
28
+ $arglist = ($Arguments | ForEach-Object { if ($_ -match '\s') { '"' + $_ + '"' } else { $_ } }) -join ' '
29
+ # No -Wait: that also waits for every process the installer started, and has no timeout.
30
+ $p = Start-Process -FilePath $Exe -ArgumentList $arglist -PassThru
31
+ if (-not $p.WaitForExit($TimeoutSeconds * 1000)) {
32
+ Write-Host "::error::the installer did not finish within $TimeoutSeconds seconds"
33
+ Show-Diagnostics
34
+ Get-CimInstance Win32_Process | Where-Object { $_.Name -like 'il2ks-setup*' } |
35
+ ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
36
+ throw "installer timed out"
37
+ }
38
+ $p.WaitForExit()
39
+ Show-Diagnostics
40
+ if ($p.ExitCode -ne 0) { throw "installer exit code $($p.ExitCode)" }
@@ -0,0 +1,125 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ lint:
10
+ # The same command agents and pre-commit run (`il2ks dev check`), minus the tests (the jobs below run those):
11
+ # ruff, format, pyright, import-linter, vulture, makemigrations --check, migration immutability / single leaf,
12
+ # bump-templates --check, translations check. Full history: the migration guard compares with origin/main.
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v7
16
+ with:
17
+ fetch-depth: 0
18
+ - uses: astral-sh/setup-uv@v10.2.0
19
+ - run: uv sync --locked
20
+ - run: uv run il2ks dev check --no-tests --verbose
21
+
22
+ test-sqlite:
23
+ # SQLite is the default test database (TD-19). Windows is the main target platform.
24
+ strategy:
25
+ fail-fast: false
26
+ matrix:
27
+ os: [ubuntu-latest, windows-latest]
28
+ runs-on: ${{ matrix.os }}
29
+ steps:
30
+ - uses: actions/checkout@v7
31
+ - uses: astral-sh/setup-uv@v10.2.0
32
+ - run: uv sync --locked
33
+ - run: uv run pytest -m "not perf" # the budgets of tests/perf have their own job (test-perf)
34
+
35
+ test-postgres:
36
+ # Postgres is dev-side only: one extra job keeps a future switch cheap (TD-04, TD-19).
37
+ runs-on: ubuntu-latest
38
+ services:
39
+ postgres:
40
+ image: postgres:17
41
+ env:
42
+ POSTGRES_USER: il2ks
43
+ POSTGRES_PASSWORD: il2ks
44
+ POSTGRES_DB: il2ks
45
+ ports: ["5432:5432"]
46
+ options: >-
47
+ --health-cmd "pg_isready -U il2ks" --health-interval 5s --health-timeout 5s --health-retries 10
48
+ env:
49
+ IL2KS_TEST_DB: postgres
50
+ steps:
51
+ - uses: actions/checkout@v7
52
+ - uses: astral-sh/setup-uv@v10.2.0
53
+ - run: uv sync --locked
54
+ - run: uv run pytest -m "not perf" # the budgets of tests/perf have their own job (test-perf)
55
+
56
+ test-perf:
57
+ # Query and time budgets of every public page over a seeded world (tests/perf, marker `perf`; OQ-97). Kept out of
58
+ # the functional jobs so a slow runner never fails them. SQLite first (what ships), then the Postgres service:
59
+ # Postgres plans queries differently and is where a slow query shows up.
60
+ runs-on: ubuntu-latest
61
+ services:
62
+ postgres:
63
+ image: postgres:17
64
+ env:
65
+ POSTGRES_USER: il2ks
66
+ POSTGRES_PASSWORD: il2ks
67
+ POSTGRES_DB: il2ks
68
+ ports: ["5432:5432"]
69
+ options: >-
70
+ --health-cmd "pg_isready -U il2ks" --health-interval 5s --health-timeout 5s --health-retries 10
71
+ steps:
72
+ - uses: actions/checkout@v7
73
+ - uses: astral-sh/setup-uv@v10.2.0
74
+ - run: uv sync --locked
75
+ - run: uv run pytest -m perf -n 0
76
+ - run: uv run pytest -m perf -n 0
77
+ env:
78
+ IL2KS_TEST_DB: postgres
79
+
80
+ test-e2e:
81
+ # Browser tests (doc 08): the real app in a child process, driven by Chromium through Playwright. Opt-in locally
82
+ # (IL2KS_TEST_E2E=1); always on here. Traces and screenshots of failures are kept as an artifact.
83
+ runs-on: ubuntu-24.04 # Playwright's --with-deps apt step lags behind new Ubuntu releases (ubuntu-latest moves to 26 on 2026-10-19)
84
+ env:
85
+ IL2KS_TEST_E2E: "1"
86
+ steps:
87
+ - uses: actions/checkout@v7
88
+ - uses: astral-sh/setup-uv@v10.2.0
89
+ - run: uv sync --locked
90
+ - run: uv run playwright install --with-deps chromium
91
+ - run: >-
92
+ uv run pytest -m e2e --basetemp=e2e-tmp --output=test-results
93
+ --tracing=retain-on-failure --screenshot=only-on-failure
94
+ - uses: actions/upload-artifact@v7
95
+ if: failure()
96
+ with:
97
+ name: e2e-failure-${{ github.run_id }}
98
+ path: |
99
+ test-results/
100
+ e2e-tmp/**/server.log
101
+ if-no-files-found: ignore
102
+ retention-days: 14
103
+
104
+ package:
105
+ # The wheel must carry templates, static files, catalog data, the example config and the migrations (PyPI path).
106
+ runs-on: ubuntu-latest
107
+ steps:
108
+ - uses: actions/checkout@v7
109
+ - uses: astral-sh/setup-uv@v10.2.0
110
+ - run: uv sync --locked
111
+ - run: uv run pytest tests/unit/test_packaging.py
112
+ env:
113
+ IL2KS_TEST_BUILD: "1"
114
+
115
+ docker:
116
+ # The image of docs/install-docker.md (doc 07 option A): build it (nothing is pushed) and smoke-test it.
117
+ runs-on: ubuntu-latest
118
+ steps:
119
+ - uses: actions/checkout@v7
120
+ - run: docker build -f docker/Dockerfile -t il2ks:ci .
121
+ - run: docker compose -f docker/compose.yaml config --quiet
122
+ env:
123
+ IL2KS_SERVER_TIMEZONE: UTC
124
+ IL2KS_LOGS_HOST_DIR: /tmp
125
+ - run: docker/smoke-test.sh il2ks:ci
@@ -0,0 +1,38 @@
1
+ name: Load test
2
+
3
+ # Manual only (Actions tab -> Load test -> Run workflow): load numbers on a shared runner are too noisy to gate a
4
+ # commit on. Seeds a scratch database, runs Locust against `il2ks web --dev`, uploads the report (docs/performance-testing.md).
5
+ on:
6
+ workflow_dispatch:
7
+ inputs:
8
+ users:
9
+ description: Concurrent users
10
+ default: "20"
11
+ run_time:
12
+ description: Run time (Locust syntax, e.g. 60s or 3m)
13
+ default: "60s"
14
+ missions:
15
+ description: Missions to seed
16
+ default: "60"
17
+
18
+ jobs:
19
+ loadtest:
20
+ runs-on: ubuntu-24.04
21
+ steps:
22
+ - uses: actions/checkout@v7
23
+ - uses: astral-sh/setup-uv@v10.2.0
24
+ - run: uv sync --locked
25
+ - name: Seed, serve and load the site
26
+ run: >-
27
+ uv run python loadtest/run.py
28
+ -u "${{ inputs.users }}" -t "${{ inputs.run_time }}" --missions "${{ inputs.missions }}"
29
+ --html loadtest-report.html | tee loadtest-report.md
30
+ - uses: actions/upload-artifact@v7
31
+ if: always()
32
+ with:
33
+ name: loadtest-${{ github.run_id }}
34
+ path: |
35
+ loadtest-report.html
36
+ loadtest-report.md
37
+ if-no-files-found: ignore
38
+ retention-days: 30
@@ -0,0 +1,119 @@
1
+ name: Release
2
+
3
+ # Pushing a tag like v0.1.0 builds il2ks, proves the wheel works in a clean environment on Linux and Windows, and
4
+ # publishes it to PyPI with trusted publishing (no API token stored anywhere).
5
+ #
6
+ # One-time setup on pypi.org: Your projects -> il2ks -> Publishing -> add a trusted publisher
7
+ # owner: FGlazov repository: il2_korea_stats workflow: release.yml environment: pypi
8
+ # (for the very first release, add it as a "pending publisher" under Your account -> Publishing).
9
+ # And in GitHub: Settings -> Environments -> New environment "pypi" (optionally require a reviewer there).
10
+ #
11
+ # Release steps: bump __version__ in src/il2ks/__init__.py (the only place), commit, `git tag v<version>`, push the tag.
12
+
13
+ on:
14
+ push:
15
+ tags: ["v*"]
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ build:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v7
25
+ - uses: astral-sh/setup-uv@v10.2.0
26
+ - run: uv sync --locked
27
+
28
+ - name: The tag must match the package version
29
+ run: |
30
+ version="$(uv run python -c 'import il2ks; print(il2ks.__version__)')"
31
+ if [ "v${version}" != "${GITHUB_REF_NAME}" ]; then
32
+ echo "Tag ${GITHUB_REF_NAME} does not match il2ks.__version__ ${version}" >&2
33
+ exit 1
34
+ fi
35
+
36
+ - name: Template versions count again after the first release (TD-25)
37
+ run: |
38
+ done="$(uv run python -c 'from il2ks.serving.templateversions import FIRST_RELEASE_DONE; print(FIRST_RELEASE_DONE)')"
39
+ case "${GITHUB_REF_NAME}" in *a[0-9]*|*b[0-9]*|*rc[0-9]*) echo "pre-release tag: the switch may stay off"; exit 0;; esac
40
+ if [ "${done}" != "True" ]; then
41
+ echo "FIRST_RELEASE_DONE is still False in serving/templateversions.py: flip it before tagging (docs/releasing.md)" >&2
42
+ exit 1
43
+ fi
44
+
45
+ - name: Tests, including the wheel contents check
46
+ run: uv run pytest -q
47
+ env:
48
+ IL2KS_TEST_BUILD: "1"
49
+
50
+ - name: Build wheel and sdist
51
+ run: uv build
52
+
53
+ - uses: actions/upload-artifact@v7
54
+ with:
55
+ name: dist
56
+ path: dist/
57
+ if-no-files-found: error
58
+
59
+ smoke:
60
+ # Install the built wheel into a fresh virtual environment, away from the source tree, and make it do real work.
61
+ needs: build
62
+ strategy:
63
+ fail-fast: true
64
+ matrix:
65
+ os: [ubuntu-latest, windows-latest]
66
+ runs-on: ${{ matrix.os }}
67
+ defaults:
68
+ run:
69
+ shell: bash
70
+ steps:
71
+ - uses: astral-sh/setup-uv@v10.2.0
72
+ - uses: actions/download-artifact@v8
73
+ with:
74
+ name: dist
75
+ path: dist
76
+
77
+ - name: Install the wheel in a clean venv
78
+ run: |
79
+ uv venv --python 3.13 smoke-venv
80
+ if [ "$RUNNER_OS" = "Windows" ]; then BIN=smoke-venv/Scripts; else BIN=smoke-venv/bin; fi
81
+ echo "BIN=$PWD/$BIN" >> "$GITHUB_ENV"
82
+ uv pip install --python smoke-venv dist/*.whl # the folder: `Scripts/python` without `.exe` fails on Windows
83
+
84
+ - name: il2ks --help and --version
85
+ run: |
86
+ "$BIN/il2ks" --help
87
+ "$BIN/il2ks" --version
88
+
89
+ - name: Smoke test
90
+ env:
91
+ IL2KS_DATA_DIR: ${{ github.workspace }}/smoke-data
92
+ run: |
93
+ "$BIN/il2ks" manage migrate --noinput
94
+ "$BIN/il2ks" custom list --builtin | grep "templates/il2ks/base.html" > /dev/null
95
+ "$BIN/il2ks" caddyfile | grep "reverse_proxy 127.0.0.1:8000" > /dev/null
96
+ "$BIN/il2ks" service systemd | grep "ExecStart=" > /dev/null
97
+ "$BIN/il2ks" web --dev --port 18000 > web.log 2>&1 &
98
+ ok=0
99
+ for i in $(seq 1 40); do
100
+ if curl -fsS http://127.0.0.1:18000/ > /dev/null; then ok=1; break; fi
101
+ sleep 1
102
+ done
103
+ cat web.log
104
+ [ "$ok" = "1" ] || { echo "the site did not answer" >&2; exit 1; }
105
+ curl -fsS http://127.0.0.1:18000/admin/login/ > /dev/null
106
+ if [ "$RUNNER_OS" = "Linux" ]; then pkill -f "il2ks web" || true; fi
107
+
108
+ publish:
109
+ needs: smoke
110
+ runs-on: ubuntu-latest
111
+ environment: pypi
112
+ permissions:
113
+ id-token: write # trusted publishing
114
+ steps:
115
+ - uses: actions/download-artifact@v8
116
+ with:
117
+ name: dist
118
+ path: dist
119
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,232 @@
1
+ name: Windows installer
2
+
3
+ # Builds dist/il2ks-setup-<version>.exe (packaging/windows, doc 07 option B), smoke-tests it, and on a version tag attaches it
4
+ # to the GitHub release. Not run on every push: it downloads about 90 MB of pinned inputs and takes several minutes.
5
+ #
6
+ # - tag v* build + smoke test + release asset (+ the real-service test, which may fail without blocking)
7
+ # - workflow_dispatch build + smoke test, uploaded as a workflow artifact; tick "service_test" for the real-service test
8
+ #
9
+ # The smoke test installs into a temp folder with the service and firewall steps switched off (/NOSERVICE /NOFIREWALL), so it
10
+ # changes nothing outside the runner's disposable VM anyway. The service test installs the real service on that VM.
11
+
12
+ on:
13
+ push:
14
+ tags: ["v*"]
15
+ workflow_dispatch:
16
+ inputs:
17
+ service_test:
18
+ description: "Also install the real Windows service on the runner and check start and graceful stop"
19
+ type: boolean
20
+ default: false
21
+
22
+ permissions:
23
+ contents: read
24
+
25
+ jobs:
26
+ build:
27
+ runs-on: windows-latest
28
+ steps:
29
+ - uses: actions/checkout@v7
30
+ - uses: astral-sh/setup-uv@v10.2.0
31
+ - run: uv sync --locked
32
+
33
+ - name: The tag must match the package version
34
+ if: startsWith(github.ref, 'refs/tags/v')
35
+ shell: bash
36
+ run: |
37
+ version="$(uv run python -c 'import il2ks; print(il2ks.__version__)')"
38
+ if [ "v${version}" != "${GITHUB_REF_NAME}" ]; then
39
+ echo "Tag ${GITHUB_REF_NAME} does not match il2ks.__version__ ${version}" >&2
40
+ exit 1
41
+ fi
42
+
43
+ - name: Build the installer (pinned inputs, SHA-256 checked)
44
+ run: uv run python packaging/windows/build.py
45
+
46
+ - uses: actions/upload-artifact@v7
47
+ with:
48
+ name: il2ks-windows-installer
49
+ path: dist/il2ks-setup-*.exe
50
+ if-no-files-found: error
51
+
52
+ smoke:
53
+ # Install silently into a temp folder, no service, no firewall; run il2ks from the installed copy; uninstall.
54
+ needs: build
55
+ runs-on: windows-latest
56
+ timeout-minutes: 30 # a silent install that waits for input would otherwise hang for 6 hours
57
+ steps:
58
+ - uses: actions/checkout@v7 # only for .github/scripts/run-installer.ps1
59
+ - uses: actions/download-artifact@v8
60
+ with:
61
+ name: il2ks-windows-installer
62
+ path: installer
63
+
64
+ - name: Install silently
65
+ shell: pwsh
66
+ run: |
67
+ $exe = (Get-ChildItem installer\il2ks-setup-*.exe).FullName
68
+ $app = Join-Path $env:RUNNER_TEMP 'il2ks-app'
69
+ $logs = Join-Path $env:RUNNER_TEMP 'dserver-logs'
70
+ $pw = Join-Path $env:RUNNER_TEMP 'il2ks-admin-password.txt'
71
+ Set-Content -Path $pw -Value 'Correct-Horse-Battery-9' -Encoding ascii
72
+ New-Item -ItemType Directory -Force $logs | Out-Null
73
+ "APP=$app" | Out-File -Append -Encoding utf8 $env:GITHUB_ENV
74
+ $args = @('/VERYSILENT', '/SUPPRESSMSGBOXES', '/NORESTART', '/SP-', "/DIR=$app", "/LOG=$env:RUNNER_TEMP\setup.log",
75
+ '/NOSERVICE', '/NOFIREWALL', '/MERGETASKS=!firewall', "/LOGDIR=$logs", '/TIMEZONE=UTC',
76
+ '/ADMINUSER=ci', "/ADMINPASSWORDFILE=$pw")
77
+ .github\scripts\run-installer.ps1 -Exe $exe -LogFile "$env:RUNNER_TEMP\setup.log" -Arguments $args
78
+ if (Test-Path "$pw") { throw "the installer did not delete the password file" }
79
+
80
+ - name: il2ks --version and doctor from the installed copy
81
+ shell: pwsh
82
+ run: |
83
+ & "$env:APP\il2ks.cmd" --version
84
+ if ($LASTEXITCODE -ne 0) { throw "il2ks --version failed" }
85
+ $report = & "$env:APP\il2ks.cmd" doctor 2>&1 | Out-String
86
+ $code = $LASTEXITCODE
87
+ Write-Output $report
88
+ # 0 = all OK, 1 = warnings (no missions yet, no domain), 2 = errors: only that fails the job. The GitHub
89
+ # runner has something listening on port 80 already (shown below), which is the runner's, not ours.
90
+ Get-NetTCPConnection -LocalPort 80 -State Listen -ErrorAction SilentlyContinue |
91
+ ForEach-Object { Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue } | Format-Table Id, ProcessName
92
+ $errors = ([regex]::Matches($report, '\[ERROR\] ([^\r\n]*)') | ForEach-Object { $_.Groups[1].Value })
93
+ $unexpected = @($errors | Where-Object { $_ -notmatch '^Port 80 ' })
94
+ if ($code -ge 2 -and $unexpected.Count -gt 0) { throw "il2ks doctor reported errors: $($unexpected -join '; ')" }
95
+ if (-not (Test-Path "$env:APP\service\il2ks-service.exe")) { throw "the service wrapper is missing" }
96
+ if (-not (Test-Path "$env:APP\bin\caddy.exe")) { throw "caddy.exe is missing" }
97
+ & "$env:APP\bin\caddy.exe" version
98
+ if (-not (Test-Path "$env:ProgramData\il2ks\il2ks.toml")) { throw "setup did not write il2ks.toml" }
99
+ if (Get-Service il2ks -ErrorAction SilentlyContinue) { throw "a service was installed despite /NOSERVICE" }
100
+
101
+ - name: The site answers (il2ks web --dev from the installed Python)
102
+ shell: pwsh
103
+ run: |
104
+ $proc = Start-Process -FilePath "$env:APP\python\python.exe" -PassThru -NoNewWindow `
105
+ -ArgumentList '-m', 'il2ks', '--config', "$env:ProgramData\il2ks\il2ks.toml", 'web', '--dev', '--port', '18000'
106
+ $ok = $false
107
+ foreach ($i in 1..60) {
108
+ try { $r = Invoke-WebRequest -UseBasicParsing http://127.0.0.1:18000/ ; $ok = $true; break } catch { Start-Sleep 1 }
109
+ }
110
+ Stop-Process -Id $proc.Id -Force
111
+ if (-not $ok) { throw "the site did not answer" }
112
+
113
+ - name: Upgrade over an install with an outdated override warns in the log (silent mode)
114
+ shell: pwsh
115
+ run: |
116
+ # A copy of a built-in page, then its version line set back to v0: as if the new il2ks had changed that page.
117
+ $cfg = "$env:ProgramData\il2ks\il2ks.toml"
118
+ & "$env:APP\python\python.exe" -P -m il2ks --config $cfg custom copy il2ks/home.html
119
+ if ($LASTEXITCODE -ne 0) { throw "custom copy failed" }
120
+ $file = "$env:ProgramData\il2ks\custom\templates\il2ks\home.html"
121
+ $text = [IO.File]::ReadAllText($file)
122
+ $old = [regex]::Match($text, 'il2ks/home\.html v\d+').Value
123
+ if (-not $old) { throw "the copy has no version line" }
124
+ [IO.File]::WriteAllText($file, $text.Replace($old, 'il2ks/home.html v0'))
125
+ & "$env:APP\python\python.exe" -P -m il2ks --config $cfg custom list --problems --fail-on-problems
126
+ if ($LASTEXITCODE -ne 4) { throw "expected exit code 4 (override out of date), got $LASTEXITCODE" }
127
+ # Install the same build again over it: an upgrade (il2ks.toml exists), silent, so no message box
128
+ $exe = (Get-ChildItem installer\il2ks-setup-*.exe).FullName
129
+ $args = @('/VERYSILENT', '/SUPPRESSMSGBOXES', '/NORESTART', '/SP-', "/DIR=$env:APP", "/LOG=$env:RUNNER_TEMP\upgrade.log",
130
+ '/NOSERVICE', '/NOFIREWALL', '/MERGETASKS=!firewall')
131
+ .github\scripts\run-installer.ps1 -Exe $exe -LogFile "$env:RUNNER_TEMP\upgrade.log" -Arguments $args
132
+ $report = "$env:ProgramData\il2ks\logs\installer-custom-check.log"
133
+ if (-not (Test-Path $report)) { throw "no ${report}: the upgrade did not check the customized templates" }
134
+ Get-Content $report
135
+ if ((Get-Content $report -Raw) -notmatch 'templates/il2ks/home\.html') { throw "the report does not name the outdated override" }
136
+ if ((Get-Content "$env:RUNNER_TEMP\upgrade.log" -Raw) -notmatch 'customized file\(s\)') { throw "the installer log has no warning" }
137
+ exit 0 # $LASTEXITCODE is still 4 from the expected `custom list --fail-on-problems` above
138
+
139
+ - name: Uninstall keeps the data
140
+ shell: pwsh
141
+ run: |
142
+ $p = Start-Process -FilePath "$env:APP\unins000.exe" -ArgumentList '/VERYSILENT', '/SUPPRESSMSGBOXES', '/NORESTART' -Wait -PassThru
143
+ if ($p.ExitCode -ne 0) { throw "uninstaller exit code $($p.ExitCode)" }
144
+ Start-Sleep 3
145
+ if (Test-Path "$env:APP\python") { throw "program files are still there" }
146
+ if (-not (Test-Path "$env:ProgramData\il2ks\il2ks.toml")) { throw "the data folder was deleted" }
147
+
148
+ service-test:
149
+ # The real thing on a disposable runner: register the Windows service, start it, stop it the way Windows does, remove it.
150
+ # Informational until it has passed on a real runner a few times (continue-on-error), because it cannot be run elsewhere.
151
+ needs: build
152
+ if: github.event_name == 'push' || inputs.service_test
153
+ runs-on: windows-latest
154
+ timeout-minutes: 30
155
+ continue-on-error: true
156
+ steps:
157
+ - uses: actions/checkout@v7 # only for .github/scripts/run-installer.ps1
158
+ - uses: actions/download-artifact@v8
159
+ with:
160
+ name: il2ks-windows-installer
161
+ path: installer
162
+
163
+ - name: "Install with the service (own-proxy mode: no ports 80/443 needed)"
164
+ shell: pwsh
165
+ run: |
166
+ $exe = (Get-ChildItem installer\il2ks-setup-*.exe).FullName
167
+ $logs = Join-Path $env:RUNNER_TEMP 'dserver-logs'
168
+ $pw = Join-Path $env:RUNNER_TEMP 'il2ks-admin-password.txt'
169
+ Set-Content -Path $pw -Value 'Correct-Horse-Battery-9' -Encoding ascii
170
+ New-Item -ItemType Directory -Force $logs | Out-Null
171
+ $args = @('/VERYSILENT', '/SUPPRESSMSGBOXES', '/NORESTART', '/SP-', "/LOG=$env:RUNNER_TEMP\setup.log", '/NOFIREWALL',
172
+ '/HTTPS=external', '/DOMAIN=stats.example.org', "/LOGDIR=$logs", '/TIMEZONE=UTC',
173
+ '/ADMINUSER=ci', "/ADMINPASSWORDFILE=$pw")
174
+ .github\scripts\run-installer.ps1 -Exe $exe -LogFile "$env:RUNNER_TEMP\setup.log" -Arguments $args
175
+
176
+ - name: The service is running and the site answers
177
+ shell: pwsh
178
+ run: |
179
+ $svc = Get-Service il2ks
180
+ if ($svc.Status -ne 'Running') { throw "service status: $($svc.Status)" }
181
+ $account = (Get-CimInstance Win32_Service -Filter "Name='il2ks'").StartName
182
+ if ($account -ne 'NT SERVICE\il2ks') { throw "the service runs as '$account', not as its virtual account" }
183
+ $ok = $false
184
+ foreach ($i in 1..90) {
185
+ try {
186
+ # production mode redirects plain http to https unless the proxy says it already did
187
+ $r = Invoke-WebRequest -UseBasicParsing -Headers @{ 'X-Forwarded-Proto' = 'https'; Host = 'stats.example.org' } http://127.0.0.1:8000/
188
+ $ok = $true; break
189
+ } catch { Start-Sleep 1 }
190
+ }
191
+ if (-not $ok) { Get-ChildItem "$env:ProgramData\il2ks\logs" -Recurse | ForEach-Object { "== $($_.FullName)"; Get-Content $_.FullName -Tail 20 }; throw "the site did not answer" }
192
+
193
+ - name: Stopping the service stops il2ks gracefully and leaves nothing behind
194
+ shell: pwsh
195
+ run: |
196
+ Stop-Service il2ks
197
+ Start-Sleep 3
198
+ $left = Get-Process -Name python, caddy -ErrorAction SilentlyContinue | Where-Object { $_.Path -like "$env:ProgramFiles\il2ks\*" }
199
+ Get-ChildItem "$env:ProgramData\il2ks\logs" -Filter 'run-*.log' | ForEach-Object { Get-Content $_.FullName -Tail 12 }
200
+ if ($left) { throw "processes left behind: $($left.Id -join ', ')" }
201
+ $log = Get-ChildItem "$env:ProgramData\il2ks\logs" -Filter 'run-*.log' | ForEach-Object { Get-Content $_.FullName } | Out-String
202
+ if ($log -notmatch '"message": "stopped"') { throw "il2ks run did not log a clean stop (it was killed)" }
203
+ Start-Service il2ks
204
+
205
+ - name: Uninstall removes the service
206
+ shell: pwsh
207
+ run: |
208
+ $p = Start-Process -FilePath "$env:ProgramFiles\il2ks\unins000.exe" -ArgumentList '/VERYSILENT', '/SUPPRESSMSGBOXES', '/NORESTART' -Wait -PassThru
209
+ if ($p.ExitCode -ne 0) { throw "uninstaller exit code $($p.ExitCode)" }
210
+ Start-Sleep 5
211
+ if (Get-Service il2ks -ErrorAction SilentlyContinue) { throw "the service is still registered" }
212
+ if (-not (Test-Path "$env:ProgramData\il2ks\il2ks.toml")) { throw "the data folder was deleted" }
213
+
214
+ release:
215
+ needs: smoke
216
+ if: startsWith(github.ref, 'refs/tags/v')
217
+ runs-on: ubuntu-latest
218
+ permissions:
219
+ contents: write # attach the installer to the GitHub release
220
+ steps:
221
+ - uses: actions/download-artifact@v8
222
+ with:
223
+ name: il2ks-windows-installer
224
+ path: installer
225
+ - name: Attach the installer to the release (created if the PyPI release workflow has not made one)
226
+ env:
227
+ GH_TOKEN: ${{ github.token }}
228
+ GH_REPO: ${{ github.repository }}
229
+ run: |
230
+ gh release view "$GITHUB_REF_NAME" > /dev/null 2>&1 || gh release create "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" --generate-notes
231
+ sha256sum installer/*.exe | tee installer/SHA256SUMS.txt
232
+ gh release upload "$GITHUB_REF_NAME" installer/*.exe installer/SHA256SUMS.txt --clobber