@atmosx/event-product-parser 2.0.16 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -237
- package/dist/cjs/index.cjs +2233 -3105
- package/dist/esm/index.mjs +2233 -3108
- package/package.json +3 -2
- package/src/@building/building.clean.ts +30 -0
- package/src/@building/building.create.ts +42 -0
- package/src/@building/building.enhance.ts +56 -0
- package/src/@building/building.geometry.ts +42 -0
- package/src/@building/building.headers.ts +37 -0
- package/src/@building/building.office.ts +43 -0
- package/src/@building/building.polygon.ts +71 -0
- package/src/@building/building.properties.ts +89 -0
- package/src/@building/building.signature.ts +78 -0
- package/src/@building/building.tags.ts +24 -0
- package/src/@building/building.tracking.ts +68 -0
- package/src/@building/building.validate.ts +132 -0
- package/src/@core/core.callback.ts +39 -0
- package/src/@core/core.getEvents.ts +25 -0
- package/src/@core/core.getNodes.ts +25 -0
- package/src/@core/core.listener.ts +24 -0
- package/src/@core/core.setNode.ts +81 -0
- package/src/@core/core.start.ts +54 -0
- package/src/@core/core.stop.ts +32 -0
- package/src/@dictionaries/dictionaries.betterEventNames.ts +85 -0
- package/src/@dictionaries/dictionaries.eventActions.ts +28 -0
- package/src/@dictionaries/{awips.ts → dictionaries.eventAwipAbreviations.ts} +12 -6
- package/src/@dictionaries/dictionaries.eventCancelMessages.ts +29 -0
- package/src/@dictionaries/dictionaries.eventCauses.ts +36 -0
- package/src/@dictionaries/dictionaries.eventProducts.ts +25 -0
- package/src/@dictionaries/dictionaries.eventRecords.ts +25 -0
- package/src/@dictionaries/dictionaries.eventSeverity.ts +27 -0
- package/src/@dictionaries/dictionaries.eventStatus.ts +31 -0
- package/src/@dictionaries/{signatures.ts → dictionaries.eventTags.ts} +13 -68
- package/src/@dictionaries/dictionaries.eventTypes.ts +82 -0
- package/src/@dictionaries/dictionaries.eventsOffshore.ts +31 -0
- package/src/@dictionaries/dictionaries.hailStrings.ts +31 -0
- package/src/@dictionaries/{icao.ts → dictionaries.officeICAOs.ts} +13 -6
- package/src/@dictionaries/dictionaries.regExp.ts +28 -0
- package/src/@dictionaries/dictionaries.shapefileLinks.ts +36 -0
- package/src/@dictionaries/dictionaries.statusCorrelationText.ts +40 -0
- package/src/@dictionaries/dictionaries.test_signatures.ts +23 -0
- package/src/@dictionaries/dictionaries.transcribedMessageReplacements.ts +68 -0
- package/src/@events/events.api.ts +113 -0
- package/src/@events/events.text.ts +79 -0
- package/src/@events/events.ugc.ts +83 -0
- package/src/@events/events.vtec.ts +87 -0
- package/src/@manager/manager.mkEvent.ts +79 -0
- package/src/@manager/manager.rmEvent.ts +44 -0
- package/src/@manager/manager.setHash.ts +37 -0
- package/src/@manager/manager.updateNodes.ts +51 -0
- package/src/@modules/@database/database.cache.ts +48 -0
- package/src/@modules/@database/database.init.ts +45 -0
- package/src/@modules/@database/database.shapefiles.ts +97 -0
- package/src/@modules/@database/database.stanza.ts +47 -0
- package/src/@modules/@stanza/stanza.getAwipsType.ts +46 -0
- package/src/@modules/@stanza/stanza.validate.ts +50 -0
- package/src/@modules/@utilities/utilities.createHttp.ts +75 -0
- package/src/@modules/@utilities/utilities.getFormattedTime.ts +43 -0
- package/src/@modules/@utilities/utilities.getSettings.ts +25 -0
- package/src/@modules/@utilities/utilities.getShapeNearestPoint.ts +114 -0
- package/src/@modules/@utilities/utilities.setCronSchedule.ts +38 -0
- package/src/@modules/@utilities/utilities.setEventEmit.ts +41 -0
- package/src/@modules/@utilities/utilities.setListener.ts +30 -0
- package/src/@modules/@utilities/utilities.setSettings.ts +42 -0
- package/src/@modules/@utilities/utilities.setSleep.ts +33 -0
- package/src/@modules/@utilities/utilities.setTimeoutAction.ts +59 -0
- package/src/@modules/@utilities/utilities.setWarning.ts +34 -0
- package/src/@modules/@xmpp/xmpp.xDeploy.ts +58 -0
- package/src/@modules/@xmpp/xmpp.xError.ts +38 -0
- package/src/@modules/@xmpp/xmpp.xOffline.ts +38 -0
- package/src/@modules/@xmpp/xmpp.xOnline.ts +61 -0
- package/src/@modules/@xmpp/xmpp.xReconnect.ts +59 -0
- package/src/@modules/@xmpp/xmpp.xStanza.ts +63 -0
- package/src/@parsers/@hvtec/hvtec.extract.ts +40 -0
- package/src/@parsers/@pvtec/pvtec.expires.ts +26 -0
- package/src/@parsers/@pvtec/pvtec.extract.ts +50 -0
- package/src/@parsers/@text/text.getDescriptionFromProduct.ts +53 -0
- package/src/@parsers/@text/text.getPolygonFromProduct.ts +32 -0
- package/src/@parsers/@text/text.getTextFromProduct.ts +43 -0
- package/src/@parsers/@text/text.getXML.ts +61 -0
- package/src/@parsers/@ugc/ugc.coordinates.ts +110 -0
- package/src/@parsers/@ugc/ugc.expiry.ts +32 -0
- package/src/@parsers/@ugc/ugc.extract.ts +37 -0
- package/src/@parsers/@ugc/ugc.header.ts +30 -0
- package/src/@parsers/@ugc/ugc.locations.ts +29 -0
- package/src/@parsers/@ugc/ugc.zones.ts +52 -0
- package/src/@types/type.event.ts +67 -0
- package/src/@types/type.properties.ts +75 -0
- package/src/@types/types.attributes.ts +28 -0
- package/src/@types/types.compiled.ts +35 -0
- package/src/@types/types.hash.ts +24 -0
- package/src/@types/types.hvtec.ts +25 -0
- package/src/@types/types.pvtec.ts +29 -0
- package/src/@types/types.settings.ts +71 -0
- package/src/@types/types.stanza.ts +37 -0
- package/src/@types/types.ugc.ts +24 -0
- package/src/bootstrap.ts +82 -163
- package/src/index.ts +48 -216
- package/test.js +65 -49
- package/src/@dictionaries/events.ts +0 -168
- package/src/@parsers/@events/api.ts +0 -146
- package/src/@parsers/@events/cap.ts +0 -123
- package/src/@parsers/@events/text.ts +0 -104
- package/src/@parsers/@events/ugc.ts +0 -107
- package/src/@parsers/@events/vtec.ts +0 -76
- package/src/@parsers/events.ts +0 -392
- package/src/@parsers/hvtec.ts +0 -46
- package/src/@parsers/pvtec.ts +0 -72
- package/src/@parsers/stanza.ts +0 -97
- package/src/@parsers/text.ts +0 -165
- package/src/@parsers/ugc.ts +0 -247
- package/src/@submodules/database.ts +0 -201
- package/src/@submodules/eas.ts +0 -490
- package/src/@submodules/utils.ts +0 -191
- package/src/@submodules/xmpp.ts +0 -142
- package/src/types.ts +0 -259
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { regExp } from "../../@dictionaries/dictionaries.regExp";
|
|
21
|
+
|
|
22
|
+
interface GetDescriptionFromProductOptions {
|
|
23
|
+
message: string
|
|
24
|
+
handle?: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const getDescriptionFromProduct = (options: GetDescriptionFromProductOptions): string => {
|
|
28
|
+
let message = options.message;
|
|
29
|
+
const dates = Array.from(message.matchAll(regExp.dateline));
|
|
30
|
+
if (dates.length) {
|
|
31
|
+
const lastMatch = dates[dates.length - 1][0];
|
|
32
|
+
const sIndx = message.lastIndexOf(lastMatch);
|
|
33
|
+
if (sIndx !== -1) {
|
|
34
|
+
const endIndx = message.indexOf('&&', sIndx);
|
|
35
|
+
message = message.substring(sIndx + lastMatch.length, endIndx !== -1 ? endIndx : undefined).trimStart();
|
|
36
|
+
if (message.startsWith('/')) message = message.slice(1).trimStart();
|
|
37
|
+
if (options.handle && message.includes(options.handle)) {
|
|
38
|
+
const handleIdx = message.indexOf(options.handle);
|
|
39
|
+
message = message.substring(handleIdx + options.handle.length).trimStart();
|
|
40
|
+
if (message.startsWith('/')) message = message.slice(1).trimStart();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
} else if (options.handle) {
|
|
44
|
+
const handleIndx = message.indexOf(options.handle);
|
|
45
|
+
if (handleIndx !== -1) {
|
|
46
|
+
let afterHandle = message.substring(handleIndx + options.handle.length).trimStart();
|
|
47
|
+
if (afterHandle.startsWith('/')) afterHandle = afterHandle.slice(1).trimStart();
|
|
48
|
+
const latEnd = afterHandle.indexOf('&&')
|
|
49
|
+
message = latEnd !== -1 ? afterHandle.substring(0, latEnd).trim() : afterHandle.trim();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return message.trim();
|
|
53
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export const getPolygonFromProduct = (message: string): number[][] => {
|
|
21
|
+
const coordinates: [number, number][] = [];
|
|
22
|
+
const match = message.match(/LAT\.{3}LON\s+([\d\s]+)/i);
|
|
23
|
+
if (!match || !match[1]) return coordinates;
|
|
24
|
+
const coordStrings = match[1].replace(/\n/g, ' ').trim().split(/\s+/);
|
|
25
|
+
for (let i = 0; i < coordStrings.length - 1; i += 2) {
|
|
26
|
+
const lat = parseFloat(coordStrings[i]) / 100;
|
|
27
|
+
const lon = -parseFloat(coordStrings[i + 1]) / 100;
|
|
28
|
+
if (!isNaN(lat) && !isNaN(lon)) { coordinates.push([lon, lat]); }
|
|
29
|
+
}
|
|
30
|
+
if (coordinates.length > 2) { coordinates.push(coordinates[0]); }
|
|
31
|
+
return coordinates;
|
|
32
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
interface GetTextFromProductOptions {
|
|
21
|
+
message: string
|
|
22
|
+
find: string[]
|
|
23
|
+
append?: string
|
|
24
|
+
removal?: string[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const getTextFromProduct = (options: GetTextFromProductOptions): string => {
|
|
28
|
+
const lines = options.message.split(`\n`);
|
|
29
|
+
for (const line of lines) {
|
|
30
|
+
const matchedFind = options.find.find((find) => line.includes(find));
|
|
31
|
+
if (matchedFind) {
|
|
32
|
+
let result = line.slice(line.indexOf(matchedFind) + matchedFind.length).trim();
|
|
33
|
+
if (options.removal) {
|
|
34
|
+
for (const str of options.removal) {
|
|
35
|
+
result = result.toLowerCase().split(str.toLowerCase()).join('');
|
|
36
|
+
}
|
|
37
|
+
result = result.replace(matchedFind, '').replace('<', '').trim();
|
|
38
|
+
}
|
|
39
|
+
return result.toUpperCase() + (options?.append ?? ``);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
interface GetXMLOptions {
|
|
21
|
+
message: string
|
|
22
|
+
targets: string[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const getXML = (options: GetXMLOptions): Record<string, string> => {
|
|
26
|
+
const extracted: Record<string, any> = {};
|
|
27
|
+
const findValueByKey = (obj: any, searchKey: string) => {
|
|
28
|
+
const results = [];
|
|
29
|
+
if (obj === null || typeof obj !== 'object') {
|
|
30
|
+
return results;
|
|
31
|
+
}
|
|
32
|
+
const searchKeyLower = searchKey.toLowerCase();
|
|
33
|
+
for (const key in obj) {
|
|
34
|
+
if (obj.hasOwnProperty(key) && key.toLowerCase() === searchKeyLower) {
|
|
35
|
+
results.push(obj[key]);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (Array.isArray(obj)) {
|
|
39
|
+
for (const item of obj) {
|
|
40
|
+
if (item.valueName && item.valueName.toLowerCase() === searchKeyLower && item.value !== undefined) {
|
|
41
|
+
results.push(item.value);
|
|
42
|
+
}
|
|
43
|
+
const nestedResults = findValueByKey(item, searchKey);
|
|
44
|
+
results.push(...nestedResults);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
for (const key in obj) {
|
|
48
|
+
if (obj.hasOwnProperty(key)) {
|
|
49
|
+
const nestedResults = findValueByKey(obj[key], searchKey);
|
|
50
|
+
results.push(...nestedResults);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return results;
|
|
54
|
+
};
|
|
55
|
+
for (const key of options.targets) {
|
|
56
|
+
const values = findValueByKey(options.message, key);
|
|
57
|
+
const uniqueValues = [...new Set(values)];
|
|
58
|
+
extracted[key] = uniqueValues.length === 0 ? null : (uniqueValues.length === 1 ? uniqueValues[0] : uniqueValues);
|
|
59
|
+
}
|
|
60
|
+
return extracted;
|
|
61
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
import { union } from "polygon-clipping";
|
|
20
|
+
import { bootstrap } from "../../bootstrap";
|
|
21
|
+
|
|
22
|
+
interface CoordinatesOptions {
|
|
23
|
+
zones: string[]
|
|
24
|
+
isUnion: boolean
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface CoordinatesResponse {
|
|
28
|
+
type: `Polygon` | `MultiPolygon`
|
|
29
|
+
coordinates: any[]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const getZonePolygon = (options: CoordinatesOptions): CoordinatesResponse | null => {
|
|
33
|
+
const list = [...new Set(options.zones.map(z => z.trim()))].filter(z => z === 'XX000' ? false : true);
|
|
34
|
+
if (list.length === 0) return null;
|
|
35
|
+
|
|
36
|
+
const placeholders = list.map(() => "?").join(",");
|
|
37
|
+
const rows = bootstrap.database
|
|
38
|
+
.prepare(`SELECT geometry FROM shapefiles WHERE id IN (${placeholders})`)
|
|
39
|
+
.all(...list);
|
|
40
|
+
const polygons: any[] = [];
|
|
41
|
+
for (const row of rows) {
|
|
42
|
+
if (!row?.geometry) continue;
|
|
43
|
+
const geom = JSON.parse(row.geometry);
|
|
44
|
+
if (geom?.type === "Polygon") {
|
|
45
|
+
polygons.push(geom.coordinates);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (polygons.length === 0) return null;
|
|
50
|
+
|
|
51
|
+
if (options.isUnion) {
|
|
52
|
+
const unionFn = union as (...polys: any[]) => any;
|
|
53
|
+
const mergedCoords = unionFn(...polygons);
|
|
54
|
+
if (!mergedCoords || mergedCoords.length === 0) return null;
|
|
55
|
+
let maxArea = -1;
|
|
56
|
+
let bestPoly: any[] = [];
|
|
57
|
+
for (const poly of mergedCoords) {
|
|
58
|
+
const outerRing = poly[0];
|
|
59
|
+
let area = 0;
|
|
60
|
+
for (let i = 0; i < outerRing.length - 1; i++) {
|
|
61
|
+
const [x1, y1] = outerRing[i];
|
|
62
|
+
const [x2, y2] = outerRing[i + 1];
|
|
63
|
+
area += x1 * y2 - x2 * y1;
|
|
64
|
+
}
|
|
65
|
+
area = Math.abs(area / 2);
|
|
66
|
+
if (area > maxArea) {
|
|
67
|
+
maxArea = area;
|
|
68
|
+
bestPoly = poly;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (!bestPoly || bestPoly.length === 0) return null;
|
|
72
|
+
const outerRing = bestPoly[0];
|
|
73
|
+
const skip = Math.max(1, parseInt(String(bootstrap.settings.GlobalSettings.ShapefileSkipPoints), 10) || 1);
|
|
74
|
+
let skipped = outerRing.filter((_: any, idx: number) => idx % skip === 0);
|
|
75
|
+
if (skipped.length < 4) {
|
|
76
|
+
skipped = outerRing.slice();
|
|
77
|
+
}
|
|
78
|
+
const first = skipped[0];
|
|
79
|
+
const last = skipped[skipped.length - 1];
|
|
80
|
+
if (!first || !last || first[0] !== last[0] || first[1] !== last[1]) {
|
|
81
|
+
skipped.push([first[0], first[1]]);
|
|
82
|
+
}
|
|
83
|
+
return {type: "Polygon", coordinates: [skipped]};
|
|
84
|
+
} else {
|
|
85
|
+
const multi: any[] = [];
|
|
86
|
+
for (const polyCoords of polygons) {
|
|
87
|
+
if (Array.isArray(polyCoords) && Array.isArray(polyCoords[0])) {
|
|
88
|
+
multi.push(polyCoords);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (multi.length === 0) return null;
|
|
92
|
+
const skip = Math.max(1, parseInt(String(bootstrap.settings.GlobalSettings.ShapefileSkipPoints), 10) || 1);
|
|
93
|
+
if (skip > 1) {
|
|
94
|
+
for (let p = 0; p < multi.length; p++) {
|
|
95
|
+
for (let r = 0; r < multi[p].length; r++) {
|
|
96
|
+
const ring = multi[p][r];
|
|
97
|
+
let reduced = ring.filter((_: any, i: number) => i % skip === 0);
|
|
98
|
+
if (reduced.length < 4) reduced = ring.slice();
|
|
99
|
+
const first = reduced[0];
|
|
100
|
+
const last = reduced[reduced.length - 1];
|
|
101
|
+
if ( first && last && (first[0] !== last[0] || first[1] !== last[1])) {
|
|
102
|
+
reduced.push([first[0], first[1]]);
|
|
103
|
+
}
|
|
104
|
+
multi[p][r] = reduced;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return {type: "MultiPolygon", coordinates: multi};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export const getExpiry = (message: string): string | null => {
|
|
21
|
+
const match = message.match(/\b(\d{6})-/);
|
|
22
|
+
if (!match) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const date = match?.[1];
|
|
26
|
+
const day = parseInt(date?.slice(0, 2), 10);
|
|
27
|
+
const hour = parseInt(date?.slice(2, 4), 10);
|
|
28
|
+
const minute = parseInt(date?.slice(4, 6), 10);
|
|
29
|
+
const now = new Date();
|
|
30
|
+
const expires = new Date(Date.UTC(now.getUTCFullYear(),now.getUTCMonth(),day,hour,minute));
|
|
31
|
+
return expires.toISOString();
|
|
32
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { TypeUGC } from "../../@types/types.ugc";
|
|
21
|
+
import { getUGCHeader } from "./ugc.header"
|
|
22
|
+
import { getZones } from "./ugc.zones";
|
|
23
|
+
import { getExpiry } from './ugc.expiry';
|
|
24
|
+
import { getLocations } from "./ugc.locations";
|
|
25
|
+
|
|
26
|
+
export const ugcExtract = async (message: string): Promise<TypeUGC> => {
|
|
27
|
+
const head = getUGCHeader(message);
|
|
28
|
+
const ugcs = getZones(head)
|
|
29
|
+
const expires = getExpiry(message)
|
|
30
|
+
const areas = await getLocations(ugcs)
|
|
31
|
+
if (!head || ugcs?.length == 0) return;
|
|
32
|
+
return {
|
|
33
|
+
zones: ugcs,
|
|
34
|
+
locations: areas,
|
|
35
|
+
expires: expires
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { regExp } from "../../@dictionaries/dictionaries.regExp"
|
|
21
|
+
|
|
22
|
+
export const getUGCHeader = (message: string): string | null => {
|
|
23
|
+
const start = message.search(regExp.ugc1)
|
|
24
|
+
const sub = message.substring(start)
|
|
25
|
+
const end = sub.search(regExp.ugc2)
|
|
26
|
+
const fin = sub.substring(0, end)
|
|
27
|
+
.replace(/\s+/g, '')
|
|
28
|
+
.slice(0, -1);
|
|
29
|
+
return fin ?? null
|
|
30
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { bootstrap } from "../../bootstrap";
|
|
21
|
+
|
|
22
|
+
export const getLocations = async (zones: string[]): Promise<string[]> => {
|
|
23
|
+
const sites = Array.from(new Set(zones));
|
|
24
|
+
const placeholders = sites.map(() => '?').join(',');
|
|
25
|
+
const rows = await bootstrap.database
|
|
26
|
+
.prepare(`SELECT id, location FROM shapefiles WHERE id IN (${placeholders})`)
|
|
27
|
+
.all(...sites)
|
|
28
|
+
return rows.map((row: any) => row.location).sort();
|
|
29
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export const getZones = (header: string): string[] => {
|
|
21
|
+
const splits = header.split('-');
|
|
22
|
+
const zones: string[] = [];
|
|
23
|
+
let state = splits[0].substring(0, 2);
|
|
24
|
+
const format = splits[0].substring(2, 3);
|
|
25
|
+
for (const part of splits) {
|
|
26
|
+
if (/^[A-Z]/.test(part)) {
|
|
27
|
+
state = part.substring(0, 2);
|
|
28
|
+
if (part.includes('>')) {
|
|
29
|
+
const [start, end] = part.split('>');
|
|
30
|
+
const startNum = parseInt(start.substring(3), 10);
|
|
31
|
+
const endNum = parseInt(end, 10);
|
|
32
|
+
for (let j = startNum; j <= endNum; j++) {
|
|
33
|
+
zones.push(`${state}${format}${j.toString().padStart(3, '0')}`);
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
zones.push(part);
|
|
37
|
+
}
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (part.includes('>')) {
|
|
41
|
+
const [start, end] = part.split('>');
|
|
42
|
+
const startNum = parseInt(start, 10);
|
|
43
|
+
const endNum = parseInt(end, 10);
|
|
44
|
+
for (let j = startNum; j <= endNum; j++) {
|
|
45
|
+
zones.push(`${state}${format}${j.toString().padStart(3, '0')}`);
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
zones.push(`${state}${format}${part}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return zones.filter(item => item !== '');
|
|
52
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { TypeEventProperties as BaseTypeEventProperties } from "./type.properties";
|
|
21
|
+
import { TypeHVTEC } from "../@types/types.hvtec";
|
|
22
|
+
|
|
23
|
+
export type TypeEvent = {
|
|
24
|
+
type: string
|
|
25
|
+
geometry: {
|
|
26
|
+
type: string
|
|
27
|
+
coordinates: number[][]
|
|
28
|
+
}
|
|
29
|
+
properties: {
|
|
30
|
+
event: string
|
|
31
|
+
parent: string
|
|
32
|
+
status: string
|
|
33
|
+
issued: string
|
|
34
|
+
expires: string
|
|
35
|
+
status_metadata?: {
|
|
36
|
+
is_issued?: boolean
|
|
37
|
+
is_updated?: boolean
|
|
38
|
+
is_expired?: boolean
|
|
39
|
+
is_test?: boolean
|
|
40
|
+
}
|
|
41
|
+
metadata: {
|
|
42
|
+
ms: number
|
|
43
|
+
source: string
|
|
44
|
+
tracking: string
|
|
45
|
+
hash?: string
|
|
46
|
+
header: string
|
|
47
|
+
vtec: string
|
|
48
|
+
hvtec: TypeHVTEC[]
|
|
49
|
+
nodes?: {
|
|
50
|
+
updated: number
|
|
51
|
+
node: {
|
|
52
|
+
id?: string | number
|
|
53
|
+
coordinates: [number, number]
|
|
54
|
+
nearest: [number, number]
|
|
55
|
+
miles: number | null
|
|
56
|
+
kilometers: number | null
|
|
57
|
+
proximity: boolean
|
|
58
|
+
}[]
|
|
59
|
+
}
|
|
60
|
+
history: {
|
|
61
|
+
description: string
|
|
62
|
+
issued: string
|
|
63
|
+
status: string
|
|
64
|
+
}[]
|
|
65
|
+
}
|
|
66
|
+
} & BaseTypeEventProperties
|
|
67
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { TypeAttributes } from "./types.attributes";
|
|
21
|
+
|
|
22
|
+
export type TypeEventProperties = {
|
|
23
|
+
locations: string
|
|
24
|
+
description: string
|
|
25
|
+
attributes: TypeAttributes
|
|
26
|
+
geocode: {
|
|
27
|
+
office: {
|
|
28
|
+
name: string
|
|
29
|
+
office: string
|
|
30
|
+
}
|
|
31
|
+
organization: string
|
|
32
|
+
ugc: string[]
|
|
33
|
+
polygon: string
|
|
34
|
+
polygon_generated: boolean
|
|
35
|
+
}
|
|
36
|
+
parameters: {
|
|
37
|
+
tags: string[]
|
|
38
|
+
instructions: string
|
|
39
|
+
source: string
|
|
40
|
+
hazards: string
|
|
41
|
+
impacts: string
|
|
42
|
+
estimated_hail_size: string
|
|
43
|
+
estimated_wind_gusts: string
|
|
44
|
+
damage_threat: string
|
|
45
|
+
tornado_threat: string
|
|
46
|
+
flood_threat: string
|
|
47
|
+
wind_threat: string
|
|
48
|
+
hail_threat: string
|
|
49
|
+
max_hail_inches?: string
|
|
50
|
+
max_wind_gusts_surface_knots?: string
|
|
51
|
+
max_tops_x100feet?: string
|
|
52
|
+
mean_storm_motion_vector?: string
|
|
53
|
+
particularly_dangerous_situation?: string
|
|
54
|
+
}
|
|
55
|
+
watch_parameters?: {
|
|
56
|
+
watch_number: string
|
|
57
|
+
watch_type: string
|
|
58
|
+
additional_tornadoes_probability: string
|
|
59
|
+
strong_tornadoes_probability: string
|
|
60
|
+
severe_wind_probability: string
|
|
61
|
+
severe_hail_probability: string
|
|
62
|
+
hail_2in_probability: string
|
|
63
|
+
combined_hail_wind_probability: string
|
|
64
|
+
max_hail_in: string
|
|
65
|
+
max_wind_surface: string
|
|
66
|
+
max_tops_x100feet: string
|
|
67
|
+
pds_watch: boolean
|
|
68
|
+
}
|
|
69
|
+
spc_parameters: {
|
|
70
|
+
spc_max_tornado: string
|
|
71
|
+
spc_max_hail: string
|
|
72
|
+
spc_max_wind: string
|
|
73
|
+
spc_watch_issuance: string
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
export type TypeAttributes = {
|
|
22
|
+
xmlns: string
|
|
23
|
+
id: string
|
|
24
|
+
issue: string
|
|
25
|
+
ttaaii: string
|
|
26
|
+
cccc: string
|
|
27
|
+
awipsid: string
|
|
28
|
+
}
|