fix: will I ever make relative paths work?

This commit is contained in:
Davide Passoni
2024-12-11 10:22:53 +01:00
parent e41d3c93a6
commit dc7fd2c870
30 changed files with 468 additions and 461 deletions

6
frontend/build.bat Normal file
View File

@@ -0,0 +1,6 @@
cd react
call npm run build-release
cd ..
cd server
robocopy ./databases ./public/databases /E

View File

@@ -3,12 +3,12 @@
"short_name": "DCS Olympus", "short_name": "DCS Olympus",
"icons": [ "icons": [
{ {
"src": "./images/favicons/android-chrome-192x192.png", "src": "/images/favicons/android-chrome-192x192.png",
"sizes": "192x192", "sizes": "192x192",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "./images/favicons/android-chrome-512x512.png", "src": "/images/favicons/android-chrome-512x512.png",
"sizes": "512x512", "sizes": "512x512",
"type": "image/png" "type": "image/png"
} }

View File

@@ -31,7 +31,7 @@ export class ExplosionMarker extends CustomMarker {
var el = document.createElement("div"); var el = document.createElement("div");
el.classList.add("ol-explosion-icon"); el.classList.add("ol-explosion-icon");
var img = document.createElement("img"); var img = document.createElement("img");
img.src = "./images/markers/explosion.svg"; img.src = "/images/markers/explosion.svg";
img.onload = () => SVGInjector(img); img.onload = () => SVGInjector(img);
el.appendChild(img); el.appendChild(img);
this.getElement()?.appendChild(el); this.getElement()?.appendChild(el);

View File

@@ -28,7 +28,7 @@ export class SmokeMarker extends CustomMarker {
el.classList.add("ol-smoke-icon"); el.classList.add("ol-smoke-icon");
el.setAttribute("data-color", this.#color); el.setAttribute("data-color", this.#color);
var img = document.createElement("img"); var img = document.createElement("img");
img.src = "./images/markers/smoke.svg"; img.src = "/images/markers/smoke.svg";
img.onload = () => SVGInjector(img); img.onload = () => SVGInjector(img);
el.appendChild(img); el.appendChild(img);
this.getElement()?.appendChild(el); this.getElement()?.appendChild(el);

View File

@@ -1,6 +1,6 @@
.airbase-icon { .airbase-icon {
align-items: center; align-items: center;
cursor: url("../images/cursors/pointer.svg"), auto; cursor: url("/images/cursors/pointer.svg"), auto;
display: flex; display: flex;
justify-content: center; justify-content: center;
position: relative; position: relative;

View File

@@ -1,6 +1,6 @@
.bullseye-icon { .bullseye-icon {
align-items: center; align-items: center;
cursor: url("../images/cursors/pointer.svg"), auto; cursor: url("/images/cursors/pointer.svg"), auto;
display: flex; display: flex;
justify-content: center; justify-content: center;
position: relative; position: relative;

View File

@@ -1,6 +1,6 @@
/*** Unit marker elements ***/ /*** Unit marker elements ***/
[data-object|="unit"] { [data-object|="unit"] {
cursor: url("../images/cursors/pointer.svg"), auto; cursor: url("/images/cursors/pointer.svg"), auto;
display: flex; display: flex;
height: 100%; height: 100%;
justify-content: center; justify-content: center;
@@ -9,29 +9,29 @@
} }
[data-object|="unit"].attack-cursor { [data-object|="unit"].attack-cursor {
cursor: url("../images/cursors/attack.svg"), auto !important; cursor: url("/images/cursors/attack.svg"), auto !important;
} }
[data-object|="unit"].follow-cursor { [data-object|="unit"].follow-cursor {
cursor: url("../images/cursors/follow.svg"), auto !important; cursor: url("/images/cursors/follow.svg"), auto !important;
} }
[data-object|="unit"].fire-at-area-cursor, [data-object|="unit"].fire-at-area-cursor,
[data-object|="unit"].bomb-cursor, [data-object|="unit"].bomb-cursor,
[data-object|="unit"].carpet-bomb-cursor { [data-object|="unit"].carpet-bomb-cursor {
cursor: url("../images/cursors/fire-at-area.svg"), auto !important; cursor: url("/images/cursors/fire-at-area.svg"), auto !important;
} }
[data-object|="unit"].land-cursor { [data-object|="unit"].land-cursor {
cursor: url("../images/cursors/land.svg"), auto !important; cursor: url("/images/cursors/land.svg"), auto !important;
} }
[data-object|="unit"].land-at-point-cursor { [data-object|="unit"].land-at-point-cursor {
cursor: url("../images/cursors/land-at-point.svg"), auto !important; cursor: url("/images/cursors/land-at-point.svg"), auto !important;
} }
[data-object|="unit"].simulate-fire-fight-cursor { [data-object|="unit"].simulate-fire-fight-cursor {
cursor: url("../images/cursors/simulate-fire-fight.svg"), auto !important; cursor: url("/images/cursors/simulate-fire-fight.svg"), auto !important;
} }
[data-awacs-mode] .unit-short-label { [data-awacs-mode] .unit-short-label {
@@ -439,15 +439,15 @@
} }
[data-object|="unit"][data-state="rtb"] .unit-state { [data-object|="unit"][data-state="rtb"] .unit-state {
background-image: url("../images/states/rtb.svg"); background-image: url("/images/states/rtb.svg");
} }
[data-object|="unit"][data-state="land"] .unit-state { [data-object|="unit"][data-state="land"] .unit-state {
background-image: url("../images/states/rtb.svg"); background-image: url("/images/states/rtb.svg");
} }
[data-object|="unit"][data-state="idle"] .unit-state { [data-object|="unit"][data-state="idle"] .unit-state {
background-image: url("../images/states/idle.svg"); background-image: url("/images/states/idle.svg");
} }
[data-object*="groundunit"][data-state="idle"] .unit-state, [data-object*="groundunit"][data-state="idle"] .unit-state,
@@ -459,59 +459,59 @@
[data-object|="unit"][data-state="bomb-point"] .unit-state, [data-object|="unit"][data-state="bomb-point"] .unit-state,
[data-object|="unit"][data-state="carpet-bombing"] .unit-state, [data-object|="unit"][data-state="carpet-bombing"] .unit-state,
[data-object|="unit"][data-state="fire-at-area"] .unit-state { [data-object|="unit"][data-state="fire-at-area"] .unit-state {
background-image: url("../images/states/attack.svg"); background-image: url("/images/states/attack.svg");
} }
[data-object|="unit"][data-state="follow"] .unit-state { [data-object|="unit"][data-state="follow"] .unit-state {
background-image: url("../images/states/follow.svg"); background-image: url("/images/states/follow.svg");
} }
[data-object|="unit"][data-state="refuel"] .unit-state { [data-object|="unit"][data-state="refuel"] .unit-state {
background-image: url("../images/states/refuel.svg"); background-image: url("/images/states/refuel.svg");
} }
[data-object|="unit"][data-state="human"] .unit-state { [data-object|="unit"][data-state="human"] .unit-state {
background-image: url("../images/states/human.svg"); background-image: url("/images/states/human.svg");
} }
[data-object|="unit"][data-state="dcs"] .unit-state { [data-object|="unit"][data-state="dcs"] .unit-state {
background-image: url("../images/states/dcs.svg"); background-image: url("/images/states/dcs.svg");
} }
[data-object|="unit"][data-state="land-at-point"] .unit-state { [data-object|="unit"][data-state="land-at-point"] .unit-state {
background-image: url("../images/states/land-at-point.svg"); background-image: url("/images/states/land-at-point.svg");
} }
[data-object|="unit"][data-state="no-task"] .unit-state { [data-object|="unit"][data-state="no-task"] .unit-state {
background-image: url("../images/states/no-task.svg"); background-image: url("/images/states/no-task.svg");
} }
[data-object|="unit"][data-state="off"] .unit-state { [data-object|="unit"][data-state="off"] .unit-state {
background-image: url("../images/states/off.svg"); background-image: url("/images/states/off.svg");
} }
[data-object|="unit"][data-state="tanker"] .unit-state { [data-object|="unit"][data-state="tanker"] .unit-state {
background-image: url("../images/states/tanker.svg"); background-image: url("/images/states/tanker.svg");
} }
[data-object|="unit"][data-state="AWACS"] .unit-state { [data-object|="unit"][data-state="AWACS"] .unit-state {
background-image: url("../images/states/awacs.svg"); background-image: url("/images/states/awacs.svg");
} }
[data-object|="unit"][data-state="miss-on-purpose"] .unit-state { [data-object|="unit"][data-state="miss-on-purpose"] .unit-state {
background-image: url("../images/states/miss-on-purpose.svg"); background-image: url("/images/states/miss-on-purpose.svg");
} }
[data-object|="unit"][data-state="scenic-aaa"] .unit-state { [data-object|="unit"][data-state="scenic-aaa"] .unit-state {
background-image: url("../images/states/scenic-aaa.svg"); background-image: url("/images/states/scenic-aaa.svg");
} }
[data-object|="unit"][data-state="simulate-fire-fight"] .unit-state { [data-object|="unit"][data-state="simulate-fire-fight"] .unit-state {
background-image: url("../images/states/simulate-fire-fight.svg"); background-image: url("/images/states/simulate-fire-fight.svg");
} }
[data-object|="unit"] .unit-health::before { [data-object|="unit"] .unit-health::before {
background-image: url("../images/icons/health.svg"); background-image: url("/images/icons/health.svg");
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: contain; background-size: contain;
content: " "; content: " ";

View File

@@ -56,7 +56,7 @@ export class TemporaryUnitMarker extends CustomMarker {
var unitIcon = document.createElement("div"); var unitIcon = document.createElement("div");
unitIcon.classList.add("unit-icon"); unitIcon.classList.add("unit-icon");
var img = document.createElement("img"); var img = document.createElement("img");
img.src = `./images/units/map/${getApp().getMap().getOptions().AWACSMode ? "awacs" : "normal"}/${this.#coalition}/${blueprint.markerFile ?? blueprint.category}.svg`; img.src = `/images/units/map/${getApp().getMap().getOptions().AWACSMode ? "awacs" : "normal"}/${this.#coalition}/${blueprint.markerFile ?? blueprint.category}.svg`;
img.onload = () => SVGInjector(img); img.onload = () => SVGInjector(img);
unitIcon.appendChild(img); unitIcon.appendChild(img);
unitIcon.toggleAttribute("data-rotate-to-heading", false); unitIcon.toggleAttribute("data-rotate-to-heading", false);

View File

@@ -132,7 +132,7 @@
} }
.ol-target-icon { .ol-target-icon {
background-image: url("../images/markers/target.svg"); background-image: url("/images/markers/target.svg");
height: 100%; height: 100%;
width: 100%; width: 100%;
} }
@@ -184,53 +184,53 @@ path.leaflet-interactive:focus {
} }
.attack-cursor { .attack-cursor {
cursor: url("../images/cursors/attack.svg"), auto !important; cursor: url("/images/cursors/attack.svg"), auto !important;
} }
.follow-cursor { .follow-cursor {
cursor: url("../images/cursors/follow.svg"), auto !important; cursor: url("/images/cursors/follow.svg"), auto !important;
} }
.fire-at-area-cursor, .bomb-cursor, .carpet-bomb-cursor { .fire-at-area-cursor, .bomb-cursor, .carpet-bomb-cursor {
cursor: url("../images/cursors/fire-at-area.svg"), auto !important; cursor: url("/images/cursors/fire-at-area.svg"), auto !important;
} }
.land-cursor { .land-cursor {
cursor: url("../images/cursors/land.svg"), auto !important; cursor: url("/images/cursors/land.svg"), auto !important;
} }
.land-at-point-cursor { .land-at-point-cursor {
cursor: url("../images/cursors/land-at-point.svg"), auto !important; cursor: url("/images/cursors/land-at-point.svg"), auto !important;
} }
.simulate-fire-fight-cursor { .simulate-fire-fight-cursor {
cursor: url("../images/cursors/simulate-fire-fight.svg"), auto !important; cursor: url("/images/cursors/simulate-fire-fight.svg"), auto !important;
} }
#map-container.leaflet-grab { #map-container.leaflet-grab {
cursor: url("../images/cursors/grab.svg") 16 16, auto; cursor: url("/images/cursors/grab.svg") 16 16, auto;
} }
.explosion-cursor { .explosion-cursor {
cursor: url("../images/cursors/explosion.svg"), auto !important; cursor: url("/images/cursors/explosion.svg"), auto !important;
} }
.smoke-white-cursor { .smoke-white-cursor {
cursor: url("../images/cursors/smoke-white.svg"), auto !important; cursor: url("/images/cursors/smoke-white.svg"), auto !important;
} }
.smoke-blue-cursor { .smoke-blue-cursor {
cursor: url("../images/cursors/smoke-blue.svg"), auto !important; cursor: url("/images/cursors/smoke-blue.svg"), auto !important;
} }
.smoke-red-cursor { .smoke-red-cursor {
cursor: url("../images/cursors/smoke-red.svg"), auto !important; cursor: url("/images/cursors/smoke-red.svg"), auto !important;
} }
.smoke-green-cursor { .smoke-green-cursor {
cursor: url("../images/cursors/smoke-green.svg"), auto !important; cursor: url("/images/cursors/smoke-green.svg"), auto !important;
} }
.smoke-orange-cursor { .smoke-orange-cursor {
cursor: url("../images/cursors/smoke-orange.svg"), auto !important; cursor: url("/images/cursors/smoke-orange.svg"), auto !important;
} }

View File

@@ -67,7 +67,7 @@ export class Airbase extends CustomMarker {
el.classList.add("airbase-icon"); el.classList.add("airbase-icon");
el.setAttribute("data-object", "airbase"); el.setAttribute("data-object", "airbase");
this.#img.src = "./images/markers/airbase.svg"; this.#img.src = "/images/markers/airbase.svg";
this.#img.onload = () => SVGInjector(this.#img); this.#img.onload = () => SVGInjector(this.#img);
el.appendChild(this.#img); el.appendChild(this.#img);
this.getElement()?.appendChild(el); this.getElement()?.appendChild(el);

View File

@@ -23,7 +23,7 @@ export class Bullseye extends CustomMarker {
el.classList.add("bullseye-icon"); el.classList.add("bullseye-icon");
el.setAttribute("data-object", "bullseye"); el.setAttribute("data-object", "bullseye");
var img = document.createElement("img"); var img = document.createElement("img");
img.src = "./images/markers/bullseye.svg"; img.src = "/images/markers/bullseye.svg";
img.onload = () => SVGInjector(img); img.onload = () => SVGInjector(img);
el.appendChild(img); el.appendChild(img);
this.getElement()?.appendChild(el); this.getElement()?.appendChild(el);

View File

@@ -15,7 +15,7 @@ export class Carrier extends Airbase {
el.classList.add("airbase-icon"); el.classList.add("airbase-icon");
el.setAttribute("data-object", "airbase"); el.setAttribute("data-object", "airbase");
this.getImg().src = "./images/carriers/nimitz.png"; this.getImg().src = "/images/carriers/nimitz.png";
this.getImg().style.width = `0px`; // Make the image immediately small to avoid giant carriers this.getImg().style.width = `0px`; // Make the image immediately small to avoid giant carriers
el.appendChild(this.getImg()); el.appendChild(this.getImg());
this.getElement()?.appendChild(el); this.getElement()?.appendChild(el);

View File

@@ -44,7 +44,7 @@ export function OlUnitListEntry(props: {
invert invert
`}> `}>
<img <img
src={`./images/units/${props.silhouette}`} src={`/images/units/${props.silhouette}`}
className="my-auto max-h-full max-w-full" className="my-auto max-h-full max-w-full"
/> />
</div> </div>

View File

@@ -20,7 +20,7 @@ export function OlUnitSummary(props: { blueprint: UnitBlueprint; coalition: Coal
className={` className={`
absolute right-5 top-0 h-full object-cover opacity-10 invert absolute right-5 top-0 h-full object-cover opacity-10 invert
`} `}
src={"vite./images/units/" + props.blueprint.filename} src={"vite/images/units/" + props.blueprint.filename}
alt="" alt=""
/> />
<div <div

View File

@@ -94,7 +94,7 @@ export function LoginModal(props: { open: boolean }) {
max-md:border-none max-md:border-none
`} `}
> >
<img src="./images/splash/1.jpg" className={` <img src="/images/splash/1.jpg" className={`
contents-center w-full object-cover opacity-[7%] contents-center w-full object-cover opacity-[7%]
`}></img> `}></img>
<div <div
@@ -154,7 +154,7 @@ export function LoginModal(props: { open: boolean }) {
`} `}
> >
<span className="size-[80px] min-w-14"> <span className="size-[80px] min-w-14">
<img src="./images/olympus-500x500.png" className={` <img src="/images/olympus-500x500.png" className={`
flex w-full flex w-full
`}></img> `}></img>
</span> </span>
@@ -360,7 +360,7 @@ export function LoginModal(props: { open: boolean }) {
> >
<Card className="flex"> <Card className="flex">
<img <img
src="./images/splash/1.jpg" src="/images/splash/1.jpg"
className={` className={`
h-[40%] max-h-[120px] contents-center w-full rounded-md h-[40%] max-h-[120px] contents-center w-full rounded-md
object-cover object-cover
@@ -385,7 +385,7 @@ export function LoginModal(props: { open: boolean }) {
</Card> </Card>
<Card className="flex"> <Card className="flex">
<img <img
src="./images/splash/1.jpg" src="/images/splash/1.jpg"
className={` className={`
h-[40%] max-h-[120px] contents-center w-full rounded-md h-[40%] max-h-[120px] contents-center w-full rounded-md
object-cover object-cover

View File

@@ -349,7 +349,7 @@ export function FormationMenu(props: {
translate-y-[-50%] rotate-90 cursor-move opacity-80 translate-y-[-50%] rotate-90 cursor-move opacity-80
invert invert
`} `}
src={`./images/units/${unit?.getBlueprint()?.filename}`} src={`/images/units/${unit?.getBlueprint()?.filename}`}
></img> ></img>
</div> </div>
); );

View File

@@ -66,8 +66,8 @@ import {
const bearingStrings = ["north", "north-east", "east", "south-east", "south", "south-west", "west", "north-west", "north"]; const bearingStrings = ["north", "north-east", "east", "south-east", "south", "south-west", "west", "north-west", "north"];
var pathIcon = new Icon({ var pathIcon = new Icon({
iconUrl: "./images/markers/marker-icon.png", iconUrl: "/images/markers/marker-icon.png",
shadowUrl: "./images/markers/marker-shadow.png", shadowUrl: "/images/markers/marker-shadow.png",
iconAnchor: [13, 41], iconAnchor: [13, 41],
}); });
@@ -912,7 +912,7 @@ export abstract class Unit extends CustomMarker {
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().some((value) => [VISUAL, OPTIC].includes(value))) if (this.belongsToCommandedCoalition() || this.getDetectionMethods().some((value) => [VISUAL, OPTIC].includes(value)))
marker = this.getBlueprint()?.markerFile ?? this.getDefaultMarker(); marker = this.getBlueprint()?.markerFile ?? this.getDefaultMarker();
else marker = "aircraft"; else marker = "aircraft";
img.src = `./images/units/map/${getApp().getMap().getOptions().AWACSMode ? "awacs" : "normal"}/${this.getCoalition()}/${marker}.svg`; img.src = `/images/units/map/${getApp().getMap().getOptions().AWACSMode ? "awacs" : "normal"}/${this.getCoalition()}/${marker}.svg`;
img.onload = () => SVGInjector(img); img.onload = () => SVGInjector(img);
unitIcon.appendChild(img); unitIcon.appendChild(img);

View File

@@ -178,7 +178,7 @@ export class Weapon extends CustomMarker {
var unitIcon = document.createElement("div"); var unitIcon = document.createElement("div");
unitIcon.classList.add("unit-icon"); unitIcon.classList.add("unit-icon");
var img = document.createElement("img"); var img = document.createElement("img");
img.src = `./images/units/map/${getApp().getMap().getOptions().AWACSMode ? "awacs" : "normal"}/${this.getCoalition()}/${this.getMarkerCategory()}.svg`; img.src = `/images/units/map/${getApp().getMap().getOptions().AWACSMode ? "awacs" : "normal"}/${this.getCoalition()}/${this.getMarkerCategory()}.svg`;
img.onload = () => SVGInjector(img); img.onload = () => SVGInjector(img);
unitIcon.appendChild(img); unitIcon.appendChild(img);
unitIcon.toggleAttribute("data-rotate-to-heading", this.getIconOptions().rotateToHeading); unitIcon.toggleAttribute("data-rotate-to-heading", this.getIconOptions().rotateToHeading);

View File

@@ -6,10 +6,11 @@ export default defineConfig({
plugins: [react()], plugins: [react()],
base: "./", base: "./",
build: { build: {
outDir: '../server/public' outDir: "../server/public",
},esbuild: { emptyOutDir : true
},
esbuild: {
minifyIdentifiers: false, minifyIdentifiers: false,
keepNames: true, keepNames: true,
} },
}); });

View File

@@ -1,399 +1,399 @@
{ {
"airfields": { "airfields": {
"Severomorsk-1": { "Severomorsk-1": {
"runways": [ "runways": [
{ {
"headings": [ "headings": [
{ {
"14": { "14": {
"magHeading": "118", "magHeading": "118",
"Heading": "135", "Heading": "135",
"ILS": "" "ILS": ""
} }
}, },
{ {
"32": { "32": {
"magHeading": "299", "magHeading": "299",
"Heading": "315", "Heading": "315",
"ILS": "" "ILS": ""
} }
} }
], ],
"length": "9084" "length": "9084"
} }
], ],
"TACAN": "", "TACAN": "",
"ICAO": "ULAK", "ICAO": "ULAK",
"elevation": "261" "elevation": "261"
}, },
"Banak": { "Banak": {
"runways": [ "runways": [
{ {
"headings": [ "headings": [
{ {
"34": { "34": {
"magHeading": "339", "magHeading": "339",
"Heading": "352", "Heading": "352",
"ILS": "108.30" "ILS": "108.30"
} }
}, },
{ {
"16": { "16": {
"magHeading": "159", "magHeading": "159",
"Heading": "172", "Heading": "172",
"ILS": "" "ILS": ""
} }
} }
], ],
"length": "8104" "length": "8104"
} }
], ],
"TACAN": "47X", "TACAN": "47X",
"ICAO": "ENNA", "ICAO": "ENNA",
"elevation": "17" "elevation": "17"
}, },
"Severomorsk-3": { "Severomorsk-3": {
"runways": [ "runways": [
{ {
"headings": [ "headings": [
{ {
"35": { "35": {
"magHeading": "334", "magHeading": "334",
"Heading": "351", "Heading": "351",
"ILS": "" "ILS": ""
} }
}, },
{ {
"17": { "17": {
"magHeading": "154", "magHeading": "154",
"Heading": "171", "Heading": "171",
"ILS": "" "ILS": ""
} }
} }
], ],
"length": "7497" "length": "7497"
} }
], ],
"TACAN": "", "TACAN": "",
"ICAO": "XLMV", "ICAO": "XLMV",
"elevation": "567" "elevation": "567"
}, },
"Kemi Tornio": { "Kemi Tornio": {
"runways": [ "runways": [
{ {
"headings": [ "headings": [
{ {
"18": { "18": {
"magHeading": "173", "magHeading": "173",
"Heading": "184", "Heading": "184",
"ILS": "" "ILS": ""
} }
}, },
{ {
"36": { "36": {
"magHeading": "355", "magHeading": "355",
"Heading": "4", "Heading": "4",
"ILS": "110.90" "ILS": "110.90"
} }
} }
], ],
"length": "7862" "length": "7862"
} }
], ],
"TACAN": "", "TACAN": "",
"ICAO": "EFKE", "ICAO": "EFKE",
"elevation": "46" "elevation": "46"
}, },
"Murmansk International": { "Murmansk International": {
"runways": [ "runways": [
{ {
"headings": [ "headings": [
{ {
"13": { "13": {
"magHeading": "119", "magHeading": "119",
"Heading": "135", "Heading": "135",
"ILS": "110.30" "ILS": "110.30"
} }
}, },
{ {
"31": { "31": {
"magHeading": "299", "magHeading": "299",
"Heading": "315", "Heading": "315",
"ILS": "108.50" "ILS": "108.50"
} }
} }
], ],
"length": "7926" "length": "7926"
} }
], ],
"TACAN": "", "TACAN": "",
"ICAO": "ULMM", "ICAO": "ULMM",
"elevation": "249" "elevation": "249"
}, },
"Bodo": { "Bodo": {
"runways": [ "runways": [
{ {
"headings": [ "headings": [
{ {
"07": { "07": {
"magHeading": "78", "magHeading": "78",
"Heading": "84", "Heading": "84",
"ILS": "110.30" "ILS": "110.30"
} }
}, },
{ {
"25": { "25": {
"magHeading": "257", "magHeading": "257",
"Heading": "264", "Heading": "264",
"ILS": "108.70" "ILS": "108.70"
} }
} }
], ],
"length": "8618" "length": "8618"
} }
], ],
"TACAN": "45X", "TACAN": "45X",
"ICAO": "ENBO", "ICAO": "ENBO",
"elevation": "25" "elevation": "25"
}, },
"Rovaniemi": { "Rovaniemi": {
"runways": [ "runways": [
{ {
"headings": [ "headings": [
{ {
"21": { "21": {
"magHeading": "201", "magHeading": "201",
"Heading": "213", "Heading": "213",
"ILS": "117.70" "ILS": "117.70"
} }
}, },
{ {
"03": { "03": {
"magHeading": "21", "magHeading": "21",
"Heading": "33", "Heading": "33",
"ILS": "" "ILS": ""
} }
} }
], ],
"length": "9096" "length": "9096"
} }
], ],
"TACAN": "", "TACAN": "",
"ICAO": "EFRO", "ICAO": "EFRO",
"elevation": "612" "elevation": "612"
}, },
"Kalixfors": { "Kalixfors": {
"runways": [ "runways": [
{ {
"headings": [ "headings": [
{ {
"17": { "17": {
"magHeading": "162", "magHeading": "162",
"Heading": "171", "Heading": "171",
"ILS": "" "ILS": ""
} }
}, },
{ {
"35": { "35": {
"magHeading": "342", "magHeading": "342",
"Heading": "351", "Heading": "351",
"ILS": "" "ILS": ""
} }
} }
], ],
"length": "3597" "length": "3597"
} }
], ],
"TACAN": "", "TACAN": "",
"ICAO": "ESUK", "ICAO": "ESUK",
"elevation": "1552" "elevation": "1552"
}, },
"Jokkmokk": { "Jokkmokk": {
"runways": [ "runways": [
{ {
"headings": [ "headings": [
{ {
"14": { "14": {
"magHeading": "136", "magHeading": "136",
"Heading": "145", "Heading": "145",
"ILS": "" "ILS": ""
} }
}, },
{ {
"32": { "32": {
"magHeading": "316", "magHeading": "316",
"Heading": "325", "Heading": "325",
"ILS": "" "ILS": ""
} }
} }
], ],
"length": "6306" "length": "6306"
}, },
{ {
"headings": [ "headings": [
{ {
"32": { "32": {
"magHeading": "323", "magHeading": "323",
"Heading": "332", "Heading": "332",
"ILS": "" "ILS": ""
} }
}, },
{ {
"14": { "14": {
"magHeading": "143", "magHeading": "143",
"Heading": "152", "Heading": "152",
"ILS": "" "ILS": ""
} }
} }
], ],
"length": "6306" "length": "6306"
}, },
{ {
"headings": [ "headings": [
{ {
"15": { "15": {
"magHeading": "124", "magHeading": "124",
"Heading": "133", "Heading": "133",
"ILS": "" "ILS": ""
} }
}, },
{ {
"33": { "33": {
"magHeading": "302", "magHeading": "302",
"Heading": "313", "Heading": "313",
"ILS": "" "ILS": ""
} }
} }
], ],
"length": "3828" "length": "3828"
}, },
{ {
"headings": [ "headings": [
{ {
"36": { "36": {
"magHeading": "354", "magHeading": "354",
"Heading": "3", "Heading": "3",
"ILS": "" "ILS": ""
} }
}, },
{ {
"18": { "18": {
"magHeading": "174", "magHeading": "174",
"Heading": "183", "Heading": "183",
"ILS": "" "ILS": ""
} }
} }
], ],
"length": "3828" "length": "3828"
} }
], ],
"TACAN": "", "TACAN": "",
"ICAO": "ESNJ", "ICAO": "ESNJ",
"elevation": "891" "elevation": "891"
}, },
"Monchegorsk": { "Monchegorsk": {
"runways": [ "runways": [
{ {
"headings": [ "headings": [
{ {
"01": { "01": {
"magHeading": "001", "magHeading": "001",
"Heading": "16", "Heading": "16",
"ILS": "" "ILS": ""
} }
}, },
{ {
"19": { "19": {
"magHeading": "180", "magHeading": "180",
"Heading": "196", "Heading": "196",
"ILS": "" "ILS": ""
} }
} }
], ],
"length": "7509" "length": "7509"
} }
], ],
"TACAN": "", "TACAN": "",
"ICAO": "UMOE", "ICAO": "UMOE",
"elevation": "547" "elevation": "547"
}, },
"Olenya": { "Olenya": {
"runways": [ "runways": [
{ {
"headings": [ "headings": [
{ {
"19": { "19": {
"magHeading": "171", "magHeading": "171",
"Heading": "188", "Heading": "188",
"ILS": "" "ILS": ""
} }
}, },
{ {
"01": { "01": {
"magHeading": "352", "magHeading": "352",
"Heading": "8", "Heading": "8",
"ILS": "" "ILS": ""
} }
} }
], ],
"length": "10863" "length": "10863"
} }
], ],
"TACAN": "", "TACAN": "",
"ICAO": "UOLE", "ICAO": "UOLE",
"elevation": "721" "elevation": "721"
}, },
"Bas 100": { "Bas 100": {
"runways": [ "runways": [
{ {
"headings": [ "headings": [
{ {
"22": { "22": {
"magHeading": "210", "magHeading": "210",
"Heading": "223", "Heading": "223",
"ILS": "" "ILS": ""
} }
}, },
{ {
"04": { "04": {
"magHeading": "31", "magHeading": "31",
"Heading": "43", "Heading": "43",
"ILS": "" "ILS": ""
} }
} }
], ],
"length": "7719" "length": "7719"
} }
], ],
"TACAN": "", "TACAN": "",
"ICAO": "", "ICAO": "",
"elevation": "735" "elevation": "735"
}, },
"Kiruna": { "Kiruna": {
"runways": [ "runways": [
{ {
"headings": [ "headings": [
{ {
"21": { "21": {
"magHeading": "204", "magHeading": "204",
"Heading": "214", "Heading": "214",
"ILS": "110.30" "ILS": "110.30"
} }
}, },
{ {
"03": { "03": {
"magHeading": "25", "magHeading": "25",
"Heading": "34", "Heading": "34",
"ILS": "" "ILS": ""
} }
} }
], ],
"length": "7432" "length": "7432"
} }
], ],
"TACAN": "", "TACAN": "",
"ICAO": "ESNQ", "ICAO": "ESNQ",
"elevation": "1434" "elevation": "1434"
} }
} }
} }