├── pyproject.toml ├── connector ├── requirements │ ├── base.in │ ├── dev.in │ ├── Makefile │ ├── base.txt │ └── dev.txt ├── Makefile ├── Dockerfile └── test │ └── test_connector.py ├── map ├── Makefile ├── requirements │ ├── base.in │ ├── dev.in │ ├── Makefile │ ├── base.txt │ └── dev.txt ├── frontend │ ├── static │ │ └── images │ │ │ ├── aircraft_0.png │ │ │ ├── aircraft_1.png │ │ │ ├── aircraft_2.png │ │ │ ├── aircraft_3.png │ │ │ ├── aircraft_4.png │ │ │ ├── aircraft_5.png │ │ │ ├── aircraft_6.png │ │ │ ├── aircraft_7.png │ │ │ ├── aircraft_8.png │ │ │ ├── aircraft_9.png │ │ │ ├── aircraft_10.png │ │ │ ├── aircraft_100.png │ │ │ ├── aircraft_101.png │ │ │ ├── aircraft_102.png │ │ │ ├── aircraft_103.png │ │ │ ├── aircraft_104.png │ │ │ ├── aircraft_105.png │ │ │ ├── aircraft_106.png │ │ │ ├── aircraft_107.png │ │ │ ├── aircraft_108.png │ │ │ ├── aircraft_109.png │ │ │ ├── aircraft_11.png │ │ │ ├── aircraft_110.png │ │ │ ├── aircraft_111.png │ │ │ ├── aircraft_112.png │ │ │ ├── aircraft_113.png │ │ │ ├── aircraft_114.png │ │ │ ├── aircraft_115.png │ │ │ ├── aircraft_116.png │ │ │ ├── aircraft_117.png │ │ │ ├── aircraft_118.png │ │ │ ├── aircraft_119.png │ │ │ ├── aircraft_12.png │ │ │ ├── aircraft_120.png │ │ │ ├── aircraft_121.png │ │ │ ├── aircraft_122.png │ │ │ ├── aircraft_123.png │ │ │ ├── aircraft_124.png │ │ │ ├── aircraft_125.png │ │ │ ├── aircraft_126.png │ │ │ ├── aircraft_127.png │ │ │ ├── aircraft_128.png │ │ │ ├── aircraft_129.png │ │ │ ├── aircraft_13.png │ │ │ ├── aircraft_130.png │ │ │ ├── aircraft_131.png │ │ │ ├── aircraft_132.png │ │ │ ├── aircraft_133.png │ │ │ ├── aircraft_134.png │ │ │ ├── aircraft_135.png │ │ │ ├── aircraft_136.png │ │ │ ├── aircraft_137.png │ │ │ ├── aircraft_138.png │ │ │ ├── aircraft_139.png │ │ │ ├── aircraft_14.png │ │ │ ├── aircraft_140.png │ │ │ ├── aircraft_141.png │ │ │ ├── aircraft_142.png │ │ │ ├── aircraft_143.png │ │ │ ├── aircraft_144.png │ │ │ ├── aircraft_145.png │ │ │ ├── aircraft_146.png │ │ │ ├── aircraft_147.png │ │ │ ├── aircraft_148.png │ │ │ ├── aircraft_149.png │ │ │ ├── aircraft_15.png │ │ │ ├── aircraft_150.png │ │ │ ├── aircraft_151.png │ │ │ ├── aircraft_152.png │ │ │ ├── aircraft_153.png │ │ │ ├── aircraft_154.png │ │ │ ├── aircraft_155.png │ │ │ ├── aircraft_156.png │ │ │ ├── aircraft_157.png │ │ │ ├── aircraft_158.png │ │ │ ├── aircraft_159.png │ │ │ ├── aircraft_16.png │ │ │ ├── aircraft_160.png │ │ │ ├── aircraft_161.png │ │ │ ├── aircraft_162.png │ │ │ ├── aircraft_163.png │ │ │ ├── aircraft_164.png │ │ │ ├── aircraft_165.png │ │ │ ├── aircraft_166.png │ │ │ ├── aircraft_167.png │ │ │ ├── aircraft_168.png │ │ │ ├── aircraft_169.png │ │ │ ├── aircraft_17.png │ │ │ ├── aircraft_170.png │ │ │ ├── aircraft_171.png │ │ │ ├── aircraft_172.png │ │ │ ├── aircraft_173.png │ │ │ ├── aircraft_174.png │ │ │ ├── aircraft_175.png │ │ │ ├── aircraft_176.png │ │ │ ├── aircraft_177.png │ │ │ ├── aircraft_178.png │ │ │ ├── aircraft_179.png │ │ │ ├── aircraft_18.png │ │ │ ├── aircraft_180.png │ │ │ ├── aircraft_181.png │ │ │ ├── aircraft_182.png │ │ │ ├── aircraft_183.png │ │ │ ├── aircraft_184.png │ │ │ ├── aircraft_185.png │ │ │ ├── aircraft_186.png │ │ │ ├── aircraft_187.png │ │ │ ├── aircraft_188.png │ │ │ ├── aircraft_189.png │ │ │ ├── aircraft_19.png │ │ │ ├── aircraft_190.png │ │ │ ├── aircraft_191.png │ │ │ ├── aircraft_192.png │ │ │ ├── aircraft_193.png │ │ │ ├── aircraft_194.png │ │ │ ├── aircraft_195.png │ │ │ ├── aircraft_196.png │ │ │ ├── aircraft_197.png │ │ │ ├── aircraft_198.png │ │ │ ├── aircraft_199.png │ │ │ ├── aircraft_20.png │ │ │ ├── aircraft_200.png │ │ │ ├── aircraft_201.png │ │ │ ├── aircraft_202.png │ │ │ ├── aircraft_203.png │ │ │ ├── aircraft_204.png │ │ │ ├── aircraft_205.png │ │ │ ├── aircraft_206.png │ │ │ ├── aircraft_207.png │ │ │ ├── aircraft_208.png │ │ │ ├── aircraft_209.png │ │ │ ├── aircraft_21.png │ │ │ ├── aircraft_210.png │ │ │ ├── aircraft_211.png │ │ │ ├── aircraft_212.png │ │ │ ├── aircraft_213.png │ │ │ ├── aircraft_214.png │ │ │ ├── aircraft_215.png │ │ │ ├── aircraft_216.png │ │ │ ├── aircraft_217.png │ │ │ ├── aircraft_218.png │ │ │ ├── aircraft_219.png │ │ │ ├── aircraft_22.png │ │ │ ├── aircraft_220.png │ │ │ ├── aircraft_221.png │ │ │ ├── aircraft_222.png │ │ │ ├── aircraft_223.png │ │ │ ├── aircraft_224.png │ │ │ ├── aircraft_225.png │ │ │ ├── aircraft_226.png │ │ │ ├── aircraft_227.png │ │ │ ├── aircraft_228.png │ │ │ ├── aircraft_229.png │ │ │ ├── aircraft_23.png │ │ │ ├── aircraft_230.png │ │ │ ├── aircraft_231.png │ │ │ ├── aircraft_232.png │ │ │ ├── aircraft_233.png │ │ │ ├── aircraft_234.png │ │ │ ├── aircraft_235.png │ │ │ ├── aircraft_236.png │ │ │ ├── aircraft_237.png │ │ │ ├── aircraft_238.png │ │ │ ├── aircraft_239.png │ │ │ ├── aircraft_24.png │ │ │ ├── aircraft_240.png │ │ │ ├── aircraft_241.png │ │ │ ├── aircraft_242.png │ │ │ ├── aircraft_243.png │ │ │ ├── aircraft_244.png │ │ │ ├── aircraft_245.png │ │ │ ├── aircraft_246.png │ │ │ ├── aircraft_247.png │ │ │ ├── aircraft_248.png │ │ │ ├── aircraft_249.png │ │ │ ├── aircraft_25.png │ │ │ ├── aircraft_250.png │ │ │ ├── aircraft_251.png │ │ │ ├── aircraft_252.png │ │ │ ├── aircraft_253.png │ │ │ ├── aircraft_254.png │ │ │ ├── aircraft_255.png │ │ │ ├── aircraft_256.png │ │ │ ├── aircraft_257.png │ │ │ ├── aircraft_258.png │ │ │ ├── aircraft_259.png │ │ │ ├── aircraft_26.png │ │ │ ├── aircraft_260.png │ │ │ ├── aircraft_261.png │ │ │ ├── aircraft_262.png │ │ │ ├── aircraft_263.png │ │ │ ├── aircraft_264.png │ │ │ ├── aircraft_265.png │ │ │ ├── aircraft_266.png │ │ │ ├── aircraft_267.png │ │ │ ├── aircraft_268.png │ │ │ ├── aircraft_269.png │ │ │ ├── aircraft_27.png │ │ │ ├── aircraft_270.png │ │ │ ├── aircraft_271.png │ │ │ ├── aircraft_272.png │ │ │ ├── aircraft_273.png │ │ │ ├── aircraft_274.png │ │ │ ├── aircraft_275.png │ │ │ ├── aircraft_276.png │ │ │ ├── aircraft_277.png │ │ │ ├── aircraft_278.png │ │ │ ├── aircraft_279.png │ │ │ ├── aircraft_28.png │ │ │ ├── aircraft_280.png │ │ │ ├── aircraft_281.png │ │ │ ├── aircraft_282.png │ │ │ ├── aircraft_283.png │ │ │ ├── aircraft_284.png │ │ │ ├── aircraft_285.png │ │ │ ├── aircraft_286.png │ │ │ ├── aircraft_287.png │ │ │ ├── aircraft_288.png │ │ │ ├── aircraft_289.png │ │ │ ├── aircraft_29.png │ │ │ ├── aircraft_290.png │ │ │ ├── aircraft_291.png │ │ │ ├── aircraft_292.png │ │ │ ├── aircraft_293.png │ │ │ ├── aircraft_294.png │ │ │ ├── aircraft_295.png │ │ │ ├── aircraft_296.png │ │ │ ├── aircraft_297.png │ │ │ ├── aircraft_298.png │ │ │ ├── aircraft_299.png │ │ │ ├── aircraft_30.png │ │ │ ├── aircraft_300.png │ │ │ ├── aircraft_301.png │ │ │ ├── aircraft_302.png │ │ │ ├── aircraft_303.png │ │ │ ├── aircraft_304.png │ │ │ ├── aircraft_305.png │ │ │ ├── aircraft_306.png │ │ │ ├── aircraft_307.png │ │ │ ├── aircraft_308.png │ │ │ ├── aircraft_309.png │ │ │ ├── aircraft_31.png │ │ │ ├── aircraft_310.png │ │ │ ├── aircraft_311.png │ │ │ ├── aircraft_312.png │ │ │ ├── aircraft_313.png │ │ │ ├── aircraft_314.png │ │ │ ├── aircraft_315.png │ │ │ ├── aircraft_316.png │ │ │ ├── aircraft_317.png │ │ │ ├── aircraft_318.png │ │ │ ├── aircraft_319.png │ │ │ ├── aircraft_32.png │ │ │ ├── aircraft_320.png │ │ │ ├── aircraft_321.png │ │ │ ├── aircraft_322.png │ │ │ ├── aircraft_323.png │ │ │ ├── aircraft_324.png │ │ │ ├── aircraft_325.png │ │ │ ├── aircraft_326.png │ │ │ ├── aircraft_327.png │ │ │ ├── aircraft_328.png │ │ │ ├── aircraft_329.png │ │ │ ├── aircraft_33.png │ │ │ ├── aircraft_330.png │ │ │ ├── aircraft_331.png │ │ │ ├── aircraft_332.png │ │ │ ├── aircraft_333.png │ │ │ ├── aircraft_334.png │ │ │ ├── aircraft_335.png │ │ │ ├── aircraft_336.png │ │ │ ├── aircraft_337.png │ │ │ ├── aircraft_338.png │ │ │ ├── aircraft_339.png │ │ │ ├── aircraft_34.png │ │ │ ├── aircraft_340.png │ │ │ ├── aircraft_341.png │ │ │ ├── aircraft_342.png │ │ │ ├── aircraft_343.png │ │ │ ├── aircraft_344.png │ │ │ ├── aircraft_345.png │ │ │ ├── aircraft_346.png │ │ │ ├── aircraft_347.png │ │ │ ├── aircraft_348.png │ │ │ ├── aircraft_349.png │ │ │ ├── aircraft_35.png │ │ │ ├── aircraft_350.png │ │ │ ├── aircraft_351.png │ │ │ ├── aircraft_352.png │ │ │ ├── aircraft_353.png │ │ │ ├── aircraft_354.png │ │ │ ├── aircraft_355.png │ │ │ ├── aircraft_356.png │ │ │ ├── aircraft_357.png │ │ │ ├── aircraft_358.png │ │ │ ├── aircraft_359.png │ │ │ ├── aircraft_36.png │ │ │ ├── aircraft_37.png │ │ │ ├── aircraft_38.png │ │ │ ├── aircraft_39.png │ │ │ ├── aircraft_40.png │ │ │ ├── aircraft_41.png │ │ │ ├── aircraft_42.png │ │ │ ├── aircraft_43.png │ │ │ ├── aircraft_44.png │ │ │ ├── aircraft_45.png │ │ │ ├── aircraft_46.png │ │ │ ├── aircraft_47.png │ │ │ ├── aircraft_48.png │ │ │ ├── aircraft_49.png │ │ │ ├── aircraft_50.png │ │ │ ├── aircraft_51.png │ │ │ ├── aircraft_52.png │ │ │ ├── aircraft_53.png │ │ │ ├── aircraft_54.png │ │ │ ├── aircraft_55.png │ │ │ ├── aircraft_56.png │ │ │ ├── aircraft_57.png │ │ │ ├── aircraft_58.png │ │ │ ├── aircraft_59.png │ │ │ ├── aircraft_60.png │ │ │ ├── aircraft_61.png │ │ │ ├── aircraft_62.png │ │ │ ├── aircraft_63.png │ │ │ ├── aircraft_64.png │ │ │ ├── aircraft_65.png │ │ │ ├── aircraft_66.png │ │ │ ├── aircraft_67.png │ │ │ ├── aircraft_68.png │ │ │ ├── aircraft_69.png │ │ │ ├── aircraft_70.png │ │ │ ├── aircraft_71.png │ │ │ ├── aircraft_72.png │ │ │ ├── aircraft_73.png │ │ │ ├── aircraft_74.png │ │ │ ├── aircraft_75.png │ │ │ ├── aircraft_76.png │ │ │ ├── aircraft_77.png │ │ │ ├── aircraft_78.png │ │ │ ├── aircraft_79.png │ │ │ ├── aircraft_80.png │ │ │ ├── aircraft_81.png │ │ │ ├── aircraft_82.png │ │ │ ├── aircraft_83.png │ │ │ ├── aircraft_84.png │ │ │ ├── aircraft_85.png │ │ │ ├── aircraft_86.png │ │ │ ├── aircraft_87.png │ │ │ ├── aircraft_88.png │ │ │ ├── aircraft_89.png │ │ │ ├── aircraft_90.png │ │ │ ├── aircraft_91.png │ │ │ ├── aircraft_92.png │ │ │ ├── aircraft_93.png │ │ │ ├── aircraft_94.png │ │ │ ├── aircraft_95.png │ │ │ ├── aircraft_96.png │ │ │ ├── aircraft_97.png │ │ │ ├── aircraft_98.png │ │ │ └── aircraft_99.png │ └── index.html ├── Dockerfile └── app.py ├── fids ├── Makefile ├── requirements │ ├── dev.in │ ├── base.in │ └── Makefile ├── test │ └── db │ │ ├── flights.db │ │ └── positions.db ├── Dockerfile ├── trig.py └── app.py ├── db-updater ├── Makefile ├── requirements │ ├── dev.in │ ├── base.in │ ├── Makefile │ ├── base.txt │ └── dev.txt └── Dockerfile ├── .gitignore ├── docs ├── architecture-diagram.png └── database.md ├── .env-sample ├── Makefile ├── ROADMAP.md ├── ci_ping_frontend.py ├── Makefile.inc ├── ci_performance_regression_test.sh ├── LICENSE.md ├── .github └── workflows │ ├── docker-publish.yml │ ├── dockerimage.yml │ └── codeql-analysis.yml ├── README.md └── docker-compose.yml /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 100 3 | -------------------------------------------------------------------------------- /connector/requirements/base.in: -------------------------------------------------------------------------------- 1 | confluent-kafka==1.8.2 2 | -------------------------------------------------------------------------------- /map/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | PROGNAME=map 4 | -------------------------------------------------------------------------------- /fids/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | PROGNAME=fids 4 | -------------------------------------------------------------------------------- /map/requirements/base.in: -------------------------------------------------------------------------------- 1 | Flask==2.3.2 2 | confluent-kafka==1.8.2 3 | -------------------------------------------------------------------------------- /connector/requirements/dev.in: -------------------------------------------------------------------------------- 1 | -c base.txt 2 | mypy 3 | black 4 | pylint -------------------------------------------------------------------------------- /fids/requirements/dev.in: -------------------------------------------------------------------------------- 1 | -c base.txt 2 | mypy 3 | black 4 | pylint 5 | -------------------------------------------------------------------------------- /map/requirements/dev.in: -------------------------------------------------------------------------------- 1 | -c base.txt 2 | mypy 3 | black 4 | pylint 5 | -------------------------------------------------------------------------------- /connector/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | PROGNAME=connector 4 | -------------------------------------------------------------------------------- /db-updater/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.inc 2 | 3 | PROGNAME=db-updater 4 | -------------------------------------------------------------------------------- /db-updater/requirements/dev.in: -------------------------------------------------------------------------------- 1 | -c base.txt 2 | mypy 3 | black 4 | pylint 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .env 3 | venv/ 4 | .python-version 5 | .mypy_cache/ 6 | -------------------------------------------------------------------------------- /fids/test/db/flights.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/fids/test/db/flights.db -------------------------------------------------------------------------------- /fids/test/db/positions.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/fids/test/db/positions.db -------------------------------------------------------------------------------- /docs/architecture-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/docs/architecture-diagram.png -------------------------------------------------------------------------------- /fids/requirements/base.in: -------------------------------------------------------------------------------- 1 | sqlalchemy==1.3.24 2 | Flask==1.1.4 3 | flask-cors==5.0.0 4 | psycopg2-binary==2.9.3 5 | requests 6 | -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_0.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_1.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_2.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_3.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_4.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_5.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_6.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_7.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_8.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_9.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_10.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_100.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_101.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_101.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_102.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_102.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_103.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_103.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_104.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_104.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_105.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_105.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_106.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_106.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_107.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_107.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_108.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_108.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_109.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_109.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_11.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_110.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_110.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_111.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_111.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_112.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_112.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_113.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_113.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_114.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_115.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_115.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_116.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_116.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_117.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_117.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_118.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_118.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_119.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_119.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_12.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_120.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_121.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_121.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_122.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_122.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_123.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_123.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_124.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_124.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_125.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_126.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_126.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_127.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_127.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_128.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_129.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_129.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_13.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_130.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_130.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_131.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_131.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_132.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_132.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_133.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_133.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_134.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_134.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_135.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_135.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_136.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_136.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_137.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_137.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_138.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_138.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_139.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_139.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_14.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_140.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_140.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_141.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_141.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_142.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_142.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_143.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_143.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_144.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_145.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_145.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_146.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_146.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_147.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_147.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_148.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_148.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_149.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_149.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_15.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_150.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_151.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_151.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_152.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_153.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_153.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_154.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_154.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_155.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_155.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_156.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_156.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_157.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_157.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_158.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_158.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_159.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_159.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_16.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_160.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_160.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_161.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_161.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_162.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_162.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_163.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_163.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_164.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_164.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_165.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_165.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_166.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_166.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_167.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_168.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_168.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_169.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_169.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_17.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_170.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_170.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_171.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_171.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_172.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_172.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_173.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_173.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_174.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_174.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_175.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_175.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_176.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_176.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_177.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_177.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_178.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_178.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_179.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_179.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_18.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_180.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_181.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_181.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_182.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_182.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_183.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_183.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_184.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_184.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_185.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_185.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_186.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_186.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_187.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_187.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_188.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_188.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_189.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_189.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_19.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_190.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_190.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_191.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_191.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_192.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_193.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_193.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_194.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_194.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_195.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_195.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_196.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_196.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_197.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_197.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_198.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_198.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_199.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_199.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_20.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_200.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_201.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_201.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_202.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_202.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_203.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_203.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_204.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_204.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_205.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_205.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_206.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_206.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_207.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_207.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_208.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_208.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_209.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_209.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_21.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_210.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_210.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_211.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_211.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_212.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_212.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_213.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_213.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_214.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_214.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_215.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_215.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_216.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_216.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_217.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_217.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_218.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_218.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_219.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_219.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_22.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_220.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_220.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_221.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_221.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_222.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_222.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_223.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_223.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_224.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_224.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_225.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_225.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_226.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_226.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_227.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_227.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_228.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_228.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_229.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_229.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_23.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_230.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_230.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_231.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_231.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_232.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_232.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_233.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_233.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_234.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_234.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_235.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_235.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_236.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_236.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_237.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_237.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_238.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_238.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_239.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_239.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_24.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_240.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_241.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_241.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_242.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_242.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_243.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_243.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_244.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_244.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_245.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_245.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_246.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_246.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_247.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_247.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_248.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_248.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_249.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_249.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_25.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_250.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_251.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_251.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_252.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_252.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_253.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_253.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_254.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_254.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_255.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_255.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_256.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_257.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_257.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_258.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_258.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_259.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_259.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_26.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_260.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_260.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_261.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_261.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_262.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_262.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_263.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_263.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_264.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_264.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_265.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_265.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_266.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_266.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_267.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_267.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_268.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_268.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_269.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_269.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_27.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_270.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_270.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_271.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_271.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_272.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_272.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_273.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_273.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_274.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_274.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_275.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_275.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_276.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_276.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_277.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_277.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_278.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_278.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_279.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_279.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_28.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_280.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_280.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_281.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_281.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_282.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_282.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_283.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_283.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_284.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_284.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_285.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_285.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_286.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_286.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_287.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_287.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_288.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_288.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_289.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_289.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_29.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_290.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_290.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_291.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_291.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_292.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_292.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_293.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_293.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_294.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_294.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_295.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_295.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_296.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_296.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_297.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_297.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_298.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_298.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_299.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_299.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_30.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_300.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_301.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_301.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_302.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_302.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_303.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_303.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_304.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_304.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_305.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_305.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_306.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_306.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_307.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_307.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_308.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_308.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_309.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_309.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_31.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_310.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_311.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_311.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_312.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_312.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_313.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_313.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_314.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_314.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_315.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_315.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_316.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_316.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_317.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_317.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_318.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_318.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_319.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_319.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_32.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_320.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_320.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_321.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_321.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_322.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_322.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_323.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_323.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_324.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_324.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_325.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_325.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_326.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_326.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_327.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_327.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_328.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_328.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_329.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_329.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_33.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_330.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_330.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_331.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_331.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_332.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_332.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_333.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_333.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_334.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_334.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_335.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_335.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_336.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_336.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_337.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_337.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_338.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_338.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_339.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_339.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_34.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_340.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_340.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_341.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_341.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_342.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_342.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_343.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_343.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_344.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_344.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_345.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_345.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_346.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_346.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_347.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_347.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_348.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_348.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_349.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_349.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_35.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_350.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_350.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_351.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_351.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_352.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_352.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_353.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_353.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_354.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_354.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_355.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_355.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_356.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_356.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_357.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_357.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_358.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_358.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_359.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_359.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_36.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_37.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_38.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_39.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_40.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_41.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_42.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_43.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_44.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_45.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_46.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_47.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_48.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_49.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_50.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_51.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_52.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_53.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_54.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_54.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_55.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_56.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_57.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_58.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_59.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_60.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_61.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_61.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_62.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_62.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_63.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_63.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_64.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_65.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_65.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_66.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_66.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_67.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_67.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_68.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_68.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_69.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_69.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_70.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_71.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_71.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_72.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_73.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_73.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_74.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_74.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_75.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_75.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_76.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_77.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_77.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_78.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_78.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_79.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_79.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_80.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_81.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_81.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_82.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_82.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_83.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_83.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_84.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_84.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_85.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_85.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_86.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_86.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_87.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_88.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_88.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_89.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_89.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_90.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_91.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_91.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_92.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_92.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_93.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_93.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_94.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_94.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_95.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_95.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_96.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_97.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_97.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_98.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_98.png -------------------------------------------------------------------------------- /map/frontend/static/images/aircraft_99.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flightaware/firestarter/master/map/frontend/static/images/aircraft_99.png -------------------------------------------------------------------------------- /.env-sample: -------------------------------------------------------------------------------- 1 | FH_USERNAME=user 2 | FH_APIKEY=key 3 | INIT_CMD_ARGS=events "flifo departure arrival cancellation position" 4 | GOOGLE_MAPS_API_KEY=key 5 | -------------------------------------------------------------------------------- /db-updater/requirements/base.in: -------------------------------------------------------------------------------- 1 | sqlalchemy==1.3.24 2 | # optional, if postgres support is desired 3 | psycopg2-binary==2.9.3 4 | confluent-kafka==1.8.2 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | run: 2 | docker-compose build --parallel && docker-compose up 3 | 4 | run-background: 5 | docker-compose build --parallel && docker-compose up -d 6 | -------------------------------------------------------------------------------- /fids/requirements/Makefile: -------------------------------------------------------------------------------- 1 | objects = $(wildcard *.in) 2 | outputs := $(objects:.in=.txt) 3 | 4 | .PHONY: all 5 | all: $(outputs) 6 | 7 | %.txt: %.in 8 | . ../venv/bin/activate && pip-compile --verbose --build-isolation --generate-hashes --output-file $@ $< 9 | 10 | test.txt: base.txt 11 | -------------------------------------------------------------------------------- /map/requirements/Makefile: -------------------------------------------------------------------------------- 1 | objects = $(wildcard *.in) 2 | outputs := $(objects:.in=.txt) 3 | 4 | .PHONY: all 5 | all: $(outputs) 6 | 7 | %.txt: %.in 8 | . ../venv/bin/activate && pip-compile --verbose --build-isolation --generate-hashes --output-file $@ $< 9 | 10 | test.txt: base.txt 11 | -------------------------------------------------------------------------------- /connector/requirements/Makefile: -------------------------------------------------------------------------------- 1 | objects = $(wildcard *.in) 2 | outputs := $(objects:.in=.txt) 3 | 4 | .PHONY: all 5 | all: $(outputs) 6 | 7 | %.txt: %.in 8 | . ../venv/bin/activate && pip-compile --verbose --build-isolation --generate-hashes --output-file $@ $< 9 | 10 | dev.txt: base.txt 11 | -------------------------------------------------------------------------------- /db-updater/requirements/Makefile: -------------------------------------------------------------------------------- 1 | objects = $(wildcard *.in) 2 | outputs := $(objects:.in=.txt) 3 | 4 | .PHONY: all 5 | all: $(outputs) 6 | 7 | %.txt: %.in 8 | . ../venv/bin/activate && pip-compile --verbose --build-isolation --generate-hashes --output-file $@ $< 9 | 10 | test.txt: base.txt 11 | -------------------------------------------------------------------------------- /connector/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim-bullseye 2 | 3 | LABEL org.opencontainers.image.source=https://github.com/flightaware/firestarter 4 | 5 | RUN apt-get update && apt-get install -y build-essential librdkafka-dev 6 | RUN id -u firestarter || useradd -u 8081 firestarter -c "FIRESTARTER User" -m -s /bin/sh 7 | USER firestarter 8 | WORKDIR /home/firestarter 9 | 10 | COPY --chown=firestarter Makefile.inc . 11 | 12 | RUN mkdir app 13 | WORKDIR /home/firestarter/app 14 | COPY --chown=firestarter connector/requirements ./requirements 15 | COPY --chown=firestarter connector/Makefile . 16 | 17 | RUN make docker-setup 18 | ENV VIRTUAL_ENV=./venv 19 | ENV PATH="$VIRTUAL_ENV/bin:$PATH" 20 | 21 | COPY --chown=firestarter connector/main.py . 22 | 23 | CMD ["python3", "main.py"] 24 | 25 | -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | # Roadmap 2 | ### v1 3 | Firestarter v1 contains 2 services and an example application. With these 4 | components you can track flights at the granularity of departures and arrivals 5 | (using flight info messages) and view them in a FIDS-like interface. 6 | 7 | ### v2 8 | Firestarter v2 will introduce a robust queueing component between the connector 9 | and its clients, allowing for efficient data fan-out. 10 | 11 | ### v3 (current release) 12 | Firestarter v3 adds support for processing and storage of airborne position data 13 | from Firehose. It will likely also include a sample application for viewing such 14 | data. 15 | 16 | ### v4 17 | Firestarter v4 will support processing and storage of surface position data from 18 | Firehose. It will likely also include a sample application for viewing such 19 | data. 20 | -------------------------------------------------------------------------------- /db-updater/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim-bullseye 2 | 3 | LABEL org.opencontainers.image.source=https://github.com/flightaware/firestarter 4 | 5 | RUN apt-get update && apt-get install -y libpq-dev build-essential sqlite3 postgresql-client librdkafka-dev 6 | RUN id -u firestarter || useradd -u 8081 firestarter -c "FIRESTARTER User" -m -s /bin/sh 7 | USER firestarter 8 | WORKDIR /home/firestarter 9 | 10 | COPY --chown=firestarter Makefile.inc . 11 | 12 | RUN mkdir app 13 | WORKDIR /home/firestarter/app 14 | RUN mkdir db 15 | COPY --chown=firestarter db-updater/requirements ./requirements 16 | COPY --chown=firestarter db-updater/Makefile . 17 | 18 | RUN make docker-setup 19 | ENV VIRTUAL_ENV=./venv 20 | ENV PATH="$VIRTUAL_ENV/bin:$PATH" 21 | 22 | COPY --chown=firestarter db-updater/main.py . 23 | 24 | CMD ["python3", "main.py"] 25 | -------------------------------------------------------------------------------- /ci_ping_frontend.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | from selenium import webdriver 4 | from selenium.webdriver.chrome.options import Options 5 | from webdriver_manager.chrome import ChromeDriverManager 6 | import time 7 | 8 | class NoAirportsFound(Exception): 9 | pass 10 | 11 | time.sleep(30) 12 | 13 | chrome_options = Options() 14 | chrome_options.add_argument("--headless") 15 | chrome_options.binary_location = '/usr/bin/google-chrome' 16 | 17 | driver = webdriver.Chrome(executable_path=ChromeDriverManager().install(), chrome_options=chrome_options) 18 | driver.get('http://localhost:8080/') 19 | page_output = driver.page_source 20 | 21 | p = re.compile("airport-list-link.*?>([A-Z]{4})") 22 | airports = p.findall(page_output) 23 | 24 | if len(airports) > 0: 25 | print(airports) 26 | else: 27 | raise NoAirportsFound() 28 | 29 | driver.quit() 30 | -------------------------------------------------------------------------------- /fids/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim-bullseye 2 | 3 | LABEL org.opencontainers.image.source=https://github.com/flightaware/firestarter 4 | 5 | RUN apt-get update && \ 6 | apt-get install -y libpq-dev build-essential 7 | RUN id -u firestarter || useradd -u 8081 firestarter -c "FIRESTARTER User" -m -s /bin/sh 8 | USER firestarter 9 | WORKDIR /home/firestarter 10 | 11 | COPY --chown=firestarter Makefile.inc . 12 | 13 | RUN mkdir app 14 | WORKDIR /home/firestarter/app 15 | 16 | RUN mkdir db 17 | COPY --chown=firestarter fids/requirements ./requirements 18 | COPY --chown=firestarter fids/Makefile . 19 | 20 | ENV FLASK_APP=app.py 21 | ENV FLASK_ENV=development 22 | 23 | RUN make docker-setup 24 | ENV VIRTUAL_ENV=./venv 25 | ENV PATH="$VIRTUAL_ENV/bin:$PATH" 26 | 27 | COPY --chown=firestarter fids/app.py . 28 | COPY --chown=firestarter fids/trig.py . 29 | 30 | CMD ["python3", "app.py"] 31 | -------------------------------------------------------------------------------- /map/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim-bullseye 2 | 3 | LABEL org.opencontainers.image.source=https://github.com/flightaware/firestarter 4 | 5 | RUN apt-get update && \ 6 | apt-get install -y npm build-essential librdkafka-dev && \ 7 | npm install npm@latest -g 8 | RUN id -u firestarter || useradd -u 8081 firestarter -c "FIRESTARTER User" -m -s /bin/sh 9 | USER firestarter 10 | WORKDIR /home/firestarter 11 | 12 | COPY --chown=firestarter Makefile.inc . 13 | 14 | RUN mkdir app 15 | WORKDIR /home/firestarter/app 16 | 17 | COPY --chown=firestarter map/requirements ./requirements 18 | COPY --chown=firestarter map/Makefile . 19 | 20 | ENV FLASK_APP=app.py 21 | ENV FLASK_ENV=development 22 | 23 | RUN make docker-setup 24 | ENV VIRTUAL_ENV=./venv 25 | ENV PATH="$VIRTUAL_ENV/bin:$PATH" 26 | 27 | COPY --chown=firestarter map/frontend frontend 28 | COPY --chown=firestarter map/app.py . 29 | 30 | CMD ["python3", "app.py"] 31 | -------------------------------------------------------------------------------- /fids/trig.py: -------------------------------------------------------------------------------- 1 | from math import degrees, radians, sin, cos, atan2 2 | from typing import Tuple 3 | 4 | 5 | def get_bearing_degrees(coord1: Tuple[float, float], coord2: Tuple[float, float]) -> float: 6 | """Get bearing in degrees between 2 sets of coordinates""" 7 | r_lat1 = radians(coord1[0]) 8 | r_lon1 = radians(coord1[1]) 9 | r_lat2 = radians(coord2[0]) 10 | r_lon2 = radians(coord2[1]) 11 | d_lon = r_lon2 - r_lon1 12 | y = sin(d_lon) * cos(r_lat2) 13 | x = cos(r_lat1) * sin(r_lat2) - sin(r_lat1) * cos(r_lat2) * cos(d_lon) 14 | bearing = degrees(atan2(y, x)) 15 | bearing = (bearing + 360) % 360 16 | return bearing 17 | 18 | 19 | def get_cardinal_for_angle(angle_degrees: float) -> int: 20 | """Approximate an angle in degrees to 1 of 4 cardinal directions""" 21 | if 45 <= angle_degrees < 135: 22 | return 90 23 | elif 135 <= angle_degrees < 225: 24 | return 180 25 | elif 225 <= angle_degrees < 315: 26 | return 270 27 | else: 28 | return 0 29 | -------------------------------------------------------------------------------- /Makefile.inc: -------------------------------------------------------------------------------- 1 | BLACK=black 2 | PYLINT=pylint 3 | PYTHON=python3 4 | 5 | venv: venv/bin/activate 6 | 7 | venv/bin/activate: 8 | test -d venv || $(PYTHON) -m venv venv 9 | . venv/bin/activate && $(PYTHON) -m pip install pip-tools && $(PYTHON) -m pip install --upgrade setuptools 10 | 11 | pip-compile: venv 12 | . venv/bin/activate && make -C requirements all 13 | 14 | pip-sync: venv pip-compile 15 | . venv/bin/activate && venv/bin/pip-sync $(wildcard requirements/*.txt) 16 | 17 | pip-sync-ci: 18 | $(PYTHON) -m pip install pip-tools 19 | pip-sync $(wildcard requirements/*.txt) 20 | 21 | docker-setup: venv pip-sync 22 | 23 | type-check: 24 | . venv/bin/activate && mypy --check-untyped-defs . 25 | 26 | format: 27 | . venv/bin/activate && $(PYTHON) -m $(BLACK) --line-length=100 . 28 | 29 | lint: 30 | . venv/bin/activate && $(PYTHON) -m $(PYLINT) *.py 31 | 32 | check: lint type-check 33 | 34 | test: 35 | . venv/bin/activate && $(PYTHON) -m unittest discover -s test 36 | 37 | test-ci: 38 | $(PYTHON) -m unittest discover -s test 39 | 40 | run: 41 | docker-compose -f ../docker-compose.yml up --build $(PROGNAME) 42 | 43 | .PHONY: venv pip-compile pip-sync docker-setup type-check format lint check test run 44 | -------------------------------------------------------------------------------- /ci_performance_regression_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | start=$(date +%s) 4 | 5 | sleep 300 6 | 7 | dbupdater_container=$(docker ps | grep firestarter_db-updater_1 | awk 'NF>1{print $NF}') 8 | flights_count=$(docker exec -i ${dbupdater_container} sqlite3 /home/firestarter/app/db/flights.db 'SELECT COUNT(*) FROM flights') 9 | 10 | timescaledb_container=$(docker ps | grep firestarter_timescaledb_1 | awk 'NF>1{print $NF}') 11 | positions_count=$(docker exec -i ${timescaledb_container} psql -qAt -U postgres -c 'SELECT COUNT(*) FROM positions') 12 | 13 | positions_time_processed=$(docker exec -i ${timescaledb_container} psql -qAt -U postgres -c 'SELECT MAX(extract(epoch from time)) - MIN(extract(epoch from time)) as time_diff FROM positions' | tr -d '\r') 14 | 15 | end=$(date +%s) 16 | 17 | echo "Flights Count: ${flights_count}" 18 | echo "Positions Count: ${positions_count}" 19 | 20 | if [[ $flights_count -lt 45000 ]]; then 21 | echo "Flight count lower than threshold 45000" 22 | docker-compose logs 23 | exit 1 24 | fi 25 | 26 | if [[ $positions_count -lt 200000 ]]; then 27 | echo "Position count lower than threshold 200000" 28 | docker-compose logs 29 | exit 1 30 | fi 31 | 32 | echo "Position catch-up rate: x$(($positions_time_processed / ($end - $start)))" 33 | 34 | exit 0 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, FlightAware 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /.github/workflows/docker-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Docker image 2 | 3 | on: 4 | push: 5 | # Publish `master` as Docker `latest` image. 6 | branches: 7 | - master 8 | 9 | # Publish `v1.2.3` tags as releases. 10 | tags: 11 | - v* 12 | 13 | workflow_dispatch: 14 | # Allow manually triggered builds too. 15 | 16 | env: 17 | CONNECTOR_IMAGE_NAME: connector 18 | DB_UPDATER_IMAGE_NAME: db-updater 19 | FIDS_IMAGE_NAME: fids-backend 20 | MAP_IMAGE_NAME: map 21 | FH_USERNAME: dummy 22 | FH_APIKEY: dummy 23 | FS_VERSION: latest 24 | 25 | jobs: 26 | # Push image to GitHub Packages. 27 | # See also https://docs.docker.com/docker-hub/builds/ 28 | push: 29 | 30 | runs-on: ubuntu-latest 31 | if: github.event_name == 'push' 32 | 33 | steps: 34 | - uses: actions/checkout@v2 35 | 36 | - name: Build images 37 | run: | 38 | # Strip git ref prefix from version 39 | FS_VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') 40 | 41 | # Use Docker `latest` tag convention 42 | [ "$FS_VERSION" == "master" ] && FS_VERSION=latest 43 | 44 | echo "FS_VERSION=$FS_VERSION" >> $GITHUB_ENV 45 | 46 | docker-compose build --parallel $CONNECTOR_IMAGE_NAME $DB_UPDATER_IMAGE_NAME $FIDS_IMAGE_NAME $MAP_IMAGE_NAME 47 | 48 | - name: Log into registry 49 | run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ secrets.GHCR_USER }} --password-stdin 50 | 51 | - name: Push images 52 | run: 53 | docker-compose push $CONNECTOR_IMAGE_NAME $DB_UPDATER_IMAGE_NAME $FIDS_IMAGE_NAME $MAP_IMAGE_NAME 54 | -------------------------------------------------------------------------------- /connector/requirements/base.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with python 3.9 3 | # To update, run: 4 | # 5 | # pip-compile --generate-hashes --output-file=base.txt base.in 6 | # 7 | confluent-kafka==1.8.2 \ 8 | --hash=sha256:02b78bb6d1199ea350240eae1f4415f22014896199a46edf85f779a69751f984 \ 9 | --hash=sha256:039c68379f9a5ece6e45a683ec7abebb95a9dac904ec4e2f9d93738e1cf6fab2 \ 10 | --hash=sha256:1df83fa20e4fe032651ad73ce0ba85dd14a7fabff6066c9cb20e944d2748e72b \ 11 | --hash=sha256:3d66e8c1a6a15144ca5b176170adbf30207c27813c76202c56abf52ef2b475e1 \ 12 | --hash=sha256:4f26052ef53212752039cd1d9e932b2feb6a0975d717ab070af323629a72a0b9 \ 13 | --hash=sha256:585bc8e8aa7d6fbd46dc0b2da3d4b1fd8457555288fee1ecba6af2c97ab738cc \ 14 | --hash=sha256:748813f47641dd65dd8d3bae8dcb3ce96a3e455c12b467d4b35e1fc880362d01 \ 15 | --hash=sha256:ac7155e1b9a94445ed8eecf691c80c61407148813808a2aa1cba0babbe197e77 \ 16 | --hash=sha256:add05db627435697d4ed8f81b3ce1081931770813a989fd775910865f07d694d \ 17 | --hash=sha256:ae75d3f4bc3d2109663912d77911c45aaa2939bde3694fc05e75842c806fa760 \ 18 | --hash=sha256:b679c3f9f555e87a9cbb043c676473c30d12182609e075be85afd98f84bcc863 \ 19 | --hash=sha256:b79e836c3554bc51c6837a8a0152f7521c9bf31342f5b8e21eba6b28044fa585 \ 20 | --hash=sha256:b7cb6fa3d44972e3670e0b3b054186a6006e6fd664600cfe70e008fad2443d16 \ 21 | --hash=sha256:d50b091770d277714766943d885ad6b2c5c427e67328706cfd33dc86eef540c9 \ 22 | --hash=sha256:e49382a943fb47813f421e913cc6c87cd1d4bfdecad1785efa0dacada7003d84 \ 23 | --hash=sha256:ead7f18c516f7bcb886b643fa78ff2a2142270adaf931ba0311b62e9a047e6ca \ 24 | --hash=sha256:f843680e183479f6e0732b593ea3235c836a5bb2de6be3819a11b891b6af1dde 25 | # via -r base.in 26 | -------------------------------------------------------------------------------- /docs/database.md: -------------------------------------------------------------------------------- 1 | # Database support 2 | Firestarter offers flexibility in your choice of database. Its db-updater 3 | component is written on top of SQLAlchemy, a python library which supports many 4 | popular SQL databases (full listing at 5 | https://docs.sqlalchemy.org/en/13/dialects/index.html). By default, db-updater 6 | uses a sqlite database located on a Docker named volume. This allows the 7 | database file (located at `/home/firestarter/db/flights.db`) to persist between 8 | container restarts and allows sharing the database file with the fids 9 | component. Db-updater uses TimescaleDB for positions. TimescaleDB is a 10 | time-series database, so it is very efficient in handling time-series data like 11 | positions. It is also an extension of PostgreSQL, which has been fully tested 12 | in db-updater. 13 | 14 | When starting db-updater, it checks the database it's connected to ensure that 15 | the "flights" or "positions" table exists (depending on what it is intended to 16 | update). If no such table exists, it is created with the schema found 17 | [here](../db-updater/main.py). 18 | 19 | ## Customizing the database connection 20 | To use a different database than db-updater's default sqlite file, you just 21 | need to set the DB_URL environment variable. The syntax for this variable is 22 | described at https://docs.sqlalchemy.org/en/13/core/engines.html#database-urls. 23 | Here are a few examples of potential values for the variable: 24 | * `sqlite:///db/flights.db` 25 | This is the default DB_URL. It uses the sqlite dialect, and it opens the 26 | database located at `./db/flights.db` 27 | * `postgresql://postgres:password@10.1.1.1/flightdata` 28 | This is a sample PostgreSQL connection URL. It will connect to a database 29 | named "flightdata" running at the host with IP 10.1.1.1 with username 30 | "postgres" and password "password". The database does not need to be running 31 | in Docker; it just needs to be reachable from the container host. 32 | -------------------------------------------------------------------------------- /.github/workflows/dockerimage.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | push: 5 | branches: '**' 6 | workflow_dispatch: 7 | # Allow manually triggered builds too. 8 | 9 | env: 10 | KEEPALIVE: 60 11 | KEEPALIVE_STALE_PITRS: 5 12 | SERVER: firehose-test.flightaware.com 13 | PRINT_STATS_PERIOD: 0 14 | FH_USERNAME: ${{ secrets.FH_USERNAME }} 15 | FH_APIKEY: ${{ secrets.FH_APIKEY }} 16 | 17 | jobs: 18 | test: 19 | runs-on: ubuntu-latest 20 | strategy: 21 | matrix: 22 | node-version: [12.16.3] 23 | python-version: [3.9] 24 | steps: 25 | - name: Add secrets mask 26 | run: | 27 | echo "::add-mask::${{ secrets.FH_USERNAME }}" 28 | echo "::add-mask::${{ secrets.FH_APIKEY }}" 29 | - uses: actions/checkout@v2 30 | - name: Set up Python ${{ matrix.python-version }} 31 | uses: actions/setup-python@v2 32 | with: 33 | python-version: ${{ matrix.python-version }} 34 | - name: Setup Node.js ${{ matrix.node-version }} 35 | uses: actions/setup-node@v1 36 | with: 37 | node-version: ${{ matrix.node-version }} 38 | - name: Connector 39 | env: 40 | INIT_CMD_TIME: "pitr 1647160200" 41 | INIT_CMD_ARGS: "events \"flifo\"" 42 | KAFKA_TOPIC_NAME: feed1 43 | run: | 44 | cd connector 45 | make pip-sync-ci 46 | make test-ci 47 | 48 | - name: Db-updater 49 | env: 50 | KAFKA_TOPIC_NAME: feed1 51 | KAFKA_GROUP_NAME: group1 52 | run: | 53 | cd db-updater 54 | make pip-sync-ci 55 | make test-ci 56 | 57 | - name: Fids 58 | run: | 59 | cd fids 60 | make pip-sync-ci 61 | make test-ci 62 | 63 | - name: Full_Integration 64 | env: 65 | INIT_CMD_ARGS: "events \"flightplan departure arrival cancellation position\"" 66 | run: | 67 | docker-compose build --parallel 68 | docker-compose up -d 69 | python3 -m pip install webdriver-manager 70 | python3 -m pip install selenium 71 | python3 ci_ping_frontend.py 72 | docker-compose rm -fsv 73 | docker volume prune -f 74 | 75 | - name: Performance 76 | env: 77 | INIT_CMD_TIME: "pitr 1577880000" 78 | INIT_CMD_ARGS: "events \"flightplan departure arrival cancellation position\"" 79 | run: | 80 | docker-compose up -d 81 | ./ci_performance_regression_test.sh 82 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '39 19 * * 0' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | language: [ 'javascript', 'python' ] 32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 33 | # Learn more: 34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 35 | 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v2 39 | 40 | # Initializes the CodeQL tools for scanning. 41 | - name: Initialize CodeQL 42 | uses: github/codeql-action/init@v1 43 | with: 44 | languages: ${{ matrix.language }} 45 | # If you wish to specify custom queries, you can do so here or in a config file. 46 | # By default, queries listed here will override any specified in a config file. 47 | # Prefix the list here with "+" to use these queries and those in the config file. 48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 49 | 50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 51 | # If this step fails, then you should remove it and run the build manually (see below) 52 | - name: Autobuild 53 | uses: github/codeql-action/autobuild@v1 54 | 55 | # ℹ️ Command-line programs to run using the OS shell. 56 | # 📚 https://git.io/JvXDl 57 | 58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 59 | # and modify them (or add more) to build your code if your project 60 | # uses a compiled language 61 | 62 | #- run: | 63 | # make bootstrap 64 | # make release 65 | 66 | - name: Perform CodeQL Analysis 67 | uses: github/codeql-action/analyze@v1 68 | -------------------------------------------------------------------------------- /map/app.py: -------------------------------------------------------------------------------- 1 | """Forward flight events via SSE""" 2 | 3 | import os 4 | import random 5 | 6 | from confluent_kafka import KafkaException, Consumer # type: ignore 7 | from flask import Flask, Response, render_template, request 8 | 9 | 10 | app = Flask(__name__, template_folder="frontend", static_folder="frontend/static") 11 | 12 | @app.route("/") 13 | def index(): 14 | return render_template( 15 | "index.html", 16 | google_maps_api_key=os.environ.get("GOOGLE_MAPS_API_KEY", ""), 17 | startlive='live' in request.args) 18 | 19 | @app.route("/listen") 20 | def listen(): 21 | group = request.headers.get("Last-Event-ID", f"{os.environ['KAFKA_GROUP_NAME']}{random.randint(0, 10**9)}") 22 | live = 'live' in request.args 23 | def stream(): 24 | innergroup = group 25 | consumer = None 26 | while True: 27 | try: 28 | # Handle case where we initialized the consumer but failed to 29 | # subscribe. Don't want to keep initializing. 30 | if consumer is None: 31 | consumer = Consumer( 32 | { 33 | "bootstrap.servers": "kafka:9092", 34 | "group.id": innergroup, 35 | "auto.offset.reset": "latest" if live else "earliest", 36 | "enable.auto.commit": True, 37 | "auto.commit.interval.ms": 1000, 38 | } 39 | ) 40 | consumer.subscribe([os.environ["KAFKA_TOPIC_NAME"]]) 41 | break 42 | except (KafkaException, OSError) as error: 43 | # Consider providing some sort of status update to listener 44 | time.sleep(3) 45 | while True: 46 | # Polling will mask SIGINT, just fyi 47 | messagestr = consumer.poll(timeout=1.0) 48 | if messagestr is None: 49 | # poll timed out 50 | continue 51 | if messagestr.error(): 52 | # Consider providing to listener 53 | print(f"Encountered kafka error: {messagestr.error()}") 54 | # They continue in the examples, so let's do it as well 55 | continue 56 | yield as_sse(messagestr.value().decode(), id=innergroup) 57 | # Only send the id for the first message. We're kind of hijacking 58 | # the ID's purpose since it's really supposed to be unique per 59 | # message. We just need one ID for handling the group membership, 60 | # though. 61 | innergroup = None 62 | return Response(stream(), mimetype="text/event-stream") 63 | 64 | 65 | def as_sse(data, event=None, id=None): 66 | message = f"data: {data}" 67 | if event is not None: 68 | message = f"event: {event}\n{message}" 69 | if id is not None: 70 | message = f"{message}\nid: {id}" 71 | message = message + "\n\n" 72 | return message 73 | 74 | app.run(host="0.0.0.0", port=5001) 75 | -------------------------------------------------------------------------------- /map/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Live Flight Map 5 | 6 | 10 | 25 | 107 | 108 | 109 |
110 | 111 | 112 | -------------------------------------------------------------------------------- /map/requirements/base.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with python 3.8 3 | # To update, run: 4 | # 5 | # pip-compile --generate-hashes --output-file=base.txt base.in 6 | # 7 | blinker==1.6.2 \ 8 | --hash=sha256:4afd3de66ef3a9f8067559fb7a1cbe555c17dcbe15971b05d1b625c3e7abe213 \ 9 | --hash=sha256:c3d739772abb7bc2860abf5f2ec284223d9ad5c76da018234f6f50d6f31ab1f0 10 | # via flask 11 | click==8.1.3 \ 12 | --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ 13 | --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48 14 | # via flask 15 | confluent-kafka==1.8.2 \ 16 | --hash=sha256:02b78bb6d1199ea350240eae1f4415f22014896199a46edf85f779a69751f984 \ 17 | --hash=sha256:039c68379f9a5ece6e45a683ec7abebb95a9dac904ec4e2f9d93738e1cf6fab2 \ 18 | --hash=sha256:1df83fa20e4fe032651ad73ce0ba85dd14a7fabff6066c9cb20e944d2748e72b \ 19 | --hash=sha256:3d66e8c1a6a15144ca5b176170adbf30207c27813c76202c56abf52ef2b475e1 \ 20 | --hash=sha256:4f26052ef53212752039cd1d9e932b2feb6a0975d717ab070af323629a72a0b9 \ 21 | --hash=sha256:585bc8e8aa7d6fbd46dc0b2da3d4b1fd8457555288fee1ecba6af2c97ab738cc \ 22 | --hash=sha256:748813f47641dd65dd8d3bae8dcb3ce96a3e455c12b467d4b35e1fc880362d01 \ 23 | --hash=sha256:ac7155e1b9a94445ed8eecf691c80c61407148813808a2aa1cba0babbe197e77 \ 24 | --hash=sha256:add05db627435697d4ed8f81b3ce1081931770813a989fd775910865f07d694d \ 25 | --hash=sha256:ae75d3f4bc3d2109663912d77911c45aaa2939bde3694fc05e75842c806fa760 \ 26 | --hash=sha256:b679c3f9f555e87a9cbb043c676473c30d12182609e075be85afd98f84bcc863 \ 27 | --hash=sha256:b79e836c3554bc51c6837a8a0152f7521c9bf31342f5b8e21eba6b28044fa585 \ 28 | --hash=sha256:b7cb6fa3d44972e3670e0b3b054186a6006e6fd664600cfe70e008fad2443d16 \ 29 | --hash=sha256:d50b091770d277714766943d885ad6b2c5c427e67328706cfd33dc86eef540c9 \ 30 | --hash=sha256:e49382a943fb47813f421e913cc6c87cd1d4bfdecad1785efa0dacada7003d84 \ 31 | --hash=sha256:ead7f18c516f7bcb886b643fa78ff2a2142270adaf931ba0311b62e9a047e6ca \ 32 | --hash=sha256:f843680e183479f6e0732b593ea3235c836a5bb2de6be3819a11b891b6af1dde 33 | # via -r base.in 34 | flask==2.3.2 \ 35 | --hash=sha256:77fd4e1249d8c9923de34907236b747ced06e5467ecac1a7bb7115ae0e9670b0 \ 36 | --hash=sha256:8c2f9abd47a9e8df7f0c3f091ce9497d011dc3b31effcf4c85a6e2b50f4114ef 37 | # via -r base.in 38 | itsdangerous==2.1.2 \ 39 | --hash=sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44 \ 40 | --hash=sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a 41 | # via flask 42 | jinja2==3.1.2 \ 43 | --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ 44 | --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 45 | # via flask 46 | markupsafe==2.1.2 \ 47 | --hash=sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed \ 48 | --hash=sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc \ 49 | --hash=sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2 \ 50 | --hash=sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460 \ 51 | --hash=sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7 \ 52 | --hash=sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0 \ 53 | --hash=sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1 \ 54 | --hash=sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa \ 55 | --hash=sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03 \ 56 | --hash=sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323 \ 57 | --hash=sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65 \ 58 | --hash=sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013 \ 59 | --hash=sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036 \ 60 | --hash=sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f \ 61 | --hash=sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4 \ 62 | --hash=sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419 \ 63 | --hash=sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2 \ 64 | --hash=sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619 \ 65 | --hash=sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a \ 66 | --hash=sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a \ 67 | --hash=sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd \ 68 | --hash=sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7 \ 69 | --hash=sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666 \ 70 | --hash=sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65 \ 71 | --hash=sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859 \ 72 | --hash=sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625 \ 73 | --hash=sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff \ 74 | --hash=sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156 \ 75 | --hash=sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd \ 76 | --hash=sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba \ 77 | --hash=sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f \ 78 | --hash=sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1 \ 79 | --hash=sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094 \ 80 | --hash=sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a \ 81 | --hash=sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513 \ 82 | --hash=sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed \ 83 | --hash=sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d \ 84 | --hash=sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3 \ 85 | --hash=sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147 \ 86 | --hash=sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c \ 87 | --hash=sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603 \ 88 | --hash=sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601 \ 89 | --hash=sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a \ 90 | --hash=sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1 \ 91 | --hash=sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d \ 92 | --hash=sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3 \ 93 | --hash=sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54 \ 94 | --hash=sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2 \ 95 | --hash=sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6 \ 96 | --hash=sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58 97 | # via 98 | # jinja2 99 | # werkzeug 100 | werkzeug==2.3.3 \ 101 | --hash=sha256:4866679a0722de00796a74086238bb3b98d90f423f05de039abb09315487254a \ 102 | --hash=sha256:a987caf1092edc7523edb139edb20c70571c4a8d5eed02e0b547b4739174d091 103 | # via flask 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Docker Image CI](https://github.com/flightaware/firestarter/workflows/Docker%20Image%20CI/badge.svg)](https://github.com/flightaware/firestarter/actions?query=workflow%3A%22Docker+Image+CI%22) 2 | # Firestarter - Getting started with FlightAware Firehose 3 | Firestarter is a small collection of services and sample applications to help 4 | you get started using [FlightAware's Firehose Flight Data Feed](https://flightaware.com/commercial/firehose/documentation). 5 | 6 | Firestarter is structured as a group of Docker containers managed by 7 | Docker Compose. Currently, 3 core services and 2 sample applications are 8 | included, with more being developed (see [the roadmap](./ROADMAP.md) for 9 | details). 10 | 11 | ## Quickstart 12 | We suggest that you have at least 8GB of RAM and 30GB of available disk space 13 | to run the full Firestarter stack. In order to have more fine-grained control 14 | over memory usage, check the notes on how to configure the [timescaledb-tune](https://github.com/timescale/timescaledb-docker#notes-on-timescaledb-tune) 15 | parameters for TimescaleDB. 16 | 17 | You must set the following variables (in your environment or a .env file) 18 | before you can start using Firestarter. 19 | * FH_USERNAME - Your FlightAware Firehose account username 20 | * FH_APIKEY - The key to your FlightAware Firehose account 21 | * INIT_CMD_ARGS - Firehose initiation command; more information about this is 22 | available at https://flightaware.com/commercial/firehose/documentation/commands 23 | and in the env section of [docker-compose.yml](./docker-compose.yml). Its value 24 | will vary based on your account configuration, but a very basic example that 25 | should work for most users is `events "flifo departure arrival cancellation 26 | position"`. 27 | 28 | There are a number of other environment variables that can be set to tune the 29 | behavior of Firestarter. They are documented in 30 | [docker-compose.yml](./docker-compose.yml). 31 | 32 | You'll also need to install Docker (18.06+) and Docker Compose (1.22.0+)\ 33 | Details available at Docker's site: https://docs.docker.com/get-docker/ 34 | 35 | The usual Docker Compose incantation run in the root of this repo will get you 36 | up and running: 37 | ``` 38 | docker-compose pull && docker-compose up 39 | ``` 40 | 41 | `docker-compose pull` pulls prebuilt images from the Github Container Registry, 42 | and `docker-compose up` creates containers from those images and launches them. 43 | If you'd like to build the images yourself, you can instead run 44 | `docker-compose up --build`. 45 | 46 | After running the above command, you should be greeted with log output from 47 | each container. The services will log periodically as Firehose messages are 48 | received, while the sample webapps will produce some initial log output and 49 | then only log as requests are made to them. 50 | 51 | You can test out the FIDS sample application by visiting http://localhost:8080 52 | in your web browser (if not running Docker locally, use the Docker host's 53 | address). The map sample application can be accessed at http://localhost:5001. 54 | 55 | If you are running on Mac OS Monterrey or later, disable "AirPlay Receiver" 56 | in System Preferences > Sharing > AirPlay Receiver. It runs on port 5000, 57 | which is the same port as the FIDS backend application. 58 | 59 | 60 | ## Firestarter Components 61 | 62 | ![](docs/architecture-diagram.png) 63 | 64 | ### connector 65 | The connector service handles connecting to Firehose over an SSL socket. This 66 | involves building and sending the initiation command, handling compression, and 67 | reconnecting to Firehose without data loss if the connection is interrupted. 68 | The connector then forwards Firehose messages to its own clients. 69 | 70 | ### kafka/zookeeper 71 | We are using kafka as a message queue between the connector and the db-updater. 72 | Kafka depends on zookeeper to coordinate some important tasks, so we included 73 | that as well. We chose to pull existing docker containers for these pieces of 74 | software. 75 | Their documentation can be found here: 76 | https://hub.docker.com/r/bitnami/kafka/ 77 | https://hub.docker.com/r/bitnami/zookeeper/ 78 | 79 | In this code, the connector is the kafka "producer" and the db-updater is the 80 | kafka "consumer". If db-updater stops running and restarts, kafka will ensure 81 | that it starts reading from the queue where it left off. We recommend that 82 | you let kafka take care of this offset reconnect logic. 83 | 84 | We ensure that the kafka consumer will start where it left off with the 85 | "enable_auto_commit" and "auto_commit_interval_ms" parameters. We also need to 86 | be sure to provide a group name to store the last offset. Consumers with 87 | different group names will each consume all messages in a given topic, and 88 | consumers with the same group name will split messages from that topic between 89 | them. A single Kafka topic is used in Firestarter to stream all messages 90 | published by the connector to all subscribers. 91 | 92 | ### db-updater 93 | The db-updater service receives Firehose messages from the queue and 94 | maintains a database table based on their contents. The service is capable of 95 | handling so-called "flifo" (flight info) messages and airborne position messages. 96 | Two db-updater containers are configured by default - one handles flight info and 97 | updates a "flights" table, and the other handles airborne positions and updates 98 | a "positions" table. The flight info db-updater uses sqlite by default (but has been 99 | tested with PostgreSQL), and the position db-updater uses TimescaleDB which is 100 | based on PostgreSQL. Other databases could potentially be supported with little 101 | effort. To prevent bloat, flights and positions older than 48 hours are 102 | automatically dropped from the table. 103 | 104 | ### fids 105 | The fids sample application is a webapp backed by the flights and positions 106 | databases. You can use it to browse flight data by airport, presenting flights 107 | similarly to how you'd see them on a flight information display system (FIDS). 108 | Detailed information for individual flights can also be viewed. 109 | 110 | If you've specified a Google Maps API key, a flight's actual route will be 111 | displayed as a static image on its information page. 112 | Instructions: 113 | https://developers.google.com/maps/documentation/maps-static/get-api-key 114 | Once you get your API key, just specify it in your .env file as 115 | GOOGLE_MAPS_API_KEY. Then you will see static maps with a flight track on your 116 | flight info pages. Note that the Google Maps API is a paid service with a free 117 | tier, so you will need to provide payment information when signing up. 118 | Pricing information: 119 | https://developers.google.com/maps/documentation/maps-static/usage-and-billing 120 | You can see that you currently get "a $200 USD Google Maps Platform credit" 121 | each month, and each query 0-100,000 is 0.002 USD each. So that means that you 122 | will get 100,000 free queries per month. Since this is a demo and not meant for 123 | production, that should be fine. 124 | 125 | While Firestarter's services are suited for use in a production environment, 126 | this sample application should only be considered a demonstration of what can 127 | be built using the data from Firehose. It should *not* be used in a production 128 | environment. 129 | 130 | ### map 131 | The map sample application demonstrates another potential application of 132 | Firehose data by plotting live airborne flight positions directly onto a 133 | dynamic Google Map. Rather than using Firestarter's databases, this web app's 134 | backend connects directly to the queue service. This is a place where an API 135 | like Firehose truly shines, as no polling is required by the client to update 136 | the map. A Google Maps API key is required to run this application. 137 | 138 | Check out [the roadmap](./ROADMAP.md) to see what components are coming in the 139 | future! 140 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | connector: 5 | image: "ghcr.io/flightaware/firestarter/firestarter_connector:${FS_VERSION:-latest}" 6 | build: 7 | context: . 8 | dockerfile: connector/Dockerfile 9 | init: true 10 | networks: 11 | - internal 12 | ports: 13 | # Provides optional access to the raw Firehose stream for consumption 14 | # by non-dockerized applications 15 | - "${STREAMING_PORT:-127.0.0.1:1601}:1601" 16 | environment: 17 | # REQUIRED environment variables 18 | # Firehose account username 19 | - FH_USERNAME=${FH_USERNAME:?FH_USERNAME variable must be set} 20 | # Firehose account key 21 | - FH_APIKEY=${FH_APIKEY:?FH_APIKEY variable must be set} 22 | # Use a single topic for all events to ensure proper ordering per flight 23 | - KAFKA_TOPIC_NAME=events 24 | 25 | # OPTIONAL environment variables 26 | # Firehose URL, defaults to firehose-test.flightaware.com. 27 | # firehose.flightaware.com can also be used 28 | - SERVER 29 | # Streaming compression of incoming Firehose data. Valid values are gzip, 30 | # deflate, or compress. Leave blank to disable compression. 31 | - COMPRESSION 32 | # Frequency in seconds to print stats about connection (messages/bytes 33 | # per second). Set to 0 to disable. 34 | - PRINT_STATS_PERIOD 35 | # Frequency in seconds that Firehose should send a synthetic "keepalive" 36 | # message to help connector ensure the connection is still alive. If no 37 | # such message is received within roughly $keepalive seconds, connector 38 | # will automatically reconnect to Firehose. 39 | - KEEPALIVE 40 | # The number of times that the same pitr seen in consecutive keeplive 41 | # messages should trigger an error and a restart of the connection 42 | - KEEPALIVE_STALE_PITRS 43 | # "Time mode" of Firehose init command. Can be "live" or "pitr "; 44 | # range is currently not supported. 45 | # See https://flightaware.com/commercial/firehose/documentation/commands 46 | # for more details. 47 | - INIT_CMD_TIME 48 | # The "optional" section of the Firehose init command. Mostly consists of 49 | # filters for the data. Do not put username, password, keepalive, or 50 | # compression commands here. Documentation at 51 | # https://flightaware.com/commercial/firehose/documentation/commands 52 | - INIT_CMD_ARGS 53 | 54 | # PYTHON settings 55 | - PYTHONUNBUFFERED=1 56 | logging: 57 | driver: "json-file" 58 | options: 59 | max-size: "10mb" 60 | max-file: "5" 61 | depends_on: 62 | - kafka 63 | 64 | db-updater: 65 | image: "ghcr.io/flightaware/firestarter/firestarter_db-updater:${FS_VERSION:-latest}" 66 | build: 67 | context: . 68 | dockerfile: db-updater/Dockerfile 69 | init: true 70 | networks: 71 | - internal 72 | environment: 73 | # URL to database that will be updated based on Firehose contents. 74 | # Documentation at https://docs.sqlalchemy.org/en/13/core/engines.html#database-urls 75 | - DB_URL=${FLIGHTS_DB_URL:-sqlite:///db/flights.db} 76 | - PYTHONUNBUFFERED=1 77 | # Same kafka topic name as the producer of the feed that you want to consume 78 | - KAFKA_TOPIC_NAME=events 79 | # Consumers with the same group name will split the data between them, 80 | # but consumers with different group names will each receive all of the messages 81 | - KAFKA_GROUP_NAME=group1 82 | # Set this to "flights" or "positions" depending on what kinds of messages this updater is handling 83 | - TABLE=flights 84 | volumes: 85 | - data:/home/firestarter/app/db 86 | logging: 87 | driver: "json-file" 88 | options: 89 | max-size: "10mb" 90 | max-file: "5" 91 | depends_on: 92 | - kafka 93 | 94 | position-db-updater: 95 | image: "ghcr.io/flightaware/firestarter/firestarter_db-updater:${FS_VERSION:-latest}" 96 | build: 97 | context: . 98 | dockerfile: db-updater/Dockerfile 99 | init: true 100 | networks: 101 | - internal 102 | environment: 103 | # URL to database that will be updated based on Firehose contents. 104 | # Documentation at https://docs.sqlalchemy.org/en/13/core/engines.html#database-urls 105 | - DB_URL=${POSITIONS_DB_URL:-postgresql://postgres:positions@timescaledb:5432} 106 | - PYTHONUNBUFFERED=1 107 | # Same kafka topic name as the producer of the feed that you want to consume 108 | - KAFKA_TOPIC_NAME=events 109 | # Consumers with the same group name will split the data between them, 110 | # but consumers with different group names will each receive all of the messages 111 | - KAFKA_GROUP_NAME=position_group1 112 | # Set this to "flights" or "positions" depending on what kinds of messages this updater is handling 113 | - TABLE=positions 114 | logging: 115 | driver: "json-file" 116 | options: 117 | max-size: "10mb" 118 | max-file: "5" 119 | depends_on: 120 | - kafka 121 | - timescaledb 122 | 123 | fids-backend: 124 | image: "ghcr.io/flightaware/firestarter/firestarter_fids:${FS_VERSION:-latest}" 125 | build: 126 | context: . 127 | dockerfile: fids/Dockerfile 128 | init: true 129 | networks: 130 | internal: 131 | aliases: 132 | - fids-backend 133 | environment: 134 | # URL to database that is being updated by db-updater. 135 | # Documentation at https://docs.sqlalchemy.org/en/13/core/engines.html#database-urls 136 | - FLIGHTS_DB_URL=${FLIGHTS_DB_URL:-sqlite:///db/flights.db} 137 | - POSITIONS_DB_URL=${POSITIONS_DB_URL:-postgresql://postgres:positions@timescaledb:5432} 138 | - GOOGLE_MAPS_API_KEY=${GOOGLE_MAPS_API_KEY:-} 139 | - PYTHONUNBUFFERED=1 140 | volumes: 141 | - data:/home/firestarter/app/db 142 | logging: 143 | driver: "json-file" 144 | options: 145 | max-size: "10mb" 146 | max-file: "5" 147 | 148 | fids-frontend: 149 | image: "ghcr.io/flightaware/fids_frontend/fids-frontend:${FIDS_VERSION:-latest}" 150 | ports: 151 | # Port upon which to serve webapp 152 | - "${WEB_SERVER_PORT:-8080}:80" 153 | networks: 154 | - internal 155 | logging: 156 | driver: "json-file" 157 | options: 158 | max-size: "10mb" 159 | max-file: "5" 160 | 161 | map: 162 | image: "ghcr.io/flightaware/firestarter/firestarter_map:${FS_VERSION:-latest}" 163 | build: 164 | context: . 165 | dockerfile: map/Dockerfile 166 | init: true 167 | ports: 168 | # Port upon which to serve webapp 169 | - "${MAP_SERVER_PORT:-5001}:5001" 170 | networks: 171 | - internal 172 | environment: 173 | - PYTHONUNBUFFERED=1 174 | - KAFKA_TOPIC_NAME=events 175 | - KAFKA_GROUP_NAME=map_group 176 | - GOOGLE_MAPS_API_KEY 177 | logging: 178 | driver: "json-file" 179 | options: 180 | max-size: "10mb" 181 | max-file: "5" 182 | depends_on: 183 | - kafka 184 | 185 | zookeeper: 186 | image: "bitnami/zookeeper:3.6.2" 187 | init: true 188 | networks: 189 | - internal 190 | environment: 191 | - ALLOW_ANONYMOUS_LOGIN=yes 192 | volumes: 193 | - zookeeper_data:/bitnami/zookeeper 194 | 195 | kafka: 196 | image: "bitnami/kafka:3.1" 197 | init: true 198 | networks: 199 | - internal 200 | environment: 201 | - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 202 | - ALLOW_PLAINTEXT_LISTENER=yes 203 | # Retain messages for 1 hour 204 | - KAFKA_CFG_LOG_RETENTION_HOURS=1 205 | volumes: 206 | - kafka_data:/bitnami/kafka 207 | depends_on: 208 | - zookeeper 209 | 210 | timescaledb: 211 | image: "timescale/timescaledb:1.7.4-pg12" 212 | init: true 213 | networks: 214 | - internal 215 | environment: 216 | - POSTGRES_PASSWORD=positions 217 | volumes: 218 | - position_data:/var/lib/postgresql/data 219 | 220 | volumes: 221 | data: 222 | position_data: 223 | kafka_data: 224 | zookeeper_data: 225 | 226 | networks: 227 | internal: 228 | -------------------------------------------------------------------------------- /db-updater/requirements/base.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with python 3.9 3 | # To update, run: 4 | # 5 | # pip-compile --generate-hashes --output-file=base.txt base.in 6 | # 7 | confluent-kafka==1.8.2 \ 8 | --hash=sha256:02b78bb6d1199ea350240eae1f4415f22014896199a46edf85f779a69751f984 \ 9 | --hash=sha256:039c68379f9a5ece6e45a683ec7abebb95a9dac904ec4e2f9d93738e1cf6fab2 \ 10 | --hash=sha256:1df83fa20e4fe032651ad73ce0ba85dd14a7fabff6066c9cb20e944d2748e72b \ 11 | --hash=sha256:3d66e8c1a6a15144ca5b176170adbf30207c27813c76202c56abf52ef2b475e1 \ 12 | --hash=sha256:4f26052ef53212752039cd1d9e932b2feb6a0975d717ab070af323629a72a0b9 \ 13 | --hash=sha256:585bc8e8aa7d6fbd46dc0b2da3d4b1fd8457555288fee1ecba6af2c97ab738cc \ 14 | --hash=sha256:748813f47641dd65dd8d3bae8dcb3ce96a3e455c12b467d4b35e1fc880362d01 \ 15 | --hash=sha256:ac7155e1b9a94445ed8eecf691c80c61407148813808a2aa1cba0babbe197e77 \ 16 | --hash=sha256:add05db627435697d4ed8f81b3ce1081931770813a989fd775910865f07d694d \ 17 | --hash=sha256:ae75d3f4bc3d2109663912d77911c45aaa2939bde3694fc05e75842c806fa760 \ 18 | --hash=sha256:b679c3f9f555e87a9cbb043c676473c30d12182609e075be85afd98f84bcc863 \ 19 | --hash=sha256:b79e836c3554bc51c6837a8a0152f7521c9bf31342f5b8e21eba6b28044fa585 \ 20 | --hash=sha256:b7cb6fa3d44972e3670e0b3b054186a6006e6fd664600cfe70e008fad2443d16 \ 21 | --hash=sha256:d50b091770d277714766943d885ad6b2c5c427e67328706cfd33dc86eef540c9 \ 22 | --hash=sha256:e49382a943fb47813f421e913cc6c87cd1d4bfdecad1785efa0dacada7003d84 \ 23 | --hash=sha256:ead7f18c516f7bcb886b643fa78ff2a2142270adaf931ba0311b62e9a047e6ca \ 24 | --hash=sha256:f843680e183479f6e0732b593ea3235c836a5bb2de6be3819a11b891b6af1dde 25 | # via -r base.in 26 | psycopg2-binary==2.9.3 \ 27 | --hash=sha256:01310cf4cf26db9aea5158c217caa92d291f0500051a6469ac52166e1a16f5b7 \ 28 | --hash=sha256:083a55275f09a62b8ca4902dd11f4b33075b743cf0d360419e2051a8a5d5ff76 \ 29 | --hash=sha256:090f3348c0ab2cceb6dfbe6bf721ef61262ddf518cd6cc6ecc7d334996d64efa \ 30 | --hash=sha256:0a29729145aaaf1ad8bafe663131890e2111f13416b60e460dae0a96af5905c9 \ 31 | --hash=sha256:0c9d5450c566c80c396b7402895c4369a410cab5a82707b11aee1e624da7d004 \ 32 | --hash=sha256:10bb90fb4d523a2aa67773d4ff2b833ec00857f5912bafcfd5f5414e45280fb1 \ 33 | --hash=sha256:12b11322ea00ad8db8c46f18b7dfc47ae215e4df55b46c67a94b4effbaec7094 \ 34 | --hash=sha256:152f09f57417b831418304c7f30d727dc83a12761627bb826951692cc6491e57 \ 35 | --hash=sha256:15803fa813ea05bef089fa78835118b5434204f3a17cb9f1e5dbfd0b9deea5af \ 36 | --hash=sha256:15c4e4cfa45f5a60599d9cec5f46cd7b1b29d86a6390ec23e8eebaae84e64554 \ 37 | --hash=sha256:183a517a3a63503f70f808b58bfbf962f23d73b6dccddae5aa56152ef2bcb232 \ 38 | --hash=sha256:1f14c8b0942714eb3c74e1e71700cbbcb415acbc311c730370e70c578a44a25c \ 39 | --hash=sha256:1f6b813106a3abdf7b03640d36e24669234120c72e91d5cbaeb87c5f7c36c65b \ 40 | --hash=sha256:280b0bb5cbfe8039205c7981cceb006156a675362a00fe29b16fbc264e242834 \ 41 | --hash=sha256:2d872e3c9d5d075a2e104540965a1cf898b52274a5923936e5bfddb58c59c7c2 \ 42 | --hash=sha256:2f9ffd643bc7349eeb664eba8864d9e01f057880f510e4681ba40a6532f93c71 \ 43 | --hash=sha256:3303f8807f342641851578ee7ed1f3efc9802d00a6f83c101d21c608cb864460 \ 44 | --hash=sha256:35168209c9d51b145e459e05c31a9eaeffa9a6b0fd61689b48e07464ffd1a83e \ 45 | --hash=sha256:3a79d622f5206d695d7824cbf609a4f5b88ea6d6dab5f7c147fc6d333a8787e4 \ 46 | --hash=sha256:404224e5fef3b193f892abdbf8961ce20e0b6642886cfe1fe1923f41aaa75c9d \ 47 | --hash=sha256:46f0e0a6b5fa5851bbd9ab1bc805eef362d3a230fbdfbc209f4a236d0a7a990d \ 48 | --hash=sha256:47133f3f872faf28c1e87d4357220e809dfd3fa7c64295a4a148bcd1e6e34ec9 \ 49 | --hash=sha256:526ea0378246d9b080148f2d6681229f4b5964543c170dd10bf4faaab6e0d27f \ 50 | --hash=sha256:53293533fcbb94c202b7c800a12c873cfe24599656b341f56e71dd2b557be063 \ 51 | --hash=sha256:539b28661b71da7c0e428692438efbcd048ca21ea81af618d845e06ebfd29478 \ 52 | --hash=sha256:57804fc02ca3ce0dbfbef35c4b3a4a774da66d66ea20f4bda601294ad2ea6092 \ 53 | --hash=sha256:63638d875be8c2784cfc952c9ac34e2b50e43f9f0a0660b65e2a87d656b3116c \ 54 | --hash=sha256:6472a178e291b59e7f16ab49ec8b4f3bdada0a879c68d3817ff0963e722a82ce \ 55 | --hash=sha256:68641a34023d306be959101b345732360fc2ea4938982309b786f7be1b43a4a1 \ 56 | --hash=sha256:6e82d38390a03da28c7985b394ec3f56873174e2c88130e6966cb1c946508e65 \ 57 | --hash=sha256:761df5313dc15da1502b21453642d7599d26be88bff659382f8f9747c7ebea4e \ 58 | --hash=sha256:7af0dd86ddb2f8af5da57a976d27cd2cd15510518d582b478fbb2292428710b4 \ 59 | --hash=sha256:7b1e9b80afca7b7a386ef087db614faebbf8839b7f4db5eb107d0f1a53225029 \ 60 | --hash=sha256:874a52ecab70af13e899f7847b3e074eeb16ebac5615665db33bce8a1009cf33 \ 61 | --hash=sha256:887dd9aac71765ac0d0bac1d0d4b4f2c99d5f5c1382d8b770404f0f3d0ce8a39 \ 62 | --hash=sha256:8b344adbb9a862de0c635f4f0425b7958bf5a4b927c8594e6e8d261775796d53 \ 63 | --hash=sha256:8fc53f9af09426a61db9ba357865c77f26076d48669f2e1bb24d85a22fb52307 \ 64 | --hash=sha256:91920527dea30175cc02a1099f331aa8c1ba39bf8b7762b7b56cbf54bc5cce42 \ 65 | --hash=sha256:93cd1967a18aa0edd4b95b1dfd554cf15af657cb606280996d393dadc88c3c35 \ 66 | --hash=sha256:99485cab9ba0fa9b84f1f9e1fef106f44a46ef6afdeec8885e0b88d0772b49e8 \ 67 | --hash=sha256:9d29409b625a143649d03d0fd7b57e4b92e0ecad9726ba682244b73be91d2fdb \ 68 | --hash=sha256:a29b3ca4ec9defec6d42bf5feb36bb5817ba3c0230dd83b4edf4bf02684cd0ae \ 69 | --hash=sha256:a9e1f75f96ea388fbcef36c70640c4efbe4650658f3d6a2967b4cc70e907352e \ 70 | --hash=sha256:accfe7e982411da3178ec690baaceaad3c278652998b2c45828aaac66cd8285f \ 71 | --hash=sha256:adf20d9a67e0b6393eac162eb81fb10bc9130a80540f4df7e7355c2dd4af9fba \ 72 | --hash=sha256:af9813db73395fb1fc211bac696faea4ca9ef53f32dc0cfa27e4e7cf766dcf24 \ 73 | --hash=sha256:b1c8068513f5b158cf7e29c43a77eb34b407db29aca749d3eb9293ee0d3103ca \ 74 | --hash=sha256:bda845b664bb6c91446ca9609fc69f7db6c334ec5e4adc87571c34e4f47b7ddb \ 75 | --hash=sha256:c381bda330ddf2fccbafab789d83ebc6c53db126e4383e73794c74eedce855ef \ 76 | --hash=sha256:c3ae8e75eb7160851e59adc77b3a19a976e50622e44fd4fd47b8b18208189d42 \ 77 | --hash=sha256:d1c1b569ecafe3a69380a94e6ae09a4789bbb23666f3d3a08d06bbd2451f5ef1 \ 78 | --hash=sha256:def68d7c21984b0f8218e8a15d514f714d96904265164f75f8d3a70f9c295667 \ 79 | --hash=sha256:dffc08ca91c9ac09008870c9eb77b00a46b3378719584059c034b8945e26b272 \ 80 | --hash=sha256:e3699852e22aa68c10de06524a3721ade969abf382da95884e6a10ff798f9281 \ 81 | --hash=sha256:e847774f8ffd5b398a75bc1c18fbb56564cda3d629fe68fd81971fece2d3c67e \ 82 | --hash=sha256:ffb7a888a047696e7f8240d649b43fb3644f14f0ee229077e7f6b9f9081635bd 83 | # via -r base.in 84 | sqlalchemy==1.3.24 \ 85 | --hash=sha256:014ea143572fee1c18322b7908140ad23b3994036ef4c0d630110faf942652f8 \ 86 | --hash=sha256:0172423a27fbcae3751ef016663b72e1a516777de324a76e30efa170dbd3dd2d \ 87 | --hash=sha256:01aa5f803db724447c1d423ed583e42bf5264c597fd55e4add4301f163b0be48 \ 88 | --hash=sha256:0352db1befcbed2f9282e72843f1963860bf0e0472a4fa5cf8ee084318e0e6ab \ 89 | --hash=sha256:09083c2487ca3c0865dc588e07aeaa25416da3d95f7482c07e92f47e080aa17b \ 90 | --hash=sha256:0d5d862b1cfbec5028ce1ecac06a3b42bc7703eb80e4b53fceb2738724311443 \ 91 | --hash=sha256:14f0eb5db872c231b20c18b1e5806352723a3a89fb4254af3b3e14f22eaaec75 \ 92 | --hash=sha256:1e2f89d2e5e3c7a88e25a3b0e43626dba8db2aa700253023b82e630d12b37109 \ 93 | --hash=sha256:26155ea7a243cbf23287f390dba13d7927ffa1586d3208e0e8d615d0c506f996 \ 94 | --hash=sha256:2ed6343b625b16bcb63c5b10523fd15ed8934e1ed0f772c534985e9f5e73d894 \ 95 | --hash=sha256:34fcec18f6e4b24b4a5f6185205a04f1eab1e56f8f1d028a2a03694ebcc2ddd4 \ 96 | --hash=sha256:4d0e3515ef98aa4f0dc289ff2eebb0ece6260bbf37c2ea2022aad63797eacf60 \ 97 | --hash=sha256:5de2464c254380d8a6c20a2746614d5a436260be1507491442cf1088e59430d2 \ 98 | --hash=sha256:6607ae6cd3a07f8a4c3198ffbf256c261661965742e2b5265a77cd5c679c9bba \ 99 | --hash=sha256:8110e6c414d3efc574543109ee618fe2c1f96fa31833a1ff36cc34e968c4f233 \ 100 | --hash=sha256:816de75418ea0953b5eb7b8a74933ee5a46719491cd2b16f718afc4b291a9658 \ 101 | --hash=sha256:861e459b0e97673af6cc5e7f597035c2e3acdfb2608132665406cded25ba64c7 \ 102 | --hash=sha256:87a2725ad7d41cd7376373c15fd8bf674e9c33ca56d0b8036add2d634dba372e \ 103 | --hash=sha256:a006d05d9aa052657ee3e4dc92544faae5fcbaafc6128217310945610d862d39 \ 104 | --hash=sha256:bce28277f308db43a6b4965734366f533b3ff009571ec7ffa583cb77539b84d6 \ 105 | --hash=sha256:c10ff6112d119f82b1618b6dc28126798481b9355d8748b64b9b55051eb4f01b \ 106 | --hash=sha256:d375d8ccd3cebae8d90270f7aa8532fe05908f79e78ae489068f3b4eee5994e8 \ 107 | --hash=sha256:d37843fb8df90376e9e91336724d78a32b988d3d20ab6656da4eb8ee3a45b63c \ 108 | --hash=sha256:e47e257ba5934550d7235665eee6c911dc7178419b614ba9e1fbb1ce6325b14f \ 109 | --hash=sha256:e98d09f487267f1e8d1179bf3b9d7709b30a916491997137dd24d6ae44d18d79 \ 110 | --hash=sha256:ebbb777cbf9312359b897bf81ba00dae0f5cb69fba2a18265dcc18a6f5ef7519 \ 111 | --hash=sha256:ee5f5188edb20a29c1cc4a039b074fdc5575337c9a68f3063449ab47757bb064 \ 112 | --hash=sha256:f03bd97650d2e42710fbe4cf8a59fae657f191df851fc9fc683ecef10746a375 \ 113 | --hash=sha256:f1149d6e5c49d069163e58a3196865e4321bad1803d7886e07d8710de392c548 \ 114 | --hash=sha256:f3c5c52f7cb8b84bfaaf22d82cb9e6e9a8297f7c2ed14d806a0f5e4d22e83fb7 \ 115 | --hash=sha256:f597a243b8550a3a0b15122b14e49d8a7e622ba1c9d29776af741f1845478d79 \ 116 | --hash=sha256:fc1f2a5a5963e2e73bac4926bdaf7790c4d7d77e8fc0590817880e22dd9d0b8b \ 117 | --hash=sha256:fc4cddb0b474b12ed7bdce6be1b9edc65352e8ce66bc10ff8cbbfb3d4047dbf4 \ 118 | --hash=sha256:fcb251305fa24a490b6a9ee2180e5f8252915fb778d3dafc70f9cc3f863827b9 119 | # via -r base.in 120 | -------------------------------------------------------------------------------- /fids/app.py: -------------------------------------------------------------------------------- 1 | """Read flight information from database and display it on a webpage""" 2 | 3 | from base64 import b64encode 4 | from datetime import datetime, timezone 5 | import os 6 | import time 7 | from typing import Optional, Iterable 8 | from flask import Flask, request, jsonify, abort, Response 9 | import requests 10 | import sqlalchemy as sa # type: ignore 11 | from sqlalchemy.sql import union, select, func, and_, or_ # type: ignore 12 | from sqlalchemy.sql.expression import text # type: ignore 13 | 14 | import trig 15 | 16 | # pylint: disable=invalid-name 17 | flights_engine = sa.create_engine(os.environ["FLIGHTS_DB_URL"], echo=True) 18 | flights_meta = sa.MetaData() 19 | flights_insp = sa.inspect(flights_engine) 20 | while "flights" not in flights_insp.get_table_names(): 21 | print("Waiting for flights table to exist before starting") 22 | flights_insp.info_cache.clear() 23 | time.sleep(3) 24 | flights = sa.Table("flights", flights_meta, autoload_with=flights_engine) 25 | 26 | positions_engine = sa.create_engine(os.environ["POSITIONS_DB_URL"], echo=True) 27 | 28 | while True: 29 | try: 30 | positions_engine.connect() 31 | break 32 | except sa.exc.OperationalError as error: 33 | print(f"Can't connect to the database ({error}), trying again in a few seconds") 34 | time.sleep(3) 35 | 36 | positions_meta = sa.MetaData() 37 | positions_insp = sa.inspect(positions_engine) 38 | while "positions" not in positions_insp.get_table_names(): 39 | print("Waiting for positions table to exist before starting") 40 | positions_insp.info_cache.clear() 41 | time.sleep(3) 42 | positions = sa.Table("positions", positions_meta, autoload_with=positions_engine) 43 | 44 | google_maps_api_key = os.environ["GOOGLE_MAPS_API_KEY"] 45 | 46 | app = Flask(__name__) 47 | 48 | UTC = timezone.utc 49 | 50 | 51 | def _get_positions(flight_id: str) -> Iterable: 52 | return ( 53 | positions_engine.execute( 54 | positions.select().where(positions.c.id == flight_id).order_by(positions.c.time.desc()) 55 | ) 56 | or [] 57 | ) 58 | 59 | 60 | @app.route("/positions/") 61 | def get_positions(flight_id: str) -> Response: 62 | """Get positions for a specific flight_id""" 63 | result = _get_positions(flight_id) 64 | if not result: 65 | abort(404) 66 | return jsonify([dict(e) for e in result]) 67 | 68 | 69 | @app.route("/flights/") 70 | @app.route("/flights/") 71 | def get_flight(flight_id: Optional[str] = None) -> dict: 72 | """Get info for a specific flight_id""" 73 | if flight_id is None: 74 | # get random flight 75 | whereclause = flights.c.id.in_( 76 | select([flights.c.id]) 77 | .where(flights.c.flight_number != "BLOCKED") 78 | .order_by(func.random()) 79 | .limit(1) 80 | ) 81 | else: 82 | whereclause = flights.c.id == flight_id 83 | result = flights_engine.execute(flights.select().where(whereclause)).first() 84 | if result is None: 85 | abort(404) 86 | return dict(result) 87 | 88 | 89 | @app.route("/airports/") 90 | def get_busiest_airports() -> Response: 91 | """Get the busiest airport""" 92 | limit = request.args.get("limit", 10) 93 | query = request.args.get("query") 94 | since = int(request.args.get("since", 0)) 95 | if query: 96 | result = flights_engine.execute( 97 | union( 98 | select([flights.c.origin]).distinct().where(flights.c.origin.like(f"%{query}%")), 99 | select([flights.c.destination]) 100 | .distinct() 101 | .where(flights.c.destination.like(f"%{query}%")), 102 | ) 103 | ) 104 | if result is None: 105 | abort(404) 106 | return jsonify([row[0] for row in result]) 107 | 108 | return jsonify( 109 | [ 110 | row.origin 111 | for row in flights_engine.execute( 112 | select([flights.c.origin]) 113 | .where( 114 | func.coalesce(flights.c.actual_off, flights.c.actual_out) 115 | > ( 116 | select( 117 | [ 118 | func.datetime( 119 | func.max(flights.c.actual_off), text(f"'-{since} hours'") 120 | ) 121 | ] 122 | ) 123 | ) 124 | ) 125 | .group_by(flights.c.origin) 126 | .order_by(func.count().desc(), flights.c.origin) 127 | .limit(limit) 128 | ) 129 | ] 130 | ) 131 | 132 | 133 | @app.route("/airports//arrivals") 134 | def airport_arrivals(airport: str) -> Response: 135 | """Get a list of arrivals for a certain airport""" 136 | airport = airport.upper() 137 | result = flights_engine.execute( 138 | flights.select().where( 139 | and_( 140 | flights.c.destination == airport, 141 | flights.c.flight_number != "BLOCKED", 142 | func.coalesce(flights.c.actual_out, flights.c.actual_off) is not None, 143 | func.coalesce(flights.c.actual_in, flights.c.actual_on, flights.c.cancelled) 144 | > (select([func.datetime(func.max(flights.c.actual_off), text(f"'-5 hours'"))])), 145 | ) 146 | ) 147 | ) 148 | if result is None: 149 | abort(404) 150 | return jsonify([dict(e) for e in result]) 151 | 152 | 153 | @app.route("/airports//departures") 154 | def airport_departures(airport: str) -> Response: 155 | """Get a list of departures for a certain airport""" 156 | airport = airport.upper() 157 | result = flights_engine.execute( 158 | flights.select().where( 159 | and_( 160 | flights.c.origin == airport, 161 | flights.c.flight_number != "BLOCKED", 162 | func.coalesce(flights.c.actual_out, flights.c.actual_off) 163 | > (select([func.datetime(func.max(flights.c.actual_off), text(f"'-5 hours'"))])), 164 | ) 165 | ) 166 | ) 167 | if result is None: 168 | abort(404) 169 | return jsonify([dict(e) for e in result]) 170 | 171 | 172 | # pylint: disable=singleton-comparison 173 | @app.route("/airports//enroute") 174 | @app.route("/airports//scheduledto") 175 | def airport_enroute(airport: str) -> Response: 176 | """Get a list of flights enroute to a certain airport""" 177 | airport = airport.upper() 178 | result = flights_engine.execute( 179 | flights.select().where( 180 | and_( 181 | flights.c.destination == airport, 182 | flights.c.flight_number != "BLOCKED", 183 | func.coalesce(flights.c.actual_in, flights.c.actual_on, flights.c.cancelled) 184 | == None, 185 | flights.c.estimated_on.between( 186 | select([func.datetime(func.max(flights.c.actual_off), text(f"'-5 hours'"))]), 187 | select([func.datetime(func.max(flights.c.actual_off), text(f"'+6 hours'"))]), 188 | ), 189 | ) 190 | ) 191 | ) 192 | if result is None: 193 | abort(404) 194 | return jsonify([dict(e) for e in result]) 195 | 196 | 197 | @app.route("/airports//scheduled") 198 | @app.route("/airports//scheduledfrom") 199 | def airport_scheduled(airport: str) -> Response: 200 | """Get a list of scheduled flights from a certain airport""" 201 | airport = airport.upper() 202 | result = flights_engine.execute( 203 | flights.select().where( 204 | and_( 205 | flights.c.origin == airport, 206 | flights.c.flight_number != "BLOCKED", 207 | or_( 208 | func.coalesce(flights.c.actual_out, flights.c.actual_off) == None, 209 | # You can actually get true_cancel'ed flights with an actual_out/off. Weird? 210 | flights.c.true_cancel, 211 | ), 212 | flights.c.scheduled_off.between( 213 | select([func.datetime(func.max(flights.c.actual_off), text(f"'-5 hours'"))]), 214 | select([func.datetime(func.max(flights.c.actual_off), text(f"'+6 hours'"))]), 215 | ), 216 | or_( 217 | flights.c.cancelled == None, 218 | and_( 219 | flights.c.true_cancel, 220 | flights.c.cancelled 221 | > ( 222 | select( 223 | [func.datetime(func.max(flights.c.actual_off), text(f"'-5 hours'"))] 224 | ) 225 | ), 226 | ), 227 | ), 228 | ) 229 | ) 230 | ) 231 | if result is None: 232 | abort(404) 233 | return jsonify([dict(e) for e in result]) 234 | 235 | 236 | @app.route("/map/") 237 | def get_map(flight_id: str) -> bytes: 238 | """Get a static map image of the specified flight. Returned as a 239 | base64-encoded image""" 240 | positions = list(_get_positions(flight_id)) 241 | if not positions: 242 | abort(404) 243 | bearing = 0 244 | if len(positions) > 1: 245 | coord1 = (float(positions[1].latitude), float(positions[1].longitude)) 246 | coord2 = (float(positions[0].latitude), float(positions[0].longitude)) 247 | bearing = trig.get_cardinal_for_angle(trig.get_bearing_degrees(coord1, coord2)) 248 | coords = "|".join(f"{pos.latitude},{pos.longitude}" for pos in positions) 249 | 250 | google_maps_url = "https://maps.googleapis.com/maps/api/staticmap" 251 | google_maps_params = { 252 | "size": "640x400", 253 | "markers": f"anchor:center|icon:https://github.com/flightaware/fids_frontend/raw/master/images/aircraft_{bearing}.png|{positions[0].latitude},{positions[0].longitude}", 254 | "path": f"color:0x0000ff|weight:5|{coords}", 255 | "key": google_maps_api_key, 256 | } 257 | response = requests.get(google_maps_url, google_maps_params) 258 | response.raise_for_status() 259 | image = b64encode(response.content) 260 | return image 261 | 262 | 263 | app.run(host="0.0.0.0", port=5000) 264 | -------------------------------------------------------------------------------- /connector/requirements/dev.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with python 3.9 3 | # To update, run: 4 | # 5 | # pip-compile --generate-hashes --output-file=dev.txt dev.in 6 | # 7 | appdirs==1.4.3 \ 8 | --hash=sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92 \ 9 | --hash=sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e 10 | # via black 11 | astroid==2.3.3 \ 12 | --hash=sha256:71ea07f44df9568a75d0f354c49143a4575d90645e9fead6dfb52c26a85ed13a \ 13 | --hash=sha256:840947ebfa8b58f318d42301cf8c0a20fd794a33b61cc4638e28e9e61ba32f42 14 | # via pylint 15 | black==20.8b1 \ 16 | --hash=sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea 17 | # via -r dev.in 18 | click==7.1.2 \ 19 | --hash=sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a \ 20 | --hash=sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc 21 | # via black 22 | isort==4.3.21 \ 23 | --hash=sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1 \ 24 | --hash=sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd 25 | # via pylint 26 | lazy-object-proxy==1.4.3 \ 27 | --hash=sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d \ 28 | --hash=sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449 \ 29 | --hash=sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08 \ 30 | --hash=sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a \ 31 | --hash=sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50 \ 32 | --hash=sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd \ 33 | --hash=sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239 \ 34 | --hash=sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb \ 35 | --hash=sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea \ 36 | --hash=sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e \ 37 | --hash=sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156 \ 38 | --hash=sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142 \ 39 | --hash=sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442 \ 40 | --hash=sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62 \ 41 | --hash=sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db \ 42 | --hash=sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531 \ 43 | --hash=sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383 \ 44 | --hash=sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a \ 45 | --hash=sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357 \ 46 | --hash=sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4 \ 47 | --hash=sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0 48 | # via astroid 49 | mccabe==0.6.1 \ 50 | --hash=sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42 \ 51 | --hash=sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f 52 | # via pylint 53 | mypy==0.942 \ 54 | --hash=sha256:0e2dd88410937423fba18e57147dd07cd8381291b93d5b1984626f173a26543e \ 55 | --hash=sha256:10daab80bc40f84e3f087d896cdb53dc811a9f04eae4b3f95779c26edee89d16 \ 56 | --hash=sha256:17e44649fec92e9f82102b48a3bf7b4a5510ad0cd22fa21a104826b5db4903e2 \ 57 | --hash=sha256:1a0459c333f00e6a11cbf6b468b870c2b99a906cb72d6eadf3d1d95d38c9352c \ 58 | --hash=sha256:246e1aa127d5b78488a4a0594bd95f6d6fb9d63cf08a66dafbff8595d8891f67 \ 59 | --hash=sha256:2b184db8c618c43c3a31b32ff00cd28195d39e9c24e7c3b401f3db7f6e5767f5 \ 60 | --hash=sha256:2bc249409a7168d37c658e062e1ab5173300984a2dada2589638568ddc1db02b \ 61 | --hash=sha256:3841b5433ff936bff2f4dc8d54cf2cdbfea5d8e88cedfac45c161368e5770ba6 \ 62 | --hash=sha256:4c3e497588afccfa4334a9986b56f703e75793133c4be3a02d06a3df16b67a58 \ 63 | --hash=sha256:5bf44840fb43ac4074636fd47ee476d73f0039f4f54e86d7265077dc199be24d \ 64 | --hash=sha256:64235137edc16bee6f095aba73be5334677d6f6bdb7fa03cfab90164fa294a17 \ 65 | --hash=sha256:6776e5fa22381cc761df53e7496a805801c1a751b27b99a9ff2f0ca848c7eca0 \ 66 | --hash=sha256:6ce34a118d1a898f47def970a2042b8af6bdcc01546454726c7dd2171aa6dfca \ 67 | --hash=sha256:6f6ad963172152e112b87cc7ec103ba0f2db2f1cd8997237827c052a3903eaa6 \ 68 | --hash=sha256:6f7106cbf9cc2f403693bf50ed7c9fa5bb3dfa9007b240db3c910929abe2a322 \ 69 | --hash=sha256:7742d2c4e46bb5017b51c810283a6a389296cda03df805a4f7869a6f41246534 \ 70 | --hash=sha256:9521c1265ccaaa1791d2c13582f06facf815f426cd8b07c3a485f486a8ffc1f3 \ 71 | --hash=sha256:a1b383fe99678d7402754fe90448d4037f9512ce70c21f8aee3b8bf48ffc51db \ 72 | --hash=sha256:b840cfe89c4ab6386c40300689cd8645fc8d2d5f20101c7f8bd23d15fca14904 \ 73 | --hash=sha256:d8d3ba77e56b84cd47a8ee45b62c84b6d80d32383928fe2548c9a124ea0a725c \ 74 | --hash=sha256:dcd955f36e0180258a96f880348fbca54ce092b40fbb4b37372ae3b25a0b0a46 \ 75 | --hash=sha256:e865fec858d75b78b4d63266c9aff770ecb6a39dfb6d6b56c47f7f8aba6baba8 \ 76 | --hash=sha256:edf7237137a1a9330046dbb14796963d734dd740a98d5e144a3eb1d267f5f9ee 77 | # via -r dev.in 78 | mypy-extensions==0.4.3 \ 79 | --hash=sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d \ 80 | --hash=sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8 81 | # via 82 | # black 83 | # mypy 84 | pathspec==0.8.0 \ 85 | --hash=sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0 \ 86 | --hash=sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061 87 | # via black 88 | pylint==2.4.4 \ 89 | --hash=sha256:3db5468ad013380e987410a8d6956226963aed94ecb5f9d3a28acca6d9ac36cd \ 90 | --hash=sha256:886e6afc935ea2590b462664b161ca9a5e40168ea99e5300935f6591ad467df4 91 | # via -r dev.in 92 | regex==2020.4.4 \ 93 | --hash=sha256:08119f707f0ebf2da60d2f24c2f39ca616277bb67ef6c92b72cbf90cbe3a556b \ 94 | --hash=sha256:0ce9537396d8f556bcfc317c65b6a0705320701e5ce511f05fc04421ba05b8a8 \ 95 | --hash=sha256:1cbe0fa0b7f673400eb29e9ef41d4f53638f65f9a2143854de6b1ce2899185c3 \ 96 | --hash=sha256:2294f8b70e058a2553cd009df003a20802ef75b3c629506be20687df0908177e \ 97 | --hash=sha256:23069d9c07e115537f37270d1d5faea3e0bdded8279081c4d4d607a2ad393683 \ 98 | --hash=sha256:24f4f4062eb16c5bbfff6a22312e8eab92c2c99c51a02e39b4eae54ce8255cd1 \ 99 | --hash=sha256:295badf61a51add2d428a46b8580309c520d8b26e769868b922750cf3ce67142 \ 100 | --hash=sha256:2a3bf8b48f8e37c3a40bb3f854bf0121c194e69a650b209628d951190b862de3 \ 101 | --hash=sha256:4385f12aa289d79419fede43f979e372f527892ac44a541b5446617e4406c468 \ 102 | --hash=sha256:5635cd1ed0a12b4c42cce18a8d2fb53ff13ff537f09de5fd791e97de27b6400e \ 103 | --hash=sha256:5bfed051dbff32fd8945eccca70f5e22b55e4148d2a8a45141a3b053d6455ae3 \ 104 | --hash=sha256:7e1037073b1b7053ee74c3c6c0ada80f3501ec29d5f46e42669378eae6d4405a \ 105 | --hash=sha256:90742c6ff121a9c5b261b9b215cb476eea97df98ea82037ec8ac95d1be7a034f \ 106 | --hash=sha256:a58dd45cb865be0ce1d5ecc4cfc85cd8c6867bea66733623e54bd95131f473b6 \ 107 | --hash=sha256:c087bff162158536387c53647411db09b6ee3f9603c334c90943e97b1052a156 \ 108 | --hash=sha256:c162a21e0da33eb3d31a3ac17a51db5e634fc347f650d271f0305d96601dc15b \ 109 | --hash=sha256:c9423a150d3a4fc0f3f2aae897a59919acd293f4cb397429b120a5fcd96ea3db \ 110 | --hash=sha256:ccccdd84912875e34c5ad2d06e1989d890d43af6c2242c6fcfa51556997af6cd \ 111 | --hash=sha256:e91ba11da11cf770f389e47c3f5c30473e6d85e06d7fd9dcba0017d2867aab4a \ 112 | --hash=sha256:ea4adf02d23b437684cd388d557bf76e3afa72f7fed5bbc013482cc00c816948 \ 113 | --hash=sha256:fb95debbd1a824b2c4376932f2216cc186912e389bdb0e27147778cf6acb3f89 114 | # via black 115 | six==1.14.0 \ 116 | --hash=sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a \ 117 | --hash=sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c 118 | # via astroid 119 | toml==0.10.2 \ 120 | --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ 121 | --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f 122 | # via black 123 | tomli==2.0.1 \ 124 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 125 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 126 | # via mypy 127 | typed-ast==1.4.1 \ 128 | --hash=sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355 \ 129 | --hash=sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919 \ 130 | --hash=sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa \ 131 | --hash=sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652 \ 132 | --hash=sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75 \ 133 | --hash=sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01 \ 134 | --hash=sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d \ 135 | --hash=sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1 \ 136 | --hash=sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907 \ 137 | --hash=sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c \ 138 | --hash=sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3 \ 139 | --hash=sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b \ 140 | --hash=sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614 \ 141 | --hash=sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb \ 142 | --hash=sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b \ 143 | --hash=sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41 \ 144 | --hash=sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6 \ 145 | --hash=sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34 \ 146 | --hash=sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe \ 147 | --hash=sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4 \ 148 | --hash=sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7 149 | # via black 150 | typing-extensions==4.1.1 \ 151 | --hash=sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42 \ 152 | --hash=sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2 153 | # via 154 | # black 155 | # mypy 156 | wrapt==1.11.2 \ 157 | --hash=sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1 158 | # via astroid 159 | -------------------------------------------------------------------------------- /db-updater/requirements/dev.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with python 3.9 3 | # To update, run: 4 | # 5 | # pip-compile --generate-hashes --output-file=dev.txt dev.in 6 | # 7 | appdirs==1.4.3 \ 8 | --hash=sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92 \ 9 | --hash=sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e 10 | # via black 11 | astroid==2.3.3 \ 12 | --hash=sha256:71ea07f44df9568a75d0f354c49143a4575d90645e9fead6dfb52c26a85ed13a \ 13 | --hash=sha256:840947ebfa8b58f318d42301cf8c0a20fd794a33b61cc4638e28e9e61ba32f42 14 | # via pylint 15 | attrs==19.3.0 \ 16 | --hash=sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c \ 17 | --hash=sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72 18 | # via black 19 | black==19.10b0 \ 20 | --hash=sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b \ 21 | --hash=sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539 22 | # via -r dev.in 23 | click==7.1.2 \ 24 | --hash=sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a \ 25 | --hash=sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc 26 | # via black 27 | isort==4.3.21 \ 28 | --hash=sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1 \ 29 | --hash=sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd 30 | # via pylint 31 | lazy-object-proxy==1.4.3 \ 32 | --hash=sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d \ 33 | --hash=sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449 \ 34 | --hash=sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08 \ 35 | --hash=sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a \ 36 | --hash=sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50 \ 37 | --hash=sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd \ 38 | --hash=sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239 \ 39 | --hash=sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb \ 40 | --hash=sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea \ 41 | --hash=sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e \ 42 | --hash=sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156 \ 43 | --hash=sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142 \ 44 | --hash=sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442 \ 45 | --hash=sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62 \ 46 | --hash=sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db \ 47 | --hash=sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531 \ 48 | --hash=sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383 \ 49 | --hash=sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a \ 50 | --hash=sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357 \ 51 | --hash=sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4 \ 52 | --hash=sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0 53 | # via astroid 54 | mccabe==0.6.1 \ 55 | --hash=sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42 \ 56 | --hash=sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f 57 | # via pylint 58 | mypy==0.942 \ 59 | --hash=sha256:0e2dd88410937423fba18e57147dd07cd8381291b93d5b1984626f173a26543e \ 60 | --hash=sha256:10daab80bc40f84e3f087d896cdb53dc811a9f04eae4b3f95779c26edee89d16 \ 61 | --hash=sha256:17e44649fec92e9f82102b48a3bf7b4a5510ad0cd22fa21a104826b5db4903e2 \ 62 | --hash=sha256:1a0459c333f00e6a11cbf6b468b870c2b99a906cb72d6eadf3d1d95d38c9352c \ 63 | --hash=sha256:246e1aa127d5b78488a4a0594bd95f6d6fb9d63cf08a66dafbff8595d8891f67 \ 64 | --hash=sha256:2b184db8c618c43c3a31b32ff00cd28195d39e9c24e7c3b401f3db7f6e5767f5 \ 65 | --hash=sha256:2bc249409a7168d37c658e062e1ab5173300984a2dada2589638568ddc1db02b \ 66 | --hash=sha256:3841b5433ff936bff2f4dc8d54cf2cdbfea5d8e88cedfac45c161368e5770ba6 \ 67 | --hash=sha256:4c3e497588afccfa4334a9986b56f703e75793133c4be3a02d06a3df16b67a58 \ 68 | --hash=sha256:5bf44840fb43ac4074636fd47ee476d73f0039f4f54e86d7265077dc199be24d \ 69 | --hash=sha256:64235137edc16bee6f095aba73be5334677d6f6bdb7fa03cfab90164fa294a17 \ 70 | --hash=sha256:6776e5fa22381cc761df53e7496a805801c1a751b27b99a9ff2f0ca848c7eca0 \ 71 | --hash=sha256:6ce34a118d1a898f47def970a2042b8af6bdcc01546454726c7dd2171aa6dfca \ 72 | --hash=sha256:6f6ad963172152e112b87cc7ec103ba0f2db2f1cd8997237827c052a3903eaa6 \ 73 | --hash=sha256:6f7106cbf9cc2f403693bf50ed7c9fa5bb3dfa9007b240db3c910929abe2a322 \ 74 | --hash=sha256:7742d2c4e46bb5017b51c810283a6a389296cda03df805a4f7869a6f41246534 \ 75 | --hash=sha256:9521c1265ccaaa1791d2c13582f06facf815f426cd8b07c3a485f486a8ffc1f3 \ 76 | --hash=sha256:a1b383fe99678d7402754fe90448d4037f9512ce70c21f8aee3b8bf48ffc51db \ 77 | --hash=sha256:b840cfe89c4ab6386c40300689cd8645fc8d2d5f20101c7f8bd23d15fca14904 \ 78 | --hash=sha256:d8d3ba77e56b84cd47a8ee45b62c84b6d80d32383928fe2548c9a124ea0a725c \ 79 | --hash=sha256:dcd955f36e0180258a96f880348fbca54ce092b40fbb4b37372ae3b25a0b0a46 \ 80 | --hash=sha256:e865fec858d75b78b4d63266c9aff770ecb6a39dfb6d6b56c47f7f8aba6baba8 \ 81 | --hash=sha256:edf7237137a1a9330046dbb14796963d734dd740a98d5e144a3eb1d267f5f9ee 82 | # via -r dev.in 83 | mypy-extensions==0.4.3 \ 84 | --hash=sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d \ 85 | --hash=sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8 86 | # via mypy 87 | pathspec==0.8.0 \ 88 | --hash=sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0 \ 89 | --hash=sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061 90 | # via black 91 | pylint==2.4.4 \ 92 | --hash=sha256:3db5468ad013380e987410a8d6956226963aed94ecb5f9d3a28acca6d9ac36cd \ 93 | --hash=sha256:886e6afc935ea2590b462664b161ca9a5e40168ea99e5300935f6591ad467df4 94 | # via -r dev.in 95 | regex==2020.4.4 \ 96 | --hash=sha256:08119f707f0ebf2da60d2f24c2f39ca616277bb67ef6c92b72cbf90cbe3a556b \ 97 | --hash=sha256:0ce9537396d8f556bcfc317c65b6a0705320701e5ce511f05fc04421ba05b8a8 \ 98 | --hash=sha256:1cbe0fa0b7f673400eb29e9ef41d4f53638f65f9a2143854de6b1ce2899185c3 \ 99 | --hash=sha256:2294f8b70e058a2553cd009df003a20802ef75b3c629506be20687df0908177e \ 100 | --hash=sha256:23069d9c07e115537f37270d1d5faea3e0bdded8279081c4d4d607a2ad393683 \ 101 | --hash=sha256:24f4f4062eb16c5bbfff6a22312e8eab92c2c99c51a02e39b4eae54ce8255cd1 \ 102 | --hash=sha256:295badf61a51add2d428a46b8580309c520d8b26e769868b922750cf3ce67142 \ 103 | --hash=sha256:2a3bf8b48f8e37c3a40bb3f854bf0121c194e69a650b209628d951190b862de3 \ 104 | --hash=sha256:4385f12aa289d79419fede43f979e372f527892ac44a541b5446617e4406c468 \ 105 | --hash=sha256:5635cd1ed0a12b4c42cce18a8d2fb53ff13ff537f09de5fd791e97de27b6400e \ 106 | --hash=sha256:5bfed051dbff32fd8945eccca70f5e22b55e4148d2a8a45141a3b053d6455ae3 \ 107 | --hash=sha256:7e1037073b1b7053ee74c3c6c0ada80f3501ec29d5f46e42669378eae6d4405a \ 108 | --hash=sha256:90742c6ff121a9c5b261b9b215cb476eea97df98ea82037ec8ac95d1be7a034f \ 109 | --hash=sha256:a58dd45cb865be0ce1d5ecc4cfc85cd8c6867bea66733623e54bd95131f473b6 \ 110 | --hash=sha256:c087bff162158536387c53647411db09b6ee3f9603c334c90943e97b1052a156 \ 111 | --hash=sha256:c162a21e0da33eb3d31a3ac17a51db5e634fc347f650d271f0305d96601dc15b \ 112 | --hash=sha256:c9423a150d3a4fc0f3f2aae897a59919acd293f4cb397429b120a5fcd96ea3db \ 113 | --hash=sha256:ccccdd84912875e34c5ad2d06e1989d890d43af6c2242c6fcfa51556997af6cd \ 114 | --hash=sha256:e91ba11da11cf770f389e47c3f5c30473e6d85e06d7fd9dcba0017d2867aab4a \ 115 | --hash=sha256:ea4adf02d23b437684cd388d557bf76e3afa72f7fed5bbc013482cc00c816948 \ 116 | --hash=sha256:fb95debbd1a824b2c4376932f2216cc186912e389bdb0e27147778cf6acb3f89 117 | # via black 118 | six==1.14.0 \ 119 | --hash=sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a \ 120 | --hash=sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c 121 | # via astroid 122 | toml==0.10.0 \ 123 | --hash=sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c \ 124 | --hash=sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e 125 | # via black 126 | tomli==2.0.1 \ 127 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 128 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 129 | # via mypy 130 | typed-ast==1.4.1 \ 131 | --hash=sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355 \ 132 | --hash=sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919 \ 133 | --hash=sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa \ 134 | --hash=sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652 \ 135 | --hash=sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75 \ 136 | --hash=sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01 \ 137 | --hash=sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d \ 138 | --hash=sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1 \ 139 | --hash=sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907 \ 140 | --hash=sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c \ 141 | --hash=sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3 \ 142 | --hash=sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b \ 143 | --hash=sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614 \ 144 | --hash=sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb \ 145 | --hash=sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b \ 146 | --hash=sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41 \ 147 | --hash=sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6 \ 148 | --hash=sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34 \ 149 | --hash=sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe \ 150 | --hash=sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4 \ 151 | --hash=sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7 152 | # via black 153 | typing-extensions==4.1.1 \ 154 | --hash=sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42 \ 155 | --hash=sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2 156 | # via mypy 157 | wrapt==1.11.2 \ 158 | --hash=sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1 159 | # via astroid 160 | -------------------------------------------------------------------------------- /connector/test/test_connector.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import asyncio 4 | import warnings 5 | 6 | sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 7 | import unittest 8 | from unittest.mock import patch, Mock, AsyncMock, ANY 9 | import main 10 | 11 | 12 | class EndTestNow(Exception): 13 | pass 14 | 15 | 16 | class TestReconnect(unittest.TestCase): 17 | def setUp(self): 18 | self.init_cmd_limit = 2 19 | self.init_cmds = [] 20 | self.env = patch.dict( 21 | "os.environ", 22 | { 23 | "COMPRESSION": "", 24 | "FH_USERNAME": "testuser", 25 | "FH_APIKEY": "testapikey", 26 | "KEEPALIVE": "60", 27 | "KEEPALIVE_STALE_PITRS": "5", 28 | "INIT_CMD_ARGS": "", 29 | "INIT_CMD_TIME": "live", 30 | "SERVER": "testserver", 31 | "PRINT_STATS_PERIOD": "0", 32 | "KAFKA_TOPIC_NAME": "topic1", 33 | }, 34 | ) 35 | self.mock_reader = Mock() 36 | self.mock_reader.readline = AsyncMock() 37 | self.mock_writer = Mock() 38 | self.mock_writer.drain = AsyncMock() 39 | self.mock_writer.write.side_effect = self.save_init_cmd_stop_test 40 | 41 | def tearDown(self): 42 | pass 43 | 44 | def save_init_cmd_stop_test(self, init_cmd): 45 | self.init_cmds.append(init_cmd) 46 | 47 | if len(self.init_cmds) >= self.init_cmd_limit: 48 | raise EndTestNow() 49 | 50 | def reconnect_after_error( 51 | self, test_reconnect_live, mock_kafkaproducer, mock_openconnection, error 52 | ): 53 | # mock setup 54 | if not isinstance(error, list): 55 | error = [error] 56 | if test_reconnect_live: 57 | self.mock_reader.readline.side_effect = error 58 | else: 59 | self.mock_reader.readline.side_effect = [ 60 | b'{"pitr":"1584126630","type":"arrival","id":"KPVD-1588929046-hexid-ADF994"}', 61 | ] + error 62 | mock_openconnection.return_value = self.mock_reader, self.mock_writer 63 | 64 | # run test 65 | with self.assertRaises(EndTestNow), self.env: 66 | pitr = asyncio.run(main.main()) 67 | 68 | if test_reconnect_live: 69 | # verify expected init cmds 70 | self.assertEqual( 71 | self.init_cmds, 72 | [ 73 | b"live username testuser password testapikey useragent firestarter keepalive 60\n", 74 | b"live username testuser password testapikey useragent firestarter keepalive 60\n", 75 | ], 76 | ) 77 | # verify expect output to kafka 78 | # only call should be the to the test topic that the producer is ready 79 | self.assertEqual(mock_kafkaproducer.return_value.produce.call_count, 1) 80 | else: 81 | # verify expected init cmds 82 | self.assertEqual( 83 | self.init_cmds, 84 | [ 85 | b"live username testuser password testapikey useragent firestarter keepalive 60\n", 86 | b"pitr 1584126630 username testuser password testapikey useragent firestarter keepalive 60\n", 87 | ], 88 | ) 89 | # verify expect output to kafka 90 | if len(error) == 1: 91 | mock_kafkaproducer.return_value.produce.assert_any_call( 92 | "topic1", 93 | key=b"KPVD-1588929046-hexid-ADF994", 94 | value=b'{"pitr":"1584126630","type":"arrival","id":"KPVD-1588929046-hexid-ADF994"}', 95 | callback=ANY, 96 | ) 97 | self.assertEqual(mock_kafkaproducer.return_value.produce.call_count, 2) 98 | else: 99 | self.assertEqual(mock_kafkaproducer.return_value.produce.call_count, len(error)+1) 100 | 101 | @patch("main.open_connection", new_callable=AsyncMock) 102 | @patch("main.Producer", new_callable=Mock) 103 | def test_pitr_eof(self, mock_kafkaproducer, mock_openconnection): 104 | self.reconnect_after_error(False, mock_kafkaproducer, mock_openconnection, b"") 105 | 106 | @patch("main.open_connection", new_callable=AsyncMock) 107 | @patch("main.Producer", new_callable=Mock) 108 | def test_live_eof(self, mock_kafkaproducer, mock_openconnection): 109 | self.reconnect_after_error(True, mock_kafkaproducer, mock_openconnection, b"") 110 | 111 | @patch("main.open_connection", new_callable=AsyncMock) 112 | @patch("main.Producer", new_callable=Mock) 113 | def test_pitr_timeout(self, mock_kafkaproducer, mock_openconnection): 114 | self.reconnect_after_error( 115 | False, mock_kafkaproducer, mock_openconnection, asyncio.TimeoutError 116 | ) 117 | 118 | @patch("main.open_connection", new_callable=AsyncMock) 119 | @patch("main.Producer", new_callable=Mock) 120 | def test_live_timeout(self, mock_kafkaproducer, mock_openconnection): 121 | self.reconnect_after_error( 122 | True, mock_kafkaproducer, mock_openconnection, asyncio.TimeoutError 123 | ) 124 | 125 | @patch("main.open_connection", new_callable=AsyncMock) 126 | @patch("main.Producer", new_callable=Mock) 127 | def test_pitr_disconnect(self, mock_kafkaproducer, mock_openconnection): 128 | self.reconnect_after_error(False, mock_kafkaproducer, mock_openconnection, AttributeError) 129 | 130 | @patch("main.open_connection", new_callable=AsyncMock) 131 | @patch("main.Producer", new_callable=Mock) 132 | def test_live_disconnect(self, mock_kafkaproducer, mock_openconnection): 133 | self.reconnect_after_error(True, mock_kafkaproducer, mock_openconnection, AttributeError) 134 | 135 | @patch("main.open_connection", new_callable=AsyncMock) 136 | @patch("main.Producer", new_callable=Mock) 137 | def test_pitr_error_msg(self, mock_kafkaproducer, mock_openconnection): 138 | self.reconnect_after_error( 139 | False, 140 | mock_kafkaproducer, 141 | mock_openconnection, 142 | b'{"pitr":"1584126630","type":"error","error_msg":"test error"}', 143 | ) 144 | 145 | @patch("main.open_connection", new_callable=AsyncMock) 146 | @patch("main.Producer", new_callable=Mock) 147 | def test_live_error_msg(self, mock_kafkaproducer, mock_openconnection): 148 | self.reconnect_after_error( 149 | True, 150 | mock_kafkaproducer, 151 | mock_openconnection, 152 | b'{"pitr":"1584126630","type":"error","error_msg":"test error"}', 153 | ) 154 | 155 | @patch("main.open_connection", new_callable=AsyncMock) 156 | @patch("main.Producer", new_callable=Mock) 157 | def test_pitr_drift_exceeded(self, mock_kafkaproducer, mock_openconnection): 158 | self.reconnect_after_error( 159 | False, 160 | mock_kafkaproducer, 161 | mock_openconnection, 162 | [ 163 | b'{"pitr":"1584126630","type":"keepalive"}', 164 | b'{"pitr":"1584126630","type":"keepalive"}', 165 | b'{"pitr":"1584126630","type":"keepalive"}', 166 | b'{"pitr":"1584126630","type":"keepalive"}', 167 | b'{"pitr":"1584126630","type":"keepalive"}', 168 | b'{"pitr":"1584126630","type":"keepalive"}', 169 | ] 170 | ) 171 | 172 | @patch("main.open_connection", new_callable=AsyncMock) 173 | @patch("main.Producer", new_callable=Mock) 174 | def test_pitr_drift_reset(self, mock_kafkaproducer, mock_openconnection): 175 | # does not reconnect and is waiting for the next message 176 | with self.assertRaises(StopAsyncIteration), self.env: 177 | self.reconnect_after_error( 178 | False, 179 | mock_kafkaproducer, 180 | mock_openconnection, 181 | [ 182 | b'{"pitr":"1584126630","type":"keepalive"}', 183 | b'{"pitr":"1584126630","type":"keepalive"}', 184 | b'{"pitr":"1584126630","type":"keepalive"}', 185 | b'{"pitr":"1584126630","type":"keepalive"}', 186 | b'{"pitr":"1584126630","type":"keepalive"}', 187 | b'{"pitr":"1584126631","type":"keepalive"}', 188 | ] 189 | ) 190 | 191 | 192 | # THIS TEST WILL ONLY RUN IN TRAVIS 193 | @unittest.skipIf(not os.getenv("FH_APIKEY"), "No login credentials") 194 | class TestCompression(unittest.TestCase): 195 | def setUp(self): 196 | self.emitted_msg = [] 197 | self.save_main_open_connection = main.open_connection 198 | warnings.simplefilter("ignore", category=ResourceWarning) 199 | 200 | def tearDown(self): 201 | self.fh_writer.close() 202 | 203 | async def wrap_open_connection(self, *args, **kwargs): 204 | self.fh_reader, self.fh_writer = await self.save_main_open_connection(*args, **kwargs) 205 | return self.fh_reader, self.fh_writer 206 | 207 | def save_line_stop_test(self, topic, value=None, key=None, callback=None): 208 | if topic != "test": 209 | self.emitted_msg.append(value) 210 | raise EndTestNow() 211 | 212 | def compression(self, mock_kafkaproducer, mock_openconnection, compression): 213 | mock_kafkaproducer.return_value.produce.side_effect = self.save_line_stop_test 214 | mock_openconnection.side_effect = self.wrap_open_connection 215 | # run test 216 | with self.assertRaises(EndTestNow): 217 | os.environ["COMPRESSION"] = compression 218 | pitr = asyncio.run(main.main()) 219 | 220 | self.assertEqual( 221 | self.emitted_msg, 222 | [ 223 | b'{"pitr":"1647160200","type":"flifo","ident":"RYR1005","dest":"LROP","actual_off":"1647159545","estimated_on":"1647170100","ete":"10555","facility_hash":"D5A46EA72EB25728","facility_name":"","id":"RYR1005-1646986800-schedule-0083","orig":"EGSS","reg":"EIEKI","scheduled_off":"1647159300","scheduled_departure_gate":"37","scheduled_out":"1647159300","status":"A"}\n' 224 | ], 225 | ) 226 | 227 | @patch("main.open_connection", new_callable=AsyncMock) 228 | @patch("main.Producer", new_callable=Mock) 229 | def test_no_compression(self, mock_kafkaproducer, mock_openconnection): 230 | self.compression(mock_kafkaproducer, mock_openconnection, "") 231 | 232 | @patch("main.open_connection", new_callable=AsyncMock) 233 | @patch("main.Producer", new_callable=Mock) 234 | def test_gzip_compression(self, mock_kafkaproducer, mock_openconnection): 235 | self.compression(mock_kafkaproducer, mock_openconnection, "gzip") 236 | 237 | @patch("main.open_connection", new_callable=AsyncMock) 238 | @patch("main.Producer", new_callable=Mock) 239 | def test_compress_compression(self, mock_kafkaproducer, mock_openconnection): 240 | self.compression(mock_kafkaproducer, mock_openconnection, "compress") 241 | 242 | @patch("main.open_connection", new_callable=AsyncMock) 243 | @patch("main.Producer", new_callable=Mock) 244 | def test_deflate_compression(self, mock_kafkaproducer, mock_openconnection): 245 | self.compression(mock_kafkaproducer, mock_openconnection, "deflate") 246 | -------------------------------------------------------------------------------- /map/requirements/dev.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with python 3.8 3 | # To update, run: 4 | # 5 | # pip-compile --generate-hashes --output-file=dev.txt dev.in 6 | # 7 | appdirs==1.4.4 \ 8 | --hash=sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41 \ 9 | --hash=sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128 10 | # via black 11 | astroid==2.3.3 \ 12 | --hash=sha256:71ea07f44df9568a75d0f354c49143a4575d90645e9fead6dfb52c26a85ed13a \ 13 | --hash=sha256:840947ebfa8b58f318d42301cf8c0a20fd794a33b61cc4638e28e9e61ba32f42 14 | # via pylint 15 | black==20.8b1 \ 16 | --hash=sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea 17 | # via -r dev.in 18 | click==7.1.2 \ 19 | --hash=sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a \ 20 | --hash=sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc 21 | # via 22 | # -c base.txt 23 | # black 24 | isort==4.3.21 \ 25 | --hash=sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1 \ 26 | --hash=sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd 27 | # via pylint 28 | lazy-object-proxy==1.4.3 \ 29 | --hash=sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d \ 30 | --hash=sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449 \ 31 | --hash=sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08 \ 32 | --hash=sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a \ 33 | --hash=sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50 \ 34 | --hash=sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd \ 35 | --hash=sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239 \ 36 | --hash=sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb \ 37 | --hash=sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea \ 38 | --hash=sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e \ 39 | --hash=sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156 \ 40 | --hash=sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142 \ 41 | --hash=sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442 \ 42 | --hash=sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62 \ 43 | --hash=sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db \ 44 | --hash=sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531 \ 45 | --hash=sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383 \ 46 | --hash=sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a \ 47 | --hash=sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357 \ 48 | --hash=sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4 \ 49 | --hash=sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0 50 | # via astroid 51 | mccabe==0.6.1 \ 52 | --hash=sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42 \ 53 | --hash=sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f 54 | # via pylint 55 | mypy==0.942 \ 56 | --hash=sha256:0e2dd88410937423fba18e57147dd07cd8381291b93d5b1984626f173a26543e \ 57 | --hash=sha256:10daab80bc40f84e3f087d896cdb53dc811a9f04eae4b3f95779c26edee89d16 \ 58 | --hash=sha256:17e44649fec92e9f82102b48a3bf7b4a5510ad0cd22fa21a104826b5db4903e2 \ 59 | --hash=sha256:1a0459c333f00e6a11cbf6b468b870c2b99a906cb72d6eadf3d1d95d38c9352c \ 60 | --hash=sha256:246e1aa127d5b78488a4a0594bd95f6d6fb9d63cf08a66dafbff8595d8891f67 \ 61 | --hash=sha256:2b184db8c618c43c3a31b32ff00cd28195d39e9c24e7c3b401f3db7f6e5767f5 \ 62 | --hash=sha256:2bc249409a7168d37c658e062e1ab5173300984a2dada2589638568ddc1db02b \ 63 | --hash=sha256:3841b5433ff936bff2f4dc8d54cf2cdbfea5d8e88cedfac45c161368e5770ba6 \ 64 | --hash=sha256:4c3e497588afccfa4334a9986b56f703e75793133c4be3a02d06a3df16b67a58 \ 65 | --hash=sha256:5bf44840fb43ac4074636fd47ee476d73f0039f4f54e86d7265077dc199be24d \ 66 | --hash=sha256:64235137edc16bee6f095aba73be5334677d6f6bdb7fa03cfab90164fa294a17 \ 67 | --hash=sha256:6776e5fa22381cc761df53e7496a805801c1a751b27b99a9ff2f0ca848c7eca0 \ 68 | --hash=sha256:6ce34a118d1a898f47def970a2042b8af6bdcc01546454726c7dd2171aa6dfca \ 69 | --hash=sha256:6f6ad963172152e112b87cc7ec103ba0f2db2f1cd8997237827c052a3903eaa6 \ 70 | --hash=sha256:6f7106cbf9cc2f403693bf50ed7c9fa5bb3dfa9007b240db3c910929abe2a322 \ 71 | --hash=sha256:7742d2c4e46bb5017b51c810283a6a389296cda03df805a4f7869a6f41246534 \ 72 | --hash=sha256:9521c1265ccaaa1791d2c13582f06facf815f426cd8b07c3a485f486a8ffc1f3 \ 73 | --hash=sha256:a1b383fe99678d7402754fe90448d4037f9512ce70c21f8aee3b8bf48ffc51db \ 74 | --hash=sha256:b840cfe89c4ab6386c40300689cd8645fc8d2d5f20101c7f8bd23d15fca14904 \ 75 | --hash=sha256:d8d3ba77e56b84cd47a8ee45b62c84b6d80d32383928fe2548c9a124ea0a725c \ 76 | --hash=sha256:dcd955f36e0180258a96f880348fbca54ce092b40fbb4b37372ae3b25a0b0a46 \ 77 | --hash=sha256:e865fec858d75b78b4d63266c9aff770ecb6a39dfb6d6b56c47f7f8aba6baba8 \ 78 | --hash=sha256:edf7237137a1a9330046dbb14796963d734dd740a98d5e144a3eb1d267f5f9ee 79 | # via -r dev.in 80 | mypy-extensions==0.4.3 \ 81 | --hash=sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d \ 82 | --hash=sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8 83 | # via 84 | # black 85 | # mypy 86 | pathspec==0.8.1 \ 87 | --hash=sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd \ 88 | --hash=sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d 89 | # via black 90 | pylint==2.4.4 \ 91 | --hash=sha256:3db5468ad013380e987410a8d6956226963aed94ecb5f9d3a28acca6d9ac36cd \ 92 | --hash=sha256:886e6afc935ea2590b462664b161ca9a5e40168ea99e5300935f6591ad467df4 93 | # via -r dev.in 94 | regex==2021.3.17 \ 95 | --hash=sha256:07ef35301b4484bce843831e7039a84e19d8d33b3f8b2f9aab86c376813d0139 \ 96 | --hash=sha256:13f50969028e81765ed2a1c5fcfdc246c245cf8d47986d5172e82ab1a0c42ee5 \ 97 | --hash=sha256:14de88eda0976020528efc92d0a1f8830e2fb0de2ae6005a6fc4e062553031fa \ 98 | --hash=sha256:159fac1a4731409c830d32913f13f68346d6b8e39650ed5d704a9ce2f9ef9cb3 \ 99 | --hash=sha256:18e25e0afe1cf0f62781a150c1454b2113785401ba285c745acf10c8ca8917df \ 100 | --hash=sha256:201e2619a77b21a7780580ab7b5ce43835e242d3e20fef50f66a8df0542e437f \ 101 | --hash=sha256:360a01b5fa2ad35b3113ae0c07fb544ad180603fa3b1f074f52d98c1096fa15e \ 102 | --hash=sha256:39c44532d0e4f1639a89e52355b949573e1e2c5116106a395642cbbae0ff9bcd \ 103 | --hash=sha256:3d9356add82cff75413bec360c1eca3e58db4a9f5dafa1f19650958a81e3249d \ 104 | --hash=sha256:3d9a7e215e02bd7646a91fb8bcba30bc55fd42a719d6b35cf80e5bae31d9134e \ 105 | --hash=sha256:4651f839dbde0816798e698626af6a2469eee6d9964824bb5386091255a1694f \ 106 | --hash=sha256:486a5f8e11e1f5bbfcad87f7c7745eb14796642323e7e1829a331f87a713daaa \ 107 | --hash=sha256:4b8a1fb724904139149a43e172850f35aa6ea97fb0545244dc0b805e0154ed68 \ 108 | --hash=sha256:4c0788010a93ace8a174d73e7c6c9d3e6e3b7ad99a453c8ee8c975ddd9965643 \ 109 | --hash=sha256:4c2e364491406b7888c2ad4428245fc56c327e34a5dfe58fd40df272b3c3dab3 \ 110 | --hash=sha256:575a832e09d237ae5fedb825a7a5bc6a116090dd57d6417d4f3b75121c73e3be \ 111 | --hash=sha256:5770a51180d85ea468234bc7987f5597803a4c3d7463e7323322fe4a1b181578 \ 112 | --hash=sha256:633497504e2a485a70a3268d4fc403fe3063a50a50eed1039083e9471ad0101c \ 113 | --hash=sha256:63f3ca8451e5ff7133ffbec9eda641aeab2001be1a01878990f6c87e3c44b9d5 \ 114 | --hash=sha256:709f65bb2fa9825f09892617d01246002097f8f9b6dde8d1bb4083cf554701ba \ 115 | --hash=sha256:808404898e9a765e4058bf3d7607d0629000e0a14a6782ccbb089296b76fa8fe \ 116 | --hash=sha256:882f53afe31ef0425b405a3f601c0009b44206ea7f55ee1c606aad3cc213a52c \ 117 | --hash=sha256:8bd4f91f3fb1c9b1380d6894bd5b4a519409135bec14c0c80151e58394a4e88a \ 118 | --hash=sha256:8e65e3e4c6feadf6770e2ad89ad3deb524bcb03d8dc679f381d0568c024e0deb \ 119 | --hash=sha256:976a54d44fd043d958a69b18705a910a8376196c6b6ee5f2596ffc11bff4420d \ 120 | --hash=sha256:a0d04128e005142260de3733591ddf476e4902c0c23c1af237d9acf3c96e1b38 \ 121 | --hash=sha256:a0df9a0ad2aad49ea3c7f65edd2ffb3d5c59589b85992a6006354f6fb109bb18 \ 122 | --hash=sha256:a2ee026f4156789df8644d23ef423e6194fad0bc53575534101bb1de5d67e8ce \ 123 | --hash=sha256:a59a2ee329b3de764b21495d78c92ab00b4ea79acef0f7ae8c1067f773570afa \ 124 | --hash=sha256:b97ec5d299c10d96617cc851b2e0f81ba5d9d6248413cd374ef7f3a8871ee4a6 \ 125 | --hash=sha256:b98bc9db003f1079caf07b610377ed1ac2e2c11acc2bea4892e28cc5b509d8d5 \ 126 | --hash=sha256:b9d8d286c53fe0cbc6d20bf3d583cabcd1499d89034524e3b94c93a5ab85ca90 \ 127 | --hash=sha256:bcd945175c29a672f13fce13a11893556cd440e37c1b643d6eeab1988c8b209c \ 128 | --hash=sha256:c66221e947d7207457f8b6f42b12f613b09efa9669f65a587a2a71f6a0e4d106 \ 129 | --hash=sha256:c782da0e45aff131f0bed6e66fbcfa589ff2862fc719b83a88640daa01a5aff7 \ 130 | --hash=sha256:cb4ee827857a5ad9b8ae34d3c8cc51151cb4a3fe082c12ec20ec73e63cc7c6f0 \ 131 | --hash=sha256:d47d359545b0ccad29d572ecd52c9da945de7cd6cf9c0cfcb0269f76d3555689 \ 132 | --hash=sha256:dc9963aacb7da5177e40874585d7407c0f93fb9d7518ec58b86e562f633f36cd \ 133 | --hash=sha256:ea2f41445852c660ba7c3ebf7d70b3779b20d9ca8ba54485a17740db49f46932 \ 134 | --hash=sha256:f5d0c921c99297354cecc5a416ee4280bd3f20fd81b9fb671ca6be71499c3fdf \ 135 | --hash=sha256:f85d6f41e34f6a2d1607e312820971872944f1661a73d33e1e82d35ea3305e14 136 | # via black 137 | six==1.15.0 \ 138 | --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ 139 | --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced 140 | # via astroid 141 | toml==0.10.2 \ 142 | --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ 143 | --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f 144 | # via black 145 | tomli==2.0.1 \ 146 | --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ 147 | --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f 148 | # via mypy 149 | typed-ast==1.4.2 \ 150 | --hash=sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1 \ 151 | --hash=sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d \ 152 | --hash=sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6 \ 153 | --hash=sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd \ 154 | --hash=sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37 \ 155 | --hash=sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151 \ 156 | --hash=sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07 \ 157 | --hash=sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440 \ 158 | --hash=sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70 \ 159 | --hash=sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496 \ 160 | --hash=sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea \ 161 | --hash=sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400 \ 162 | --hash=sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc \ 163 | --hash=sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606 \ 164 | --hash=sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc \ 165 | --hash=sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581 \ 166 | --hash=sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412 \ 167 | --hash=sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a \ 168 | --hash=sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2 \ 169 | --hash=sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787 \ 170 | --hash=sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f \ 171 | --hash=sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937 \ 172 | --hash=sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64 \ 173 | --hash=sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487 \ 174 | --hash=sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b \ 175 | --hash=sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41 \ 176 | --hash=sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a \ 177 | --hash=sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3 \ 178 | --hash=sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166 \ 179 | --hash=sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10 180 | # via black 181 | typing-extensions==4.1.1 \ 182 | --hash=sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42 \ 183 | --hash=sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2 184 | # via 185 | # black 186 | # mypy 187 | wrapt==1.11.2 \ 188 | --hash=sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1 189 | # via astroid 190 | --------------------------------------------------------------------------------