From 2ae6d7307f1f00c30542b1f782dc904d06f1c219 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 20 Feb 2024 18:15:25 -0800 Subject: [PATCH 1/4] #504 ShadeTool - User settable AzElRange --- private/api/spice/ll2aerll.py | 65 ++++++--- python-requirements.txt | 3 +- scripts/server.js | 9 ++ src/essence/Tools/Shade/ShadeTool.css | 25 +++- src/essence/Tools/Shade/ShadeTool.js | 195 ++++++++++++++++++++++++-- 5 files changed, 259 insertions(+), 38 deletions(-) diff --git a/private/api/spice/ll2aerll.py b/private/api/spice/ll2aerll.py index c1aae4ea..73584d3b 100644 --- a/private/api/spice/ll2aerll.py +++ b/private/api/spice/ll2aerll.py @@ -9,7 +9,9 @@ import os import math +import numpy as np import spiceypy +import pymap3d as pm from great_circle_calculator.great_circle_calculator import distance_between_points @@ -21,7 +23,7 @@ except ImportError: from urllib import unquote -def ll2aerll(lng, lat, height, target, time, includeSunEarth): +def ll2aerll(lng, lat, height, target, time, includeSunEarth, isCustom, customAz, customEl, customRange): # Load kernels package_dir = os.path.dirname(os.path.abspath(__file__)).replace('\\','/') @@ -56,40 +58,53 @@ def ll2aerll(lng, lat, height, target, time, includeSunEarth): rP = radii[2] flattening = (rE - rP) / rE - obspos = spiceypy.georec( lng * spiceypy.rpd(), lat * spiceypy.rpd(), height / 1000, radii[0], flattening) - output = spiceypy.azlcpo( method, target, et, abcorr, azccw, elplsz, obspos, obsctr, obsref) - - razel = output[0] - - az_output = razel[1] * spiceypy.dpr() - el_output = razel[2] * spiceypy.dpr() - range_output = razel[0] + if isCustom == 'true': + az_output = float(customAz) + el_output = float(customEl) + range_output = float(customRange) + razel = [customRange, az_output * spiceypy.rpd(), el_output * spiceypy.rpd()] + else: + obspos = spiceypy.georec( lng * spiceypy.rpd(), lat * spiceypy.rpd(), height / 1000, radii[0], flattening) + output = spiceypy.azlcpo( method, target, et, abcorr, azccw, elplsz, obspos, obsctr, obsref) + + razel = output[0] + + az_output = razel[1] * spiceypy.dpr() + el_output = razel[2] * spiceypy.dpr() + range_output = razel[0] sun_az_output = None sun_el_output = None earth_az_output = None earth_el_output = None if includeSunEarth == 'true': - target = 'SUN' + targetSE = 'SUN' sun_obspos = spiceypy.georec( lng * spiceypy.rpd(), lat * spiceypy.rpd(), height / 1000, radii[0], flattening) - sun_output = spiceypy.azlcpo( method, target, et, abcorr, azccw, elplsz, sun_obspos, obsctr, obsref) + sun_output = spiceypy.azlcpo( method, targetSE, et, abcorr, azccw, elplsz, sun_obspos, obsctr, obsref) sun_razel = sun_output[0] sun_az_output = sun_razel[1] * spiceypy.dpr() sun_el_output = sun_razel[2] * spiceypy.dpr() - target = 'EARTH' + targetSE = 'EARTH' earth_obspos = spiceypy.georec( lng * spiceypy.rpd(), lat * spiceypy.rpd(), height / 1000, radii[0], flattening) - earth_output = spiceypy.azlcpo( method, target, et, abcorr, azccw, elplsz, earth_obspos, obsctr, obsref) + earth_output = spiceypy.azlcpo( method, targetSE, et, abcorr, azccw, elplsz, earth_obspos, obsctr, obsref) earth_razel = earth_output[0] earth_az_output = earth_razel[1] * spiceypy.dpr() earth_el_output = earth_razel[2] * spiceypy.dpr() - - state, light = spiceypy.spkezr(target, et, "IAU_MARS", abcorr, "MARS") - ll = spiceypy.recgeo( state[0:3], radii[0], flattening) - target_lng = ll[0] * spiceypy.dpr() - target_lat = ll[1] * spiceypy.dpr() - target_alt = ll[2] + if isCustom == 'true': + target_lat, target_lng, target_alt = pm.aer2geodetic(az_output, el_output, range_output * 1000, + lat, + lng, + height, + ell=pm.Ellipsoid(radii[0] * 1000, radii[1] * 1000, radii[2] * 1000), deg=True) + target_alt = target_alt / 1000 + else: + state, light = spiceypy.spkezr(target, et, "IAU_MARS", abcorr, "MARS") + ll = spiceypy.recgeo( state[0:3], radii[0], flattening) + target_lng = ll[0] * spiceypy.dpr() + target_lat = ll[1] * spiceypy.dpr() + target_alt = ll[2] # Unload kernels for k in kernels_to_load: @@ -122,8 +137,18 @@ def ll2aerll(lng, lat, height, target, time, includeSunEarth): target = unquote(sys.argv[4]) time = unquote(sys.argv[5]) includeSunEarth = sys.argv[6] +isCustom = False +customAz = 0 +customEl = 0 +customRange = 0 +if len(sys.argv) > 7: + isCustom = sys.argv[7] +if isCustom == 'true': + customAz = float(sys.argv[8]) + customEl = float(sys.argv[9]) + customRange = float(sys.argv[10]) try: - print(ll2aerll(lng, lat, height, target, time, includeSunEarth)) + print(ll2aerll(lng, lat, height, target, time, includeSunEarth, isCustom, customAz, customEl, customRange)) except: print(json.dumps({"error": True, "message": 'Error: ' + str(sys.exc_info()[0])})) diff --git a/python-requirements.txt b/python-requirements.txt index 387feb8b..247ed0cf 100644 --- a/python-requirements.txt +++ b/python-requirements.txt @@ -1,2 +1,3 @@ numpy==1.21.6 -spiceypy==5.1.2 \ No newline at end of file +spiceypy==5.1.2 +pymap3d==3.0.1 \ No newline at end of file diff --git a/scripts/server.js b/scripts/server.js index 5bbe40c2..79c6131c 100644 --- a/scripts/server.js +++ b/scripts/server.js @@ -710,6 +710,11 @@ setups.getBackendSetups(function (setups) { const includeSunEarth = encodeURIComponent(req.body.includeSunEarth) || "False"; + const isCustom = encodeURIComponent(req.body.isCustom) || "False"; + const customAz = encodeURIComponent(req.body.customAz); + const customEl = encodeURIComponent(req.body.customEl); + const customRange = encodeURIComponent(req.body.customRange); + execFile( "python", [ @@ -720,6 +725,10 @@ setups.getBackendSetups(function (setups) { target, time, includeSunEarth, + isCustom, + customAz, + customEl, + customRange, ], function (error, stdout, stderr) { if (error) diff --git a/src/essence/Tools/Shade/ShadeTool.css b/src/essence/Tools/Shade/ShadeTool.css index bf68c3b2..77973c08 100644 --- a/src/essence/Tools/Shade/ShadeTool.css +++ b/src/essence/Tools/Shade/ShadeTool.css @@ -147,7 +147,12 @@ padding-left: 15px; border-bottom: 1px solid var(--color-a1-5); } -#shadeTool #vstShades > li > .vstShadeContents > div > div:not(.vstRegen):first-child { +#shadeTool + #vstShades + > li + > .vstShadeContents + > div + > div:not(.vstRegen):first-child { font-size: 13px; color: var(--color-a5); } @@ -157,7 +162,7 @@ } #shadeTool .vstOptionColor > div:last-child { - width: 111px; + width: 108px; height: 29px; } @@ -313,7 +318,7 @@ background-color: var(--color-a1); color: #ededed; border: none; - width: 111px; + width: 108px; height: 27px; font-size: 14px; padding: 0px 3px; @@ -465,7 +470,7 @@ border-top: 1px solid Transparent; border-bottom: 1px solid Transparent; } -#shadeTool .vstOptionTimeSpecific input:focus { +#shadeTool .vstOptionTimeSpecific input:focus { border-bottom: 1px solid var(--color-mmgis); } #shadeTool .vstOptionData { @@ -508,6 +513,16 @@ #shadeTool #shadeTool_results #shadeTool_results_outputs ul li div:last-child { font-size: 13px; } + +#shadeTool #shadeTool_results input { + width: 120px; + height: 25px; + color: #ededed; + text-align: right; + background: var(--color-e); + border: none; +} + #shadeTool .vstClockIcon { position: absolute; right: 0; @@ -520,4 +535,4 @@ right: 0; padding: 0px 8px; pointer-events: none; -} \ No newline at end of file +} diff --git a/src/essence/Tools/Shade/ShadeTool.js b/src/essence/Tools/Shade/ShadeTool.js index 2d9636b9..818e32a7 100644 --- a/src/essence/Tools/Shade/ShadeTool.js +++ b/src/essence/Tools/Shade/ShadeTool.js @@ -279,24 +279,31 @@ let ShadeTool = { } let allSources = '' + let sourcesList = [ + { + name: 'Custom', + value: false, + }, + ] if ( ShadeTool.vars && ShadeTool.vars.sources && ShadeTool.vars.sources.length > 0 ) { - allSources = ShadeTool.vars.sources - .map( - (c, i) => - "' - ) - .join('\n') + sourcesList = ShadeTool.vars.sources.concat(sourcesList) } + allSources = sourcesList + .map( + (c, i) => + "' + ) + .join('\n') let allObservers = '' if ( @@ -396,14 +403,26 @@ let ShadeTool = { "
  • ", "
    Azimuth
    ", "
    ", + "", "
  • ", "
  • ", "
    Elevation
    ", "
    ", + "", "
  • ", "
  • ", "
    Range
    ", "
    ", + "", "
  • ", "
  • ", "
    Longitude
    ", @@ -596,6 +615,63 @@ let ShadeTool = { $('#vstShades #vstId_' + id + ' .vstRegen').addClass( 'changed' ) + const val = $( + '#vstShades #vstId_' + id + ' .vstOptionTarget select' + ).val() + if (val === 'false') { + $('#shadeTool_results_outputs_az').css({ + display: 'none', + }) + $('#shadeTool_results_outputs_az_input_wrap').css({ + display: 'inherit', + }) + $('#shadeTool_results_outputs_az_input').val( + parseFloat( + $('#shadeTool_results_outputs_az').text() + ) + ) + $('#shadeTool_results_outputs_el').css({ + display: 'none', + }) + $('#shadeTool_results_outputs_el_input_wrap').css({ + display: 'inherit', + }) + $('#shadeTool_results_outputs_el_input').val( + parseFloat( + $('#shadeTool_results_outputs_el').text() + ) + ) + $('#shadeTool_results_outputs_range').css({ + display: 'none', + }) + $('#shadeTool_results_outputs_range_input_wrap').css({ + display: 'inherit', + }) + $('#shadeTool_results_outputs_range_input').val( + parseFloat( + $('#shadeTool_results_outputs_range').text() + ) + ) + } else { + $('#shadeTool_results_outputs_az').css({ + display: 'inherit', + }) + $('#shadeTool_results_outputs_az_input_wrap').css({ + display: 'none', + }) + $('#shadeTool_results_outputs_el').css({ + display: 'inherit', + }) + $('#shadeTool_results_outputs_el_input_wrap').css({ + display: 'none', + }) + $('#shadeTool_results_outputs_range').css({ + display: 'inherit', + }) + $('#shadeTool_results_outputs_range_input_wrap').css({ + display: 'none', + }) + } if ( $( `#vstShades #vstId_${id} .vstOptionResolution select` @@ -607,6 +683,66 @@ let ShadeTool = { } })(id) ) + $('#shadeTool_results_outputs_az_input').on( + 'change', + (function (id) { + return function () { + $('#vstShades #vstId_' + id + ' .vstRegen').addClass( + 'changed' + ) + if ( + $( + '#vstShades #vstId_' + + id + + ' .vstOptionResolution select' + ).val() <= ShadeTool.dynamicUpdateResCutoff + ) { + ShadeTool.setActiveElmId(id) + ShadeTool.setSource() + } + } + })(id) + ) + $('#shadeTool_results_outputs_el_input').on( + 'change', + (function (id) { + return function () { + $('#vstShades #vstId_' + id + ' .vstRegen').addClass( + 'changed' + ) + if ( + $( + '#vstShades #vstId_' + + id + + ' .vstOptionResolution select' + ).val() <= ShadeTool.dynamicUpdateResCutoff + ) { + ShadeTool.setActiveElmId(id) + ShadeTool.setSource() + } + } + })(id) + ) + $('#shadeTool_results_outputs_range_input').on( + 'change', + (function (id) { + return function () { + $('#vstShades #vstId_' + id + ' .vstRegen').addClass( + 'changed' + ) + if ( + $( + '#vstShades #vstId_' + + id + + ' .vstOptionResolution select' + ).val() <= ShadeTool.dynamicUpdateResCutoff + ) { + ShadeTool.setActiveElmId(id) + ShadeTool.setSource() + } + } + })(id) + ) $('#vstShades #vstId_' + id + ' .vstOptionHeight input').on( 'input', (function (id) { @@ -830,6 +966,31 @@ let ShadeTool = { let dataLayer = ShadeTool.vars.data[options.dataIndex] + const isCustom = options.target === 'false' + let customAz, customEl, customRange + if (isCustom) { + customAz = parseFloat( + $('#shadeTool_results_outputs_az_input').val() + ) + customEl = parseFloat( + $('#shadeTool_results_outputs_el_input').val() + ) + customRange = parseFloat( + $('#shadeTool_results_outputs_range_input').val() + ) + if (isNaN(customAz) || isNaN(customEl) || isNaN(customRange)) { + CursorInfo.update( + 'Azimuth, Elevation and Range need to be set when using Custom Az/El source.', + 6000, + true, + { x: 296, y: -5 }, + '#e9ff26', + 'black' + ) + return + } + } + ShadeTool.tags[activeElmId] = activeElmId + 'd' + @@ -849,8 +1010,14 @@ let ShadeTool = { 't' + options.time.replace(/ /g, '_') + if (isCustom) + ShadeTool.tags[ + activeElmId + ] += `A${customAz}E${customEl}R${customRange}` + let demUrl = ShadeTool.vars.dem if (!F_.isUrlAbsolute(demUrl)) demUrl = L_.missionPath + demUrl + calls.api( 'getbands', { @@ -876,6 +1043,10 @@ let ShadeTool = { target: options.target, time: options.time + ' UTC', includeSunEarth: options.includeSunEarth, + isCustom: isCustom, + customAz, + customEl, + customRange, }, function (s) { /* From 3fb476b944f1754f1803ececbb778a7b25800eae Mon Sep 17 00:00:00 2001 From: tariqksoliman Date: Thu, 22 Feb 2024 17:25:11 -0800 Subject: [PATCH 2/4] #504 SPICE kernel scheduled downloads --- .gitignore | 5 + Missions/spice-kernels-conf.example.json | 55 +++++ docs/pages/Setup/ENVs/ENVs.md | 4 + package-lock.json | 78 +++---- package.json | 2 +- private/api/chronice.py | 98 +++++++++ private/api/{spice => }/ll2aerll.py | 69 ++++-- private/api/{spice => }/naif-about.txt | 0 private/api/spice/chronice.py | 71 ------ private/api/spice/chronos | Bin 1631040 -> 0 bytes private/api/spice/chronos.exe | Bin 1516544 -> 0 bytes private/api/spice/chronos.py | 61 ------ .../api/spice/chronosSetups/chronos-msl.setup | 29 --- .../spice/getKernelUtils/get-kernels-mro.bat | 7 - .../spice/getKernelUtils/get-kernels-msl.bat | 10 - .../spice/getKernelUtils/get-kernels-mvn.bat | 7 - .../spice/getKernelUtils/get-kernels-ody.bat | 7 - .../spice/getKernelUtils/get-kernels-tgo.bat | 7 - .../great_circle_calculator/__conversion.py | 28 --- .../great_circle_calculator/__conversion.pyc | Bin 1476 -> 0 bytes .../__error_checking.py | 18 -- .../__error_checking.pyc | Bin 916 -> 0 bytes .../spice/great_circle_calculator/__init__.py | 2 - .../great_circle_calculator/__init__.pyc | Bin 220 -> 0 bytes .../great_circle_calculator/_constants.py | 59 ----- .../great_circle_calculator/_constants.pyc | Bin 2173 -> 0 bytes .../spice/great_circle_calculator/compass.py | 202 ------------------ .../great_circle_calculator.py | 183 ---------------- .../great_circle_calculator.pyc | Bin 7924 -> 0 bytes private/api/spice/lltarg2vistimes.py | 105 --------- sample.env | 5 +- scripts/server.js | 49 ++--- spice/getKernels.js | 155 ++++++++++++++ spice/kernels/.gitkeep | 0 src/essence/Tools/Shade/ShadeTool.css | 5 + src/essence/Tools/Shade/ShadeTool.js | 66 ++++-- src/pre/calls.js | 4 - 37 files changed, 473 insertions(+), 918 deletions(-) create mode 100644 Missions/spice-kernels-conf.example.json create mode 100644 private/api/chronice.py rename private/api/{spice => }/ll2aerll.py (68%) rename private/api/{spice => }/naif-about.txt (100%) delete mode 100644 private/api/spice/chronice.py delete mode 100644 private/api/spice/chronos delete mode 100644 private/api/spice/chronos.exe delete mode 100644 private/api/spice/chronos.py delete mode 100644 private/api/spice/chronosSetups/chronos-msl.setup delete mode 100644 private/api/spice/getKernelUtils/get-kernels-mro.bat delete mode 100644 private/api/spice/getKernelUtils/get-kernels-msl.bat delete mode 100644 private/api/spice/getKernelUtils/get-kernels-mvn.bat delete mode 100644 private/api/spice/getKernelUtils/get-kernels-ody.bat delete mode 100644 private/api/spice/getKernelUtils/get-kernels-tgo.bat delete mode 100644 private/api/spice/great_circle_calculator/__conversion.py delete mode 100644 private/api/spice/great_circle_calculator/__conversion.pyc delete mode 100644 private/api/spice/great_circle_calculator/__error_checking.py delete mode 100644 private/api/spice/great_circle_calculator/__error_checking.pyc delete mode 100644 private/api/spice/great_circle_calculator/__init__.py delete mode 100644 private/api/spice/great_circle_calculator/__init__.pyc delete mode 100644 private/api/spice/great_circle_calculator/_constants.py delete mode 100644 private/api/spice/great_circle_calculator/_constants.pyc delete mode 100644 private/api/spice/great_circle_calculator/compass.py delete mode 100644 private/api/spice/great_circle_calculator/great_circle_calculator.py delete mode 100644 private/api/spice/great_circle_calculator/great_circle_calculator.pyc delete mode 100644 private/api/spice/lltarg2vistimes.py create mode 100644 spice/getKernels.js create mode 100644 spice/kernels/.gitkeep diff --git a/.gitignore b/.gitignore index 3232928b..01f05385 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,11 @@ /config/pre/toolConfigs.json /src/pre/tools.js +/spice/kernels/* +!/spice/kernels/.gitkeep +/Missions/spice-kernels-conf.json +!/Missions/spice-kernels-conf.example.json + /build/* /data/* *__pycache__ diff --git a/Missions/spice-kernels-conf.example.json b/Missions/spice-kernels-conf.example.json new file mode 100644 index 00000000..dbb4bb23 --- /dev/null +++ b/Missions/spice-kernels-conf.example.json @@ -0,0 +1,55 @@ +{ + "body": { + "description": "If the MMGIS ENV 'SPICE_SCHEDULED_KERNEL_DOWNLOAD=true', then at every other midnight, MMGIS will read /Missions/spice-kernels-conf.json and re/download all the specified kernels to /spice/kernels.'body' names and 'target' names must be valid NAIF SPICE names/ids. Meta-kernels (.tm) can also be set for download by using an object instead of a string (see example below).", + "MARS": { + "description": "MARS", + "kernels": [ + "https://naif.jpl.nasa.gov/pub/naif/generic_kernels/lsk/naif0012.tls", + "https://naif.jpl.nasa.gov/pub/naif/generic_kernels/pck/pck00011.tpc", + "https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/de440.bsp", + "https://naif.jpl.nasa.gov/pub/naif/MARS2020/kernels/spk/mar097s.bsp", + "https://naif.jpl.nasa.gov/pub/naif/generic_kernels/pck/mars_iau2000_v1.tpc" + ], + "targets": { + "MRO": { + "description": "MRO - Mars Reconnaissance Orbiter", + "kernels": [ + "https://naif.jpl.nasa.gov/pub/naif/MRO/kernels/spk/mro_psp.bsp" + ] + }, + "MSL": { + "description": "MSL - Mars Science Laboratory", + "kernels": [ + "https://naif.jpl.nasa.gov/pub/naif/MSL/kernels/spk/msl_atls_ops120808_v1.bsp", + "https://naif.jpl.nasa.gov/pub/naif/MSL/kernels/spk/msl_ls_ops120808_iau2000_v1.bsp", + "https://naif.jpl.nasa.gov/pub/naif/MSL/kernels/sclk/MSL_76_SCLKSCET.00019.tsc", + "https://naif.jpl.nasa.gov/pub/naif/MSL/kernels/sclk/msl_lmst_ops120808_v1.tsc", + "https://naif.jpl.nasa.gov/pub/naif/MSL/kernels/fk/msl_v08.tf" + ] + }, + "-202": { + "description": "MVN - MAVEN - Mars Atmosphere and Volatile Evolution", + "kernels": [ + "https://naif.jpl.nasa.gov/pub/naif/MAVEN/kernels/spk/maven_orb.bsp" + ] + }, + "-53": { + "description": "ODY - 2001 Mars Odyssey", + "kernels": [ + "https://naif.jpl.nasa.gov/pub/naif/M01/kernels/spk/m01_map.bsp" + ] + }, + "-143": { + "description": "TGO - ExoMars Trace Gas Orbiter", + "kernels": [ + { + "url": "https://naif.jpl.nasa.gov/pub/naif/EXOMARS2016/kernels/mk/em16_ops.tm", + "mkRoot": "https://naif.jpl.nasa.gov/pub/naif/EXOMARS2016/kernels", + "mkRegex": ".*/spk/em16_tgo_fsp.*.bsp" + } + ] + } + } + } + } +} diff --git a/docs/pages/Setup/ENVs/ENVs.md b/docs/pages/Setup/ENVs/ENVs.md index 718997d1..35ba4833 100644 --- a/docs/pages/Setup/ENVs/ENVs.md +++ b/docs/pages/Setup/ENVs/ENVs.md @@ -139,3 +139,7 @@ If true, MMGIS will not auto-login returning users. This can be useful when logi #### `GENERATE_SOURCEMAP=` If true at build-time, JavaScript source maps will also be built | boolean | default `false` + +#### `SPICE_SCHEDULED_KERNEL_DOWNLOAD=` + +If true, then at every other midnight, MMGIS will read /Missions/spice-kernels-conf.json and re/download all the specified kernels. See /Missions/spice-kernels-conf.example.json | boolean | default `false` diff --git a/package-lock.json b/package-lock.json index 550006ab..b32c7d96 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,7 +51,7 @@ "memorystore": "^1.6.2", "nipplejs": "^0.8.5", "node-fetch": "^2.6.1", - "node-schedule": "^1.3.2", + "node-schedule": "^2.1.1", "pg-promise": "^10.6.1", "png-js": "^1.0.0", "proj4": "^2.8.1", @@ -8705,15 +8705,14 @@ } }, "node_modules/cron-parser": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-2.18.0.tgz", - "integrity": "sha512-s4odpheTyydAbTBQepsqd2rNWGa2iV3cyo8g7zbI2QQYGLVsfbhmwukayS1XHppe02Oy1fg7mg6xoaraVJeEcg==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.9.0.tgz", + "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", "dependencies": { - "is-nan": "^1.3.0", - "moment-timezone": "^0.5.31" + "luxon": "^3.2.1" }, "engines": { - "node": ">=0.8" + "node": ">=12.0.0" } }, "node_modules/cross-env": { @@ -14160,21 +14159,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-nan": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", - "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -18114,6 +18098,14 @@ "yallist": "^3.0.2" } }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "engines": { + "node": ">=12" + } + }, "node_modules/lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", @@ -18774,13 +18766,16 @@ "dev": true }, "node_modules/node-schedule": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-1.3.3.tgz", - "integrity": "sha512-uF9Ubn6luOPrcAYKfsXWimcJ1tPFtQ8I85wb4T3NgJQrXazEzojcFZVk46ZlLHby3eEJChgkV/0T689IsXh2Gw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-2.1.1.tgz", + "integrity": "sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==", "dependencies": { - "cron-parser": "^2.18.0", + "cron-parser": "^4.2.0", "long-timeout": "0.1.1", "sorted-array-functions": "^1.3.0" + }, + "engines": { + "node": ">=6" } }, "node_modules/normalize-package-data": { @@ -33484,12 +33479,11 @@ } }, "cron-parser": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-2.18.0.tgz", - "integrity": "sha512-s4odpheTyydAbTBQepsqd2rNWGa2iV3cyo8g7zbI2QQYGLVsfbhmwukayS1XHppe02Oy1fg7mg6xoaraVJeEcg==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.9.0.tgz", + "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", "requires": { - "is-nan": "^1.3.0", - "moment-timezone": "^0.5.31" + "luxon": "^3.2.1" } }, "cross-env": { @@ -37511,15 +37505,6 @@ "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", "dev": true }, - "is-nan": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", - "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - } - }, "is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -40639,6 +40624,11 @@ "yallist": "^3.0.2" } }, + "luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==" + }, "lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", @@ -41152,11 +41142,11 @@ "dev": true }, "node-schedule": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-1.3.3.tgz", - "integrity": "sha512-uF9Ubn6luOPrcAYKfsXWimcJ1tPFtQ8I85wb4T3NgJQrXazEzojcFZVk46ZlLHby3eEJChgkV/0T689IsXh2Gw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-2.1.1.tgz", + "integrity": "sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==", "requires": { - "cron-parser": "^2.18.0", + "cron-parser": "^4.2.0", "long-timeout": "0.1.1", "sorted-array-functions": "^1.3.0" } diff --git a/package.json b/package.json index c693c1d3..42966e54 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "memorystore": "^1.6.2", "nipplejs": "^0.8.5", "node-fetch": "^2.6.1", - "node-schedule": "^1.3.2", + "node-schedule": "^2.1.1", "pg-promise": "^10.6.1", "png-js": "^1.0.0", "proj4": "^2.8.1", diff --git a/private/api/chronice.py b/private/api/chronice.py new file mode 100644 index 00000000..473c791e --- /dev/null +++ b/private/api/chronice.py @@ -0,0 +1,98 @@ +# chronice: chronos + spice (but without chronos since spice-alone offered more controll) +# chronice.py