From 403d238b642e00caf2296c79487bee0ce8c7a906 Mon Sep 17 00:00:00 2001 From: Yuval Rosen Date: Sat, 24 Jun 2023 14:03:44 +0300 Subject: [PATCH] add logging, some settings, security fixes, bug fixes --- Pages/Index.cshtml | 11 +- Pages/Settings.cshtml | 26 ++++- Pages/Shared/_Layout.cshtml | 5 +- R3E.cs | 20 ++-- README.md | 5 +- ReHUD.csproj | 3 +- SharedMemory.cs | 6 +- Startup.cs | 106 ++++++++++++++++-- electron.manifest.json | 2 +- log4net.config | 23 ++++ wwwroot/css/app.css | 4 +- wwwroot/css/settings.css | 49 +++++++- wwwroot/js/index.js | 99 +++++++++++----- wwwroot/js/settings.js | 49 ++++++++ wwwroot/js/utils.js | 96 ++++++++++++++-- wwwroot/lib/agnostic-draggable/LICENSE | 21 ++++ .../dist/agnostic-draggable.min.js | 1 + 17 files changed, 444 insertions(+), 82 deletions(-) create mode 100644 log4net.config create mode 100644 wwwroot/lib/agnostic-draggable/LICENSE create mode 100644 wwwroot/lib/agnostic-draggable/dist/agnostic-draggable.min.js diff --git a/Pages/Index.cshtml b/Pages/Index.cshtml index eb3b4dd..021238e 100644 --- a/Pages/Index.cshtml +++ b/Pages/Index.cshtml @@ -1,19 +1,18 @@ @page @model IndexModel - -@* he = hud-element *@ +@{ + Layout = "~/Pages/Shared/_Layout.cshtml"; +} ReHUD - - - - + +@* he = hud-element *@
diff --git a/Pages/Settings.cshtml b/Pages/Settings.cshtml index ea1c131..d6923fe 100644 --- a/Pages/Settings.cshtml +++ b/Pages/Settings.cshtml @@ -1,21 +1,35 @@ @page @model SettingsModel +@{ + Layout = "~/Pages/Shared/_Layout.cshtml"; +} + ReHUD | Settings + -
+
- - + +
-
+
- - + + +
+ +
+ + +
+ + + diff --git a/Pages/Shared/_Layout.cshtml b/Pages/Shared/_Layout.cshtml index 74d5b98..caf5890 100644 --- a/Pages/Shared/_Layout.cshtml +++ b/Pages/Shared/_Layout.cshtml @@ -1,8 +1,10 @@ - + + + @@ -15,6 +17,7 @@ + @await RenderSectionAsync("Scripts", required: false) diff --git a/R3E.cs b/R3E.cs index c09e31f..09bd9d8 100644 --- a/R3E.cs +++ b/R3E.cs @@ -16,7 +16,7 @@ enum VersionMajor enum VersionMinor { // Minor version number to test against - R3E_VERSION_MINOR = 13 + R3E_VERSION_MINOR = 14 }; enum Session @@ -554,9 +554,8 @@ internal struct DriverInfo public Int32 ClassPerformanceIndex; // Note: See the EngineType enum public Int32 EngineType; - - public Int32 Unused1; - public Int32 Unused2; + public Single CarWidth; + public Single CarLength; } [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -656,14 +655,13 @@ internal struct DriverData // DisqualifyPenaltyIgnoredBlueFlag = 13, // DisqualifyPenaltyMax = 14 public Int32 PenaltyReason; - + // -1 unavailable, 0 = ignition off, 1 = ignition on but not running, 2 = ignition on and running public Int32 EngineState; - // Reserved data - public Int32 Unused1; - public Single Unused2; - public Single Unused3; + // Car body orientation + // Unit: Euler angles + public Vector3 Orientation; } [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -732,7 +730,7 @@ internal struct Shared // If the session is time based, lap based or time based with an extra lap at the end public Int32 SessionLengthFormat; - + // Unit: Meter per second (m/s) public Single SessionPitSpeedLimit; @@ -1051,7 +1049,7 @@ internal struct Shared public Int32 TireTypeRear; // Which subtype of tires the car has // Note: See the R3E.Constant.TireSubtype enum - public Int32 TireSubtypeFront; + public Int32 TireSubtypeFront; public Int32 TireSubtypeRear; // Current brake temperature (-1.0 = N/A) diff --git a/README.md b/README.md index 3ed092a..1d1c108 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,8 @@ I started this project following the recent increase in the number of bugs in Ra - Fuel insights - Input meter - Damage viewer + - Radar - Live on-track relative display* - - Radar* (waiting for some features to be implemented into the shared memory API) - Session status* - Settings window: - Element scale and rearrangement* @@ -55,6 +55,9 @@ To change the position and scale of hud elements, first click on the "Edit" butt --- +## Bug Reporting +Since [v0.3.1-beta](https://github.com/Yuvix25/ReHUD/releases/tag/v0.3.1-beta), the settings window contains a "Show Log File" button. If you encounter a bug/issue, create a [new issue](https://github.com/Yuvix25/ReHUD/issues/new?assignees=Yuvix25&labels=bug&projects=&template=bug_report.md&title=), + ## Contribution Any contribution to the project will be highly appreciated! Feel free to open a new [issue](https://github.com/Yuvix25/ReHUD/issues/new/choose) or [pull request](https://github.com/Yuvix25/ReHUD/compare), and I'll do my best to review them and provide my own feedback. diff --git a/ReHUD.csproj b/ReHUD.csproj index ffec6ff..8d5a519 100644 --- a/ReHUD.csproj +++ b/ReHUD.csproj @@ -1,6 +1,6 @@  - net7.0 + net6.0 enable enable ReHUD @@ -8,6 +8,7 @@ + diff --git a/SharedMemory.cs b/SharedMemory.cs index b7a59fe..84beb0e 100644 --- a/SharedMemory.cs +++ b/SharedMemory.cs @@ -30,7 +30,7 @@ public void Run(SharedMemoryCallback callback) var timeReset = DateTime.UtcNow; var timeLast = timeReset; - Console.WriteLine("Looking for RRRE.exe..."); + ReHUD.Startup.logger.Info("Looking for RRRE.exe..."); while (true) { @@ -48,13 +48,13 @@ public void Run(SharedMemoryCallback callback) if (Utilities.IsRrreRunning() && !Mapped) { if (!found) - Console.WriteLine("Found RRRE.exe, mapping shared memory..."); + ReHUD.Startup.logger.Info("Found RRRE.exe, mapping shared memory..."); found = true; if (Map()) { - Console.WriteLine("Memory mapped successfully"); + ReHUD.Startup.logger.Info("Memory mapped successfully"); timeReset = DateTime.UtcNow; _buffer = new Byte[Marshal.SizeOf(typeof(Shared))]; diff --git a/Startup.cs b/Startup.cs index f390c10..e7eb9b8 100644 --- a/Startup.cs +++ b/Startup.cs @@ -1,11 +1,20 @@ using ElectronNET.API; using ElectronNET.API.Entities; using Newtonsoft.Json; +using log4net; +using log4net.Appender; +using log4net.Repository.Hierarchy; +using log4net.Config; +using System.Reflection; namespace ReHUD; public class Startup { + public static ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod()?.DeclaringType); + FileAppender? rootAppender; + string? logFilePath; + public Startup(IConfiguration configuration) { Configuration = configuration; @@ -22,6 +31,12 @@ public void ConfigureServices(IServiceCollection services) // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly()); + XmlConfigurator.Configure(logRepository, new FileInfo("log4net.config")); + + rootAppender = ((Hierarchy)logRepository).Root.Appenders.OfType().FirstOrDefault(); + logFilePath = rootAppender != null ? rootAppender.File : string.Empty; + if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); @@ -57,6 +72,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) } } + private const string anotherInstanceMessage = "Another instance of ReHUD is already running"; + private const string logFilePathWarning = "Log file path could not be determined. Try searching for a file name 'ReHUD.log' in C:\\Users\\\\AppData\\Local\\Programs\\rehud\\resources\\bin"; private const string userDataFile = "userData.json"; private const string settingsFile = "settings.json"; @@ -75,16 +92,18 @@ private async Task CreateMainWindow(IWebHostEnvironment env) Transparent = true, BackgroundColor = "#00000000", Icon = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "ReHUD.png"), + WebPreferences = new WebPreferences() + { + EnableRemoteModule = true, + NodeIntegration = true, + // ContextIsolation = true, + }, }); bool gotLock = await Electron.App.RequestSingleInstanceLockAsync((args, arg) => { }); if (!gotLock) { - MessageBoxOptions options = new MessageBoxOptions("Another instance of ReHUD is already running."); - options.Type = MessageBoxType.error; - options.Title = "Error"; - - await Electron.Dialog.ShowMessageBoxAsync(window, options); + await ShowMessageBox(window, anotherInstanceMessage, "Error", MessageBoxType.error); Electron.App.Quit(); return; } @@ -95,6 +114,28 @@ private async Task CreateMainWindow(IWebHostEnvironment env) window.SetIgnoreMouseEvents(true); + await Electron.IpcMain.On("log", (args) => + { + Newtonsoft.Json.Linq.JObject obj = (Newtonsoft.Json.Linq.JObject)args; + if (obj == null || obj["level"] == null) + return; + string message = ((string)(obj["message"] ?? "(unknown)")).Trim(); + string level = ((string)obj["level"]).ToUpper(); + + switch (level) { + case "INFO": + logger.Debug(message); + break; + case "WARN": + logger.Info(message); + break; + case "ERROR": + logger.Error(message); + break; + } + }); + + await Electron.IpcMain.On("get-hud-layout", (args) => { SendHudLayout(window); }); @@ -107,7 +148,7 @@ await Electron.IpcMain.On("reset-hud-layout", (args) => { try { SendHudLayout(window, new Dictionary()); } catch (Exception e) { - Console.WriteLine(e); + logger.Error("Error resetting HUD layout", e); } }); @@ -134,6 +175,13 @@ private async Task CreateSettingsWindow(IWebHostEnvironment env) Width = 800, Height = 600, Icon = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "ReHUD.png"), + WebPreferences = new WebPreferences() + { + // ContextIsolation = true, + EnableRemoteModule = true, + NodeIntegration = true, + // Preload = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "js", "utils.js"), + }, }); if (!env.IsDevelopment()) @@ -172,12 +220,54 @@ await Electron.IpcMain.On("set-setting", (arg) => if (array.Count == 2 && array[0] != null && array[0].Type == Newtonsoft.Json.Linq.JTokenType.String) SaveSetting(array[0].ToString(), array[1]); else - Console.WriteLine("Invalid setting: " + arg); + logger.Error("Invalid setting when attempting 'set-setting': " + arg); + }); + + + await Electron.IpcMain.On("show-log-file", async (arg) => { + if (logFilePath == null) { + await ShowMessageBox(window, logFilePathWarning, "Warning", MessageBoxType.warning); + } else { + await Electron.Shell.ShowItemInFolderAsync(Path.Combine(logFilePath)); + } }); window.OnClosed += () => Electron.App.Quit(); } + private async Task ShowMessageBox(BrowserWindow window, string message, string title = "Error", MessageBoxType type = MessageBoxType.error) + { + MessageBoxOptions options = PrepareMessageBox(message, title, type); + return await Electron.Dialog.ShowMessageBoxAsync(window, options); + } + + private async Task ShowMessageBox(string message, string title = "Error", MessageBoxType type = MessageBoxType.error) + { + MessageBoxOptions options = PrepareMessageBox(message, title, type); + return await Electron.Dialog.ShowMessageBoxAsync(options); + } + + private MessageBoxOptions PrepareMessageBox(string message, string title = "Error", MessageBoxType type = MessageBoxType.error) + { + MessageBoxOptions options = new MessageBoxOptions(message); + options.Type = type; + options.Title = title; + + switch (type) { + case MessageBoxType.error: + logger.Error(message); + break; + case MessageBoxType.info: + logger.Info(message); + break; + case MessageBoxType.warning: + logger.Warn(message); + break; + } + + return options; + } + Dictionary settings = GetSettings(); private void SaveSetting(String key, Object value) @@ -287,7 +377,7 @@ private void RunLoop(BrowserWindow window, IWebHostEnvironment env) } catch (Exception e) { - Console.WriteLine(e); + logger.Error("Error saving data", e); } lastLap = data.CompletedLaps; diff --git a/electron.manifest.json b/electron.manifest.json index 04803c1..fe48157 100644 --- a/electron.manifest.json +++ b/electron.manifest.json @@ -11,7 +11,7 @@ "appId": "com.yuvix.rehud", "productName": "ReHUD", "copyright": "Copyright © 2023", - "buildVersion": "0.3.0", + "buildVersion": "0.3.1", "win": { "icon": "../../../wwwroot/ReHUD.png" }, diff --git a/log4net.config b/log4net.config new file mode 100644 index 0000000..c66919b --- /dev/null +++ b/log4net.config @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/wwwroot/css/app.css b/wwwroot/css/app.css index fd7f235..8215da1 100644 --- a/wwwroot/css/app.css +++ b/wwwroot/css/app.css @@ -94,7 +94,6 @@ table { } #main-container { - display: none; width: calc(100vw - 14px); height: calc(100vh - 14px) !important; margin: 7px; @@ -159,7 +158,7 @@ progress::-webkit-progress-bar { } he#basic { - width: 217px !important; + min-width: 217px !important; } he#basic td { border: 1px solid white; @@ -434,7 +433,6 @@ span#gear { margin: 0 !important; margin-top: -3px !important; color: var(--revs-color); - width: 69px !important; } diff --git a/wwwroot/css/settings.css b/wwwroot/css/settings.css index 57298e4..eeb306b 100644 --- a/wwwroot/css/settings.css +++ b/wwwroot/css/settings.css @@ -10,7 +10,8 @@ label { } button { - border: none; + border: none !important; + outline: none !important; background-color: #2c2c2c; color: #c1c1c1; border-radius: 5px; @@ -26,7 +27,12 @@ button:hover { } button.selected { - background-color: #46290c; + background-color: #813c00; +} + +input[type=number]::-webkit-inner-spin-button, +input[type=number]::-webkit-outer-spin-button { + opacity: 1; } .setting { @@ -38,3 +44,42 @@ button.selected { color: #ff4141; margin-left: 5px; } + + + +#radar-beep-volume-text { + width: 45px; + border: none; + outline: none !important; + border-radius: 4px; + padding: 2px; +} + +.slider { + appearance: none; + height: 8px; + border-radius: 4px; + background: #d3d3d3; + outline: none; + opacity: 0.7; + transition: opacity .2s; +} +.slider:hover { + opacity: 1; +} +.slider::-webkit-slider-thumb { + appearance: none; + width: 18px; + height: 18px; + border-radius: 50%; + background: #b95600; + cursor: pointer; +} + +#show-log-file { + position: fixed; + right: 0; + bottom: 0; + margin: 40px; + box-shadow: 3px 3px 10px #181818; +} diff --git a/wwwroot/js/index.js b/wwwroot/js/index.js index da98459..756a28a 100644 --- a/wwwroot/js/index.js +++ b/wwwroot/js/index.js @@ -3,6 +3,9 @@ const {ipcRenderer} = require('electron'); +document.addEventListener('DOMContentLoaded', () => enableLogging(ipcRenderer, 'index.js')); + + const defaultRenderCycle = 30; class Value { @@ -88,10 +91,8 @@ function insertCell(row, value, className) { const RADAR_RADIUS = 12; // meters const RADAR_BEEP_MIN_SPEED = 15; // km/h -const DEFAULT_CAR_WIDTH = 1.9; // meters -const DEFAULT_CAR_LENGTH = 4.5; // meters - let RADAR_AUDIO_CONTROLLER = null; + document.addEventListener('DOMContentLoaded', () => { RADAR_AUDIO_CONTROLLER = new AudioController({volumeMultiplier: 1}); }); @@ -141,14 +142,26 @@ const laptimeFormat = (time) => { */ let SPEED_UNITS = 'kmh'; + +const NA = 'N/A'; + const root = document.querySelector(':root'); const VALUES = [ new Value('speed', 'carSpeed', 5, (x) => Math.round((typeof x !== 'number' ? 0 : x * 3.6) * (SPEED_UNITS === 'mph' ? 0.621371 : 1))), - new Value('gear', 'gear', 3, (x) => x == undefined || x == 0 ? 'N' : x == -1 ? 'R' : x), - new Value('engine-map', 'engineMapSetting', (x) => `EM: ${x == -1 ? 5 : x}`), + new Value('gear', 'gear', 3, (x, gearId) => { + const gearElement = document.getElementById(gearId); + const res = (x == undefined || x == 0) ? 'N' : x == -1 ? 'R' : x.toString(); + if (res.length == 1) + gearElement.width = '69px'; + else + gearElement.width = '117px'; + + return res; + }), + new Value('engine-map', 'engineMapSetting', (x) => `EM: ${valueIsValid(x) ? 5 : x}`), new Value('traction-control', ['tractionControlSetting', 'tractionControlPercent'], (x, y) => - `TC${x}` + (y == undefined ? `` : `: ${Math.round(y)}%`)), - new Value('engine-brake', 'engineBrakeSetting', (x) => `EB: ${x}`), + `TC${(valueIsValid(x) ? x : ': ' + NA)}` + (valueIsValid(y) ? `: ${Math.round(y)}%` : '')), + new Value('engine-brake', 'engineBrakeSetting', (x) => `EB: ${valueIsValid(x) ? x : NA}`), new Value('brake-bias', 'brakeBias', (x) => `BB: ${(100 - x * 100).toFixed(1)}%`), new Value('revs', ['engineRps', 'maxEngineRps', 'upshiftRps', 'pitLimiter'], 1, (current, max, upshift, pitLimiter, id) => { if (current == undefined || max == undefined) @@ -173,12 +186,12 @@ const VALUES = [ } }), - new Value('fuel-left', 'fuelLeft', (x) => x == undefined ? 'N/A' : `${x.toFixed(1)}`), - new Value('fuel-per-lap', '+fuelPerLap', (x) => x == undefined ? 'N/A' : `${x.toFixed(2)}`), + new Value('fuel-left', 'fuelLeft', (x) => x == undefined ? NA : `${x.toFixed(1)}`), + new Value('fuel-per-lap', '+fuelPerLap', (x) => x == undefined ? NA : `${x.toFixed(2)}`), new Value('fuel-laps', ['fuelLeft', '+fuelPerLap'], (x, y) => { if (x == undefined || y == undefined) { root.style.setProperty('--fuel-left-color', 'rgb(0, 255, 0)') - return 'N/A'; + return NA; } // 1 lap left - red, 5 laps left - green @@ -187,7 +200,7 @@ const VALUES = [ }), new Value('fuel-time', ['fuelLeft', '+fuelPerLap', '+averageLapTime'], (x, y, z) => { if (x == undefined || y == undefined || z == undefined) - return 'N/A'; + return NA; const time = x / y * z; const hours = Math.floor(time / 3600); const minutes = (Math.floor(time / 60) % 60).toString().padStart(2, '0'); @@ -197,7 +210,7 @@ const VALUES = [ new Value('fuel-last-lap', ['+fuelLastLap', '+fuelPerLap'], (x, y) => { if (x == undefined) { root.style.setProperty('--fuel-last-lap-color', 'var(--fuel-middle-color)'); - return 'N/A'; + return NA; } // lastlap consumed more than average - red, less - green, average - middle point @@ -206,13 +219,13 @@ const VALUES = [ }), new Value('fuel-to-end', ['+lapsUntilFinish', '+fuelPerLap'], (x, y) => { if (x == undefined || y == undefined) - return 'N/A'; + return NA; return `${(x * y).toFixed(1)}`; }), new Value('fuel-to-add', ['+lapsUntilFinish', '+fuelPerLap', 'fuelLeft'], (x, y, z) => { if (x == undefined || y == undefined || z == undefined) { root.style.setProperty('--fuel-to-add-color', 'var(--fuel-middle-color)'); - return 'N/A'; + return NA; } const fuelToAdd = x * y - z; @@ -257,7 +270,7 @@ const VALUES = [ const temp = x?.[tire]?.currentTemp?.[side]; if (temp == undefined) { - text.innerText = 'N/A'; + text.innerText = NA; root.style.setProperty(`--${name}-${i}-color`, 'var(--temp-color-normal)'); continue; } @@ -333,6 +346,16 @@ const VALUES = [ tc = valueIsValid(tc) ? tc : 0; abs = valueIsValid(abs) ? abs : 0; + if (tc == 0) + document.getElementById('tc-icon').style.display = 'none'; + else + document.getElementById('tc-icon').style.display = 'block'; + + if (abs == 0) + document.getElementById('abs-icon').style.display = 'none'; + else + document.getElementById('abs-icon').style.display = 'block'; + root.style.setProperty('--tc-grayscale', tc == 5 ? 0 : 1); root.style.setProperty('--abs-grayscale', abs == 5 ? 0 : 1); root.style.setProperty('--tc-brightness', tc == 0 ? 1 : 10); @@ -341,23 +364,27 @@ const VALUES = [ new Value('relative-viewer', ['driverData', 'position', 'layoutLength', 'sessionPhase'], 5, (all, place, trackLength, phase) => { const relative = document.getElementById('relative-viewer'); - if (all == null || place == null) - return false; - - relative.style.display = 'block'; const relativeTable = relative.getElementsByTagName('tbody')[0]; - place--; - // 1 - garage, 2 - gridwalk, 3 - formation, 4 - countdown, 5 - green flag, 6 - checkered flag if (phase < 3) { relativeTable.innerHTML = ''; drivers = {}; return false; } + + if (all == null || place == null) + return false; + const driverCount = all.length; if (driverCount <= 1) return false; + + + + place--; + + relative.style.display = 'block'; const classes = []; /** @@ -499,7 +526,7 @@ const VALUES = [ insertCell(row, carName, 'car-name'); const deltaRaw = mergedDeltas[i][1]; - const delta = driver.place == place + 1 ? '' : (deltaRaw == null ? 'N/A' : deltaRaw.toFixed(1)); + const delta = driver.place == place + 1 ? '' : (deltaRaw == null ? NA : deltaRaw.toFixed(1)); insertCell(row, delta, 'time-delta'); } @@ -616,10 +643,12 @@ const VALUES = [ const rotationMatrix = rotationMatrixFromEular(driver.orientation); drivers.forEach(d => { - if (myPlace != d.place) + if (myPlace != d.place) { d.relativePosition = rotateVector(rotationMatrix, vectorSubtract(driver.position, d.position)); // x - left/right, z - front/back - else { + d.relativeOrientation = vectorSubtract(d.orientation, driver.orientation); + } else { d.relativePosition = { x: 0, y: 0, z: 0 }; + d.relativeOrientation = { x: 0, y: 0, z: 0 }; } }); const close = drivers.filter(d => distanceFromZero(d.relativePosition) < RADAR_RADIUS); @@ -639,25 +668,31 @@ const VALUES = [ } radar.children[i].style.display = null; const driver = close[i]; + + const rotation = driver.relativeOrientation.y; const leftRight = driver.relativePosition.x; let frontBack = driver.relativePosition.z; - if (leftRight < 0 && (Math.abs(frontBack) < Math.abs(leftRight) || Math.abs(frontBack) <= DEFAULT_CAR_LENGTH)) + const car_width = driver.driverInfo.carWidth; + const car_length = driver.driverInfo.carLength; + + if (leftRight < 0 && (Math.abs(frontBack) < Math.abs(leftRight) || Math.abs(frontBack) <= car_length)) closeLeft = 1; - else if (leftRight > 0 && (Math.abs(frontBack) < Math.abs(leftRight) || Math.abs(frontBack) <= DEFAULT_CAR_LENGTH)) + else if (leftRight > 0 && (Math.abs(frontBack) < Math.abs(leftRight) || Math.abs(frontBack) <= car_length)) closeRight = 1; frontBack = -frontBack; const distance = distanceFromZero(driver.relativePosition); - const width = DEFAULT_CAR_WIDTH / RADAR_RADIUS * radar_size / 2; - const height = DEFAULT_CAR_LENGTH / RADAR_RADIUS * radar_size / 2; + const width = car_width / RADAR_RADIUS * radar_size / 2; + const height = car_length / RADAR_RADIUS * radar_size / 2; radar.children[i].style.left = `${(leftRight / RADAR_RADIUS) * radar_size / 2 + radar_size / 2 - width / 2}px`; radar.children[i].style.top = `${(frontBack / RADAR_RADIUS) * radar_size / 2 + radar_size / 2 - height / 2}px`; radar.children[i].style.width = `${width}px`; radar.children[i].style.height = `${height}px`; + radar.children[i].style.transform = `rotate(${rotation}rad)`; if (myPlace == driver.place) { radar.children[i].classList.add('radar-car-self'); @@ -724,14 +759,15 @@ ipcRenderer.on('data', (event, data) => { function show() { isShown = true; - document.getElementById('main-container').style.display = 'flex'; + document.body.style.display = 'block'; } function hide() { isShown = false; - document.getElementById('main-container').style.display = 'none'; + document.body.style.display = 'none'; } +document.addEventListener('DOMContentLoaded', hide); ipcRenderer.on('hide', hide); ipcRenderer.on('show', show); @@ -749,6 +785,9 @@ ipcRenderer.on('set-setting', (e, arg) => { case 'speedUnits': SPEED_UNITS = value; break; + case 'radarBeepVolume': + if (RADAR_AUDIO_CONTROLLER != null) + RADAR_AUDIO_CONTROLLER.setVolume(value); } }); diff --git a/wwwroot/js/settings.js b/wwwroot/js/settings.js index 3ff8d60..f3052c8 100644 --- a/wwwroot/js/settings.js +++ b/wwwroot/js/settings.js @@ -1,9 +1,15 @@ const {ipcRenderer} = require('electron'); +const { remote } = require('electron'); + +// document.addEventListener('DOMContentLoaded', () => utils.enableLogging(ipcRenderer, 'settings.js')); +document.addEventListener('DOMContentLoaded', () => enableLogging(ipcRenderer, 'settings.js')); + let settings = {}; const writeSettingsMap = { 'speedUnits': speedUnits, + 'radarBeepVolume': radarBeepVolume, }; @@ -21,6 +27,32 @@ function setSettings(newSettings) { document.addEventListener('DOMContentLoaded', () => { const settingsBase64 = location.hash.substring(1); setSettings(JSON.parse(Buffer.from(settingsBase64, 'base64').toString('utf8'))); + + const onclick = [ + { id: 'edit-layout', func: () => lockOverlay(true) }, + { id: 'cancel-reset-layout', func: () => lockOverlay(false) }, + { id: 'speed-units-kmh', func: () => speedUnits('kmh') }, + { id: 'speed-units-mph', func: () => speedUnits('mph') }, + { id: 'show-log-file', func: () => ipcRenderer.send('show-log-file') }, + ]; + + const oninput = [ + { id: 'radar-beep-volume', func: (v) => radarBeepVolume(v) }, + { id: 'radar-beep-volume-text', func: (v) => radarBeepVolume(v) }, + ]; + + onclick.forEach((o) => { + const element = document.getElementById(o.id); + if (element) { + element.addEventListener('click', o.func); + } + }); + oninput.forEach((o) => { + const element = document.getElementById(o.id); + if (element) { + element.addEventListener('input', () => o.func(element.value)); + } + }); }); @@ -68,6 +100,23 @@ function speedUnits(val) { } } +const MINIMUM_RADAR_BEEP_VOLUME = 0; +const MAXIMUM_RADAR_BEEP_VOLUME = 3; +function radarBeepVolume(val) { + sendToMainWindow(['radarBeepVolume', val]); + + const volumeSlider = document.getElementById('radar-beep-volume'); + const volume = volumeSlider.nextElementSibling; + + volumeSlider.min = MINIMUM_RADAR_BEEP_VOLUME; + volumeSlider.max = MAXIMUM_RADAR_BEEP_VOLUME; + volume.min = MINIMUM_RADAR_BEEP_VOLUME; + volume.max = MAXIMUM_RADAR_BEEP_VOLUME; + volumeSlider.value = val; + volume.value = val; + +} + function sendToMainWindow(arg) { ipcRenderer.send('set-setting', arg); } diff --git a/wwwroot/js/utils.js b/wwwroot/js/utils.js index 8d9812d..0823e44 100644 --- a/wwwroot/js/utils.js +++ b/wwwroot/js/utils.js @@ -30,7 +30,7 @@ class Driver { * The maximum deviation allowed within all laps for the best lap to be considered trustworthy. */ static get MIN_TRUSTWORTHINESS_FOR_BEST_LAP() { - return 0.982; // for example, [102, 101, 98.5] recieves a score of 0.985 + return 0.982; // for example, [102, 101, 98.5] receives a score of 0.985 } get BEST_LAPS_FOR_DEVIATION() { @@ -138,10 +138,11 @@ class Driver { return null; return delta; } else { - if (this.bestLapTrustworthiness > Driver.MIN_TRUSTWORTHINESS_FOR_BEST_LAP) { + const res = driver.deltaBetweenPoints(thisLapDistance, otherLapDistance); + if (res == null || this.bestLapTrustworthiness > Driver.MIN_TRUSTWORTHINESS_FOR_BEST_LAP) { return this.deltaBetweenPoints(thisLapDistance, otherLapDistance); } - return driver.deltaBetweenPoints(thisLapDistance, otherLapDistance); + return res; } } @@ -161,7 +162,7 @@ class Driver { if (this.bestLapTrustworthiness >= Driver.MIN_TRUSTWORTHINESS_FOR_BEST_LAP) { lapData = this.bestLap; } - + const point1Index = Driver.findClosestPointIndex(point1, lapData); const point2Index = Driver.findClosestPointIndex(point2, lapData); @@ -175,7 +176,7 @@ class Driver { const pointDistance = lapData[point1Index][0]; point1Time += (nextPointTime - point1Time) * (point1 - pointDistance) / (nextPointDistance - pointDistance); } - + let point2Time = lapData[point2Index][1]; if (point2Index < lapData.length - 1) { const nextPointTime = lapData[point2Index + 1][1]; @@ -252,7 +253,7 @@ class Driver { function standardDeviation(values) { var avg = average(values); - var squareDiffs = values.map(function(value) { + var squareDiffs = values.map(function (value) { var diff = value - avg; var sqrDiff = diff * diff; return sqrDiff; @@ -270,7 +271,7 @@ function standardDeviation(values) { * @return {number} */ function average(data) { - var sum = data.reduce(function(sum, value) { + var sum = data.reduce(function (sum, value) { return sum + value; }, 0); @@ -356,7 +357,7 @@ class AudioController { mediaSource = this.audioContext.createMediaElementSource(this.audio); stereoPanner = this.audioContext.createStereoPanner(); - constructor({minPlaybackRate=0.1, maxPlaybackRate=10, playbackRateMultiplier=2, volumeMultiplier=1} = {}) { + constructor({ minPlaybackRate = 0.1, maxPlaybackRate = 10, playbackRateMultiplier = 2, volumeMultiplier = 1 } = {}) { this.minPlaybackRate = minPlaybackRate; this.maxPlaybackRate = maxPlaybackRate; this.playbackRateMultiplier = playbackRateMultiplier; @@ -376,6 +377,10 @@ class AudioController { }; } + setVolume(volume) { + this.volumeMultiplier = volume; + } + /** * @param {number} amount - Controls the volume and playback rate of the audio (higher = louder and faster) * @param {number} pan - Controls the panning of the audio (negative = left, positive = right), between -1 and 1 @@ -386,7 +391,80 @@ class AudioController { this.stereoPanner.pan.value = pan; if (this.audio.paused && this.audioContext.state !== 'suspended' && !this.audioIsPlaying) { - this.audio.play().catch(() => {}); + this.audio.play().catch(() => { }); + } + } +} + +const INFO = 'INFO'; +const WARN = 'WARN'; +const ERROR = 'ERROR'; + +function writeToLog(ipc, message, level = INFO) { + ipc.send('log', { message, level }); +} + + +function enableLogging(ipc, filename) { + function proxy(ipc, f, level) { + return function (...args) { + f(...args); + function getErrorObject(){ + try { throw Error('') } catch(err) { return err; } + } + + let origin = null; + try { + const err = getErrorObject(); + const caller_line = err.stack.split("\n")[3]; + const index = caller_line.indexOf("at "); + origin = caller_line.slice(index+2, caller_line.length); + } catch (e) { + origin = filename; + } + + writeToLog(ipc, `${origin}: ${args.join(' ')}`, level); } } + const originalLog = console.log; + const originalWarn = console.warn; + const originalError = console.error; + console.log = proxy(ipc, originalLog, INFO); + console.warn = proxy(ipc, originalWarn, WARN); + console.error = proxy(ipc, originalError, ERROR); + + + window.onerror = (message, file, line, column, errorObj) => { + if (errorObj !== undefined) //so it won't blow up in the rest of the browsers + console.error(errorObj.stack); + + return false; + }; + window.addEventListener('unhandledrejection', (e) => { + console.error(JSON.stringify(e.reason)); + }); + window.addEventListener('securitypolicyviolation', (e) => { + const message = `Blocked '${e.blockedURI}' from ${e.documentURI}:${e.lineNumber} (${e.violatedDirective})`; + console.error(message); + }); } + + +// const { contextBridge } = require('electron') + + +// contextBridge.exposeInMainWorld('utils', { +// Driver, +// vectorSubtract, +// distanceFromZero, +// rotationMatrixFromEular, +// rotateVector, +// mpsToKph, +// AudioController, +// writeToLog, +// enableLogging, +// INFO, +// WARN, +// ERROR +// }); + diff --git a/wwwroot/lib/agnostic-draggable/LICENSE b/wwwroot/lib/agnostic-draggable/LICENSE new file mode 100644 index 0000000..b595925 --- /dev/null +++ b/wwwroot/lib/agnostic-draggable/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Marcos Pont + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/wwwroot/lib/agnostic-draggable/dist/agnostic-draggable.min.js b/wwwroot/lib/agnostic-draggable/dist/agnostic-draggable.min.js new file mode 100644 index 0000000..52490bf --- /dev/null +++ b/wwwroot/lib/agnostic-draggable/dist/agnostic-draggable.min.js @@ -0,0 +1 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).agnosticDraggable={})}(this,(function(e){"use strict";function t(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function n(e){for(var n=1;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0?Jt:Qt)(e)},tn=en,nn=Math.min,rn=function(e){return e>0?nn(tn(e),9007199254740991):0},on=en,an=Math.max,sn=Math.min,ln=function(e,t){var n=on(e);return n<0?an(n+t,0):sn(n,t)},un=Ee,cn=rn,hn=ln,fn=function(e){return function(t,n,r){var i,o=un(t),a=cn(o.length),s=hn(r,a);if(e&&n!=n){for(;a>s;)if((i=o[s++])!=i)return!0}else for(;a>s;s++)if((e||s in o)&&o[s]===n)return e||s||0;return!e&&-1}},pn={includes:fn(!0),indexOf:fn(!1)},dn=Oe,gn=Ee,vn=pn.indexOf,mn=St,yn=function(e,t){var n,r=gn(e),i=0,o=[];for(n in r)!dn(mn,n)&&dn(r,n)&&o.push(n);for(;t.length>i;)dn(r,n=t[i++])&&(~vn(o,n)||o.push(n));return o},bn=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],wn=yn,xn=bn.concat("length","prototype");Kt.f=Object.getOwnPropertyNames||function(e){return wn(e,xn)};var En={};En.f=Object.getOwnPropertySymbols;var kn,Sn,Pn=Kt,In=En,On=Fe,Dn=Zt("Reflect","ownKeys")||function(e){var t=Pn.f(On(e)),n=In.f;return n?t.concat(n(e)):t},Cn=Oe,An=Dn,Ln=ae,zn=We,Mn=se,jn=/#|\.prototype\./,Tn=function(e,t){var n=Hn[Rn(e)];return n==_n||n!=Nn&&("function"==typeof t?Mn(t):!!t)},Rn=Tn.normalize=function(e){return String(e).replace(jn,".").toLowerCase()},Hn=Tn.data={},Nn=Tn.NATIVE="N",_n=Tn.POLYFILL="P",$n=Tn,Bn=oe,Wn=ae.f,Yn=Qe,Fn=Je.exports,Xn=nt,Un=function(e,t){for(var n=An(t),r=zn.f,i=Ln.f,o=0;o=74)&&(kn=rr.match(/Chrome\/(\d+)/))&&(Sn=kn[1]);var sr=Sn&&+Sn,lr=tr,ur=sr,cr=se,hr=!!Object.getOwnPropertySymbols&&!cr((function(){return!Symbol.sham&&(lr?38===ur:ur>37&&ur<41)})),fr=hr&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,pr=oe,dr=ft.exports,gr=Oe,vr=bt,mr=hr,yr=fr,br=dr("wks"),wr=pr.Symbol,xr=yr?wr:wr&&wr.withoutSetter||vr,Er=function(e){return gr(br,e)&&(mr||"string"==typeof br[e])||(mr&&gr(wr,e)?br[e]=wr[e]:br[e]=xr("Symbol."+e)),br[e]},kr=ke,Sr=er,Pr=Er("species"),Ir=function(e,t){var n;return Sr(e)&&("function"!=typeof(n=e.constructor)||n!==Array&&!Sr(n.prototype)?kr(n)&&null===(n=n[Pr])&&(n=void 0):n=void 0),new(void 0===n?Array:n)(0===t?0:t)},Or=function(e,t,n){if(Zn(e),void 0===t)return e;switch(n){case 0:return function(){return e.call(t)};case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,i){return e.call(t,n,r,i)}}return function(){return e.apply(t,arguments)}},Dr=ye,Cr=Qn,Ar=rn,Lr=Ir,zr=[].push,Mr=function(e){var t=1==e,n=2==e,r=3==e,i=4==e,o=6==e,a=7==e,s=5==e||o;return function(l,u,c,h){for(var f,p,d=Cr(l),g=Dr(d),v=Or(u,c,3),m=Ar(g.length),y=0,b=h||Lr,w=t?b(l,m):n||a?b(l,0):void 0;m>y;y++)if((s||y in g)&&(p=v(f=g[y],y,d),e))if(t)w[y]=p;else if(p)switch(e){case 3:return!0;case 5:return f;case 6:return y;case 2:zr.call(w,f)}else switch(e){case 4:return!1;case 7:zr.call(w,f)}return o?-1:r||i?i:w}},jr={forEach:Mr(0),map:Mr(1),filter:Mr(2),some:Mr(3),every:Mr(4),find:Mr(5),findIndex:Mr(6),filterOut:Mr(7)},Tr=se,Rr=sr,Hr=Er("species"),Nr=function(e){return Rr>=51||!Tr((function(){var t=[];return(t.constructor={})[Hr]=function(){return{foo:1}},1!==t[e](Boolean).foo}))},_r=jr.filter;Gn({target:"Array",proto:!0,forced:!Nr("filter")},{filter:function(e){return _r(this,e,arguments.length>1?arguments[1]:void 0)}});var $r=se,Br=function(e,t){var n=[][e];return!!n&&$r((function(){n.call(null,t||function(){throw 1},1)}))},Wr=jr.forEach,Yr=Br("forEach")?[].forEach:function(e){return Wr(this,e,arguments.length>1?arguments[1]:void 0)};Gn({target:"Array",proto:!0,forced:[].forEach!=Yr},{forEach:Yr});var Fr=oe,Xr={CSSRuleList:0,CSSStyleDeclaration:0,CSSValueList:0,ClientRectList:0,DOMRectList:0,DOMStringList:0,DOMTokenList:1,DataTransferItemList:0,FileList:0,HTMLAllCollection:0,HTMLCollection:0,HTMLFormElement:0,HTMLSelectElement:0,MediaList:0,MimeTypeArray:0,NamedNodeMap:0,NodeList:1,PaintRequestList:0,Plugin:0,PluginArray:0,SVGLengthList:0,SVGNumberList:0,SVGPathSegList:0,SVGPointList:0,SVGStringList:0,SVGTransformList:0,SourceBufferList:0,StyleSheetList:0,TextTrackCueList:0,TextTrackList:0,TouchList:0},Ur=Yr,Vr=Qe;for(var Gr in Xr){var qr=Fr[Gr],Zr=qr&&qr.prototype;if(Zr&&Zr.forEach!==Ur)try{Vr(Zr,"forEach",Ur)}catch(e){Zr.forEach=Ur}}var Kr=qn,Qr=ke,Jr=[].slice,ei={},ti=function(e,t,n){if(!(t in ei)){for(var r=[],i=0;i>>0||(Li.test(n)?16:10))}:Ai;Gn({global:!0,forced:parseInt!=zi},{parseInt:zi});var Mi=Gn,ji=se,Ti=er,Ri=ke,Hi=Qn,Ni=rn,_i=oi,$i=Ir,Bi=Nr,Wi=sr,Yi=Er("isConcatSpreadable"),Fi=9007199254740991,Xi="Maximum allowed index exceeded",Ui=Wi>=51||!ji((function(){var e=[];return e[Yi]=!1,e.concat()[0]!==e})),Vi=Bi("concat"),Gi=function(e){if(!Ri(e))return!1;var t=e[Yi];return void 0!==t?!!t:Ti(e)};Mi({target:"Array",proto:!0,forced:!Ui||!Vi},{concat:function(e){var t,n,r,i,o,a=Hi(this),s=$i(a,0),l=0;for(t=-1,r=arguments.length;tFi)throw TypeError(Xi);for(n=0;n=Fi)throw TypeError(Xi);_i(s,l++,o)}return s.length=l,s}});var qi=Gn,Zi=Ee,Ki=[].join,Qi=ye!=Object,Ji=Br("join",",");qi({target:"Array",proto:!0,forced:Qi||!Ji},{join:function(e){return Ki.call(Zi(this),void 0===e?",":e)}});var eo=function(){function e(e){var t=this;this._insertTag=function(e){var n;n=0===t.tags.length?t.prepend?t.container.firstChild:t.before:t.tags[t.tags.length-1].nextSibling,t.container.insertBefore(e,n),t.tags.push(e)},this.isSpeedy=void 0===e.speedy||e.speedy,this.tags=[],this.ctr=0,this.nonce=e.nonce,this.key=e.key,this.container=e.container,this.prepend=e.prepend,this.before=null}var t=e.prototype;return t.hydrate=function(e){e.forEach(this._insertTag)},t.insert=function(e){this.ctr%(this.isSpeedy?65e3:1)==0&&this._insertTag(function(e){var t=document.createElement("style");return t.setAttribute("data-emotion",e.key),void 0!==e.nonce&&t.setAttribute("nonce",e.nonce),t.appendChild(document.createTextNode("")),t.setAttribute("data-s",""),t}(this));var t=this.tags[this.tags.length-1];if(this.isSpeedy){var n=function(e){if(e.sheet)return e.sheet;for(var t=0;t0?fo(ko,--xo):0,bo--,10===Eo&&(bo=1,yo--),Eo}function Oo(){return Eo=xo2||Lo(Eo)>3?"":" "}function Ro(e,t){for(;--t&&Oo()&&!(Eo<48||Eo>102||Eo>57&&Eo<65||Eo>70&&Eo<97););return Ao(e,Co()+(t<6&&32==Do()&&32==Oo()))}function Ho(e){for(;Oo();)switch(Eo){case e:return xo;case 34:case 39:return Ho(34===e||39===e?e:Eo);case 40:41===e&&Ho(e);break;case 92:Oo()}return xo}function No(e,t){for(;Oo()&&e+Eo!==57&&(e+Eo!==84||47!==Do()););return"/*"+Ao(t,xo-1)+"*"+lo(47===e?e:Oo())}function _o(e){for(;!Lo(Do());)Oo();return Ao(e,xo)}function $o(e){return Mo(Bo("",null,null,null,[""],e=zo(e),0,[0],e))}function Bo(e,t,n,r,i,o,a,s,l){for(var u=0,c=0,h=a,f=0,p=0,d=0,g=1,v=1,m=1,y=0,b="",w=i,x=o,E=r,k=b;v;)switch(d=y,y=Oo()){case 34:case 39:case 91:case 40:k+=jo(y);break;case 9:case 10:case 13:case 32:k+=To(d);break;case 92:k+=Ro(Co()-1,7);continue;case 47:switch(Do()){case 42:case 47:mo(Yo(No(Oo(),Co()),t,n),l);break;default:k+="/"}break;case 123*g:s[u++]=go(k)*m;case 125*g:case 59:case 0:switch(y){case 0:case 125:v=0;case 59+c:p>0&&go(k)-h&&mo(p>32?Fo(k+";",r,n,h-1):Fo(co(k," ","")+";",r,n,h-2),l);break;case 59:k+=";";default:if(mo(E=Wo(k,t,n,u,c,i,s,b,w=[],x=[],h),o),123===y)if(0===c)Bo(k,t,E,E,w,o,h,s,x);else switch(f){case 100:case 109:case 115:Bo(e,E,E,r&&mo(Wo(e,E,E,0,0,i,s,b,i,w=[],h),x),i,x,h,s,r?w:x);break;default:Bo(k,E,E,E,[""],x,h,s,x)}}u=c=p=0,g=m=1,b=k="",h=a;break;case 58:h=1+go(k),p=d;default:if(g<1)if(123==y)--g;else if(125==y&&0==g++&&125==Io())continue;switch(k+=lo(y),y*g){case 38:m=c>0?1:(k+="\f",-1);break;case 44:s[u++]=(go(k)-1)*m,m=1;break;case 64:45===Do()&&(k+=jo(Oo())),f=Do(),c=go(b=k+=_o(Co())),y++;break;case 45:45===d&&2==go(k)&&(g=0)}}return o}function Wo(e,t,n,r,i,o,a,s,l,u,c){for(var h=i-1,f=0===i?o:[""],p=vo(f),d=0,g=0,v=0;d0?f[m]+" "+y:co(y,/&\f/g,f[m])))&&(l[v++]=b);return So(e,t,n,0===i?oo:s,l,u,c)}function Yo(e,t,n){return So(e,t,n,io,lo(Eo),po(e,2,-2),0)}function Fo(e,t,n,r){return So(e,t,n,ao,po(e,0,r),po(e,r+1,-1),r)}function Xo(e,t){switch(function(e,t){return(((t<<2^fo(e,0))<<2^fo(e,1))<<2^fo(e,2))<<2^fo(e,3)}(e,t)){case 5103:return ro+"print-"+e+e;case 5737:case 4201:case 3177:case 3433:case 1641:case 4457:case 2921:case 5572:case 6356:case 5844:case 3191:case 6645:case 3005:case 6391:case 5879:case 5623:case 6135:case 4599:case 4855:case 4215:case 6389:case 5109:case 5365:case 5621:case 3829:return ro+e+e;case 5349:case 4246:case 4810:case 6968:case 2756:return ro+e+no+e+to+e+e;case 6828:case 4268:return ro+e+to+e+e;case 6165:return ro+e+to+"flex-"+e+e;case 5187:return ro+e+co(e,/(\w+).+(:[^]+)/,"-webkit-box-$1$2-ms-flex-$1$2")+e;case 5443:return ro+e+to+"flex-item-"+co(e,/flex-|-self/,"")+e;case 4675:return ro+e+to+"flex-line-pack"+co(e,/align-content|flex-|-self/,"")+e;case 5548:return ro+e+to+co(e,"shrink","negative")+e;case 5292:return ro+e+to+co(e,"basis","preferred-size")+e;case 6060:return ro+"box-"+co(e,"-grow","")+ro+e+to+co(e,"grow","positive")+e;case 4554:return ro+co(e,/([^-])(transform)/g,"$1-webkit-$2")+e;case 6187:return co(co(co(e,/(zoom-|grab)/,ro+"$1"),/(image-set)/,ro+"$1"),e,"")+e;case 5495:case 3959:return co(e,/(image-set\([^]*)/,ro+"$1$`$1");case 4968:return co(co(e,/(.+:)(flex-)?(.*)/,"-webkit-box-pack:$3-ms-flex-pack:$3"),/s.+-b[^;]+/,"justify")+ro+e+e;case 4095:case 3583:case 4068:case 2532:return co(e,/(.+)-inline(.+)/,ro+"$1$2")+e;case 8116:case 7059:case 5753:case 5535:case 5445:case 5701:case 4933:case 4677:case 5533:case 5789:case 5021:case 4765:if(go(e)-1-t>6)switch(fo(e,t+1)){case 109:if(45!==fo(e,t+4))break;case 102:return co(e,/(.+:)(.+)-([^]+)/,"$1-webkit-$2-$3$1"+no+(108==fo(e,t+3)?"$3":"$2-$3"))+e;case 115:return~ho(e,"stretch")?Xo(co(e,"stretch","fill-available"),t)+e:e}break;case 4949:if(115!==fo(e,t+1))break;case 6444:switch(fo(e,go(e)-3-(~ho(e,"!important")&&10))){case 107:return co(e,":",":"+ro)+e;case 101:return co(e,/(.+:)([^;!]+)(;|!.+)?/,"$1"+ro+(45===fo(e,14)?"inline-":"")+"box$3$1"+ro+"$2$3$1"+to+"$2box$3")+e}break;case 5936:switch(fo(e,t+11)){case 114:return ro+e+to+co(e,/[svh]\w+-[tblr]{2}/,"tb")+e;case 108:return ro+e+to+co(e,/[svh]\w+-[tblr]{2}/,"tb-rl")+e;case 45:return ro+e+to+co(e,/[svh]\w+-[tblr]{2}/,"lr")+e}return ro+e+to+e+e}return e}function Uo(e,t){for(var n="",r=vo(e),i=0;i=4;++r,i-=4)t=1540483477*(65535&(t=255&e.charCodeAt(r)|(255&e.charCodeAt(++r))<<8|(255&e.charCodeAt(++r))<<16|(255&e.charCodeAt(++r))<<24))+(59797*(t>>>16)<<16),n=1540483477*(65535&(t^=t>>>24))+(59797*(t>>>16)<<16)^1540483477*(65535&n)+(59797*(n>>>16)<<16);switch(i){case 3:n^=(255&e.charCodeAt(r+2))<<16;case 2:n^=(255&e.charCodeAt(r+1))<<8;case 1:n=1540483477*(65535&(n^=255&e.charCodeAt(r)))+(59797*(n>>>16)<<16)}return(((n=1540483477*(65535&(n^=n>>>13))+(59797*(n>>>16)<<16))^n>>>15)>>>0).toString(36)}(i)+l,styles:i,next:ua}};function fa(e,t,n){var r="";return n.split(" ").forEach((function(n){void 0!==e[n]?t.push(e[n]+";"):r+=n+" "})),r}var pa=function(e,t,n){var r=e.key+"-"+t.name;if(!1===n&&void 0===e.registered[r]&&(e.registered[r]=t.styles),void 0===e.inserted[t.name]){var i=t;do{e.insert(t===i?"."+r:"",i,e.sheet,!0),i=i.next}while(void 0!==i)}};function da(e,t){if(void 0===e.inserted[t.name])return e.insert("",t,e.sheet,!0)}function ga(e,t,n){var r=[],i=fa(e,r,n);return r.length<2?n:i+t(r)}var va=function e(t){for(var n="",r=0;r-1&&e%1==0&&e-1&&e%1==0&&e<=9007199254740991},Qa=Ra,Ja=Ka,es=Ha,ts={};ts["[object Float32Array]"]=ts["[object Float64Array]"]=ts["[object Int8Array]"]=ts["[object Int16Array]"]=ts["[object Int32Array]"]=ts["[object Uint8Array]"]=ts["[object Uint8ClampedArray]"]=ts["[object Uint16Array]"]=ts["[object Uint32Array]"]=!0,ts["[object Arguments]"]=ts["[object Array]"]=ts["[object ArrayBuffer]"]=ts["[object Boolean]"]=ts["[object DataView]"]=ts["[object Date]"]=ts["[object Error]"]=ts["[object Function]"]=ts["[object Map]"]=ts["[object Number]"]=ts["[object Object]"]=ts["[object RegExp]"]=ts["[object Set]"]=ts["[object String]"]=ts["[object WeakMap]"]=!1;var ns=function(e){return es(e)&&Ja(e.length)&&!!ts[Qa(e)]};var rs=function(e){return function(t){return e(t)}},is={exports:{}};!function(e,t){var n=xa,r=t&&!t.nodeType&&t,i=r&&e&&!e.nodeType&&e,o=i&&i.exports===r&&n.process,a=function(){try{var e=i&&i.require&&i.require("util").types;return e||o&&o.binding&&o.binding("util")}catch(e){}}();e.exports=a}(is,is.exports);var os=ns,as=rs,ss=is.exports,ls=ss&&ss.isTypedArray,us=ls?as(ls):os,cs=wa,hs=Xa,fs=Ua,ps=Va.exports,ds=Za,gs=us,vs=Object.prototype.hasOwnProperty;var ms=function(e,t){var n=fs(e),r=!n&&hs(e),i=!n&&!r&&ps(e),o=!n&&!r&&!i&&gs(e),a=n||r||i||o,s=a?cs(e.length,String):[],l=s.length;for(var u in e)!t&&!vs.call(e,u)||a&&("length"==u||i&&("offset"==u||"parent"==u)||o&&("buffer"==u||"byteLength"==u||"byteOffset"==u)||ds(u,l))||s.push(u);return s},ys=Object.prototype;var bs=function(e){var t=e&&e.constructor;return e===("function"==typeof t&&t.prototype||ys)};var ws=function(e,t){return function(n){return e(t(n))}},xs=ws(Object.keys,Object),Es=bs,ks=xs,Ss=Object.prototype.hasOwnProperty;var Ps=Ra,Is=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)};var Os=function(e){if(!Is(e))return!1;var t=Ps(e);return"[object Function]"==t||"[object GeneratorFunction]"==t||"[object AsyncFunction]"==t||"[object Proxy]"==t},Ds=Os,Cs=Ka;var As=function(e){return null!=e&&Cs(e.length)&&!Ds(e)},Ls=ms,zs=function(e){if(!Es(e))return ks(e);var t=[];for(var n in Object(e))Ss.call(e,n)&&"constructor"!=n&&t.push(n);return t},Ms=As;var js=ba,Ts=function(e){return Ms(e)?Ls(e):zs(e)};var Rs=As;var Hs=function(e,t){return function(n,r){if(null==n)return n;if(!Rs(n))return e(n,r);for(var i=n.length,o=t?i:-1,a=Object(n);(t?o--:++o0&&void 0!==arguments[0]?arguments[0]:{};r(this,e),a(this,"data",null),a(this,"canceled",!1),this.data=t}return o(e,[{key:"type",get:function(){return this.constructor.type}},{key:"cancelable",get:function(){return this.constructor.cancelable}},{key:"cancel",value:function(){this.cancelable&&(this.canceled=!0)}}]),e}();a(Zl,"type","event"),a(Zl,"cancelable",!1);var Kl=function(e){s(n,e);var t=f(n);function n(){return r(this,n),t.apply(this,arguments)}return o(n,[{key:"pageX",get:function(){return this.data.pageX||null}},{key:"pageY",get:function(){return this.data.pageY||null}},{key:"target",get:function(){return this.data.target||null},set:function(e){this.data.target=e}},{key:"caller",get:function(){return this.data.caller||null}},{key:"originalEvent",get:function(){return this.data.originalEvent||null}},{key:"preventDefault",value:function(){var e;null===(e=this.originalEvent)||void 0===e||e.preventDefault()}},{key:"stopPropagation",value:function(){var e;null===(e=this.originalEvent)||void 0===e||e.stopPropagation()}}]),n}(Zl),Ql=function(e){s(n,e);var t=f(n);function n(){return r(this,n),t.apply(this,arguments)}return n}(Kl);a(Ql,"type","mouse:down"),a(Ql,"cancelable",!0);var Jl=function(e){s(n,e);var t=f(n);function n(){return r(this,n),t.apply(this,arguments)}return n}(Kl);a(Jl,"type","mouse:start"),a(Jl,"cancelable",!0);var eu=function(e){s(n,e);var t=f(n);function n(){return r(this,n),t.apply(this,arguments)}return n}(Kl);a(eu,"type","mouse:move");var tu=function(e){s(n,e);var t=f(n);function n(){return r(this,n),t.apply(this,arguments)}return n}(Kl);a(tu,"type","mouse:stop");var nu=Function.prototype.bind.call(Function.prototype.call,[].slice),ru=function(e){e&&A(e,{display:e.previousDisplay||null||""})},iu=function(e){e&&(e.previousDisplay=A(e,"display")||null,A(e,{display:"none"}))},ou=function(e){return e?L(e,"onselectstart"in document.createElement("div")?"selectstart":"mousedown",(function(e){return e.preventDefault()})):null},au=function(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=e,r=[];n&&n.parentNode&&n.parentNode!==document&&(!t||!H(n.parentNode,t));)r.push(n.parentNode),n=n.parentNode;return r},su=function(e){for(var t=0,n=e;n&&n.previousElementSibling;)n=n.previousElementSibling,t++;return t},lu=function(e,t){return e!==t&&_(e,t)},uu=function(e,t){return e&&t&&t.parentNode&&t.parentNode.insertBefore(e,t),e},cu=function(e,t){return e&&t&&t.parentNode&&(t.nextSibling?t.parentNode.insertBefore(e,t.nextSibling):t.parentNode.appendChild(e)),e},hu=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,i=document.createElement(e);return Js(t)&&Ys(t,(function(e,t){R(i,t,e)})),n&&1===n.nodeType&&n.appendChild(i),r&&(i.innerHTML=r),i},fu=function(e){return new tu({target:e,originalEvent:pu("mouseup",e)})},pu=function(e,t){var n={button:0,bubbles:!0,cancelable:!0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,clientX:1,clientY:1,screenX:0,screenY:0,view:document.defaultView,target:t,relatedTarget:document.documentElement};return new MouseEvent("mouseup",n)},du=function(e,t){if(e){var n=document.createEvent("HTMLEvents");n.initEvent(t,!1,!0),e.dispatchEvent(n)}},gu=function(e){var t=function(e){void 0===e&&(e=b());try{var t=e.activeElement;return t&&t.nodeName?t:null}catch(t){return e.body}}();lu(t,e.target)||t===document.body||du(t,"blur")},vu=function(e){return/(left|right)/.test(A(e,"float")||/(inline|table-cell)/.test(A(e,"display")))},mu=function(e){for(var t=[],n=[A(e,"borderTop"),A(e,"borderRight"),A(e,"borderBottom"),A(e,"borderLeft")],r=[A(e,"paddingTop"),A(e,"paddingRight"),A(e,"paddingBottom"),A(e,"paddingLeft")],i=0;i<4;i++)t[i]=(parseFloat(n[i])||0)+(parseFloat(r[i])||0);return{width:t[1]+t[3],height:t[0]+t[2]}},yu=function(e){var t=A(e,"position");/^(?:r|a|f)/.test(t)||A(e,{position:"relative"})},bu=function(e){var t=A(e,"position");/^(?:fixed|absolute)/.test(t)||A(e,{position:"absolute"})},wu=function(e,t){return parseInt(A(e,t),10)||0},xu=function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],n=A(e,"position"),r="absolute"===n;if("fixed"===n)return document;var i=t?/(auto|scroll|hidden)/:/(auto|scroll)/,o=au(e).filter((function(e){return(!r||"static"!==A(e,"position"))&&i.test(A(e,"overflow")+A(e,"overflowX")+A(e,"overflowY"))}));return o.length>0?o[0]:document},Eu=function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];return e===document||e===document.documentElement||t&&e===document.body},ku=null;ku||(ku=new function e(){var t=this;r(this,e),a(this,"draggable",null),a(this,"droppables",{}),a(this,"getDroppables",(function(e){return t.droppables[e]||[]})),a(this,"addDroppable",(function(e,n){e&&n&&(t.droppables[n]||(t.droppables[n]=[]),t.droppables[n].push(e))})),a(this,"removeDroppable",(function(e,n){e&&t.droppables[n]&&(t.droppables[n]=t.droppables[n].filter((function(t){return t!==e})))})),a(this,"prepareOffsets",(function(e,n){var r=n.type;t.draggable=e,t.getDroppables(e.scope).forEach((function(t){t.refreshVisibility(),t.visible&&t.accept(e)&&("mouse:start"===r&&t.activate(n),t.refreshProportions())}))})),a(this,"onDragMove",(function(e,n){t.getDroppables(e.scope).forEach((function(t){var r=t.intersect(e,n);if(r&&!t.isOver||!r&&t.isOver){var i,o=t.element,a=t.options,s=a.greedy,l=a.scope;if(s){var u=au(o).filter((function(e){return e[t.dataProperty]&&e[t.dataProperty].options.scope===l}));u.length>0&&((i=u[0][t.dataProperty]).greedyChild=r,r&&i.out(n))}r?t.over(n):t.out(n),i&&!r&&i.over(n)}}))})),a(this,"onDragStop",(function(e,n){t.prepareOffsets(e,n)})),a(this,"drop",(function(e,n){var r=null;return t.getDroppables(e.scope).forEach((function(t){t.intersect(e,n)&&(r=t.drop(n)||r),t.accept(e)&&t.deactivate(n)})),t.draggable=null,r}))});var Su=ku,Pu=function(e){s(n,e);var t=f(n);function n(e){var i;return r(this,n),a(c(i=t.call(this,e)),"scrollParent",null),a(c(i),"scrollParentOffset",null),a(c(i),"onDragStart",(function(e){if(i.scroll){var t=i.container.helperAttrs;i.scrollParent||(i.scrollParent=t.scrollParent),Eu(i.scrollParent,!1)||(i.scrollParentOffset=V(i.scrollParent))}})),a(c(i),"onDragMove",(function(e){if(i.scroll){var t=!1,n=e.sensorEvent,r=c(i),o=r.scrollParent,a=r.scrollParentOffset,s=i.container.helperSize,l=i.container.offset.click,u=i.container.options,h=u.axis,f=u.scrollSensitivity,p=u.scrollSpeed,d=n.pageX-l.left-(Eu(i.scrollParent,!1)?X(document):0),g=n.pageY-l.top-(Eu(i.scrollParent,!1)?U(document):0);Eu(i.scrollParent,!1)?(h&&"y"===h||(d',Bu='',Wu='',Yu={n:{cursor:"n-resize",height:"7px",width:"100%",top:"-5px",left:"0"},s:{cursor:"s-resize",height:"7px",width:"100%",bottom:"-5px",left:"0"},e:{cursor:"e-resize",width:"7px",right:"-5px",top:"0",height:"100%"},w:{cursor:"w-resize",width:"7px",left:"-5px",top:"0",height:"100%"},nw:{cursor:"nw-resize",width:"12px",height:"12px",left:"1px",top:"1px",backgroundImage:"url('data:image/svg+xml;utf8,".concat(encodeURIComponent(''),"')"),backgroundPosition:"center",backgroundRepeat:"no-repeat"},ne:{cursor:"ne-resize",width:"12px",height:"12px",right:"1px",top:"1px",backgroundImage:"url('data:image/svg+xml;utf8,".concat(encodeURIComponent($u),"')"),backgroundPosition:"center",backgroundRepeat:"no-repeat"},se:{cursor:"se-resize",width:"12px",height:"12px",right:"1px",bottom:"1px",backgroundImage:"url('data:image/svg+xml;utf8,".concat(encodeURIComponent(Bu),"')"),backgroundPosition:"center",backgroundRepeat:"no-repeat"},sw:{cursor:"sw-resize",width:"12px",height:"12px",left:"1px",bottom:"1px",backgroundImage:"url('data:image/svg+xml;utf8,".concat(encodeURIComponent(Wu),"')"),backgroundPosition:"center",backgroundRepeat:"no-repeat"}},Fu=function(e){s(n,e);var t=f(n);function n(e){var i;return r(this,n),a(c(i=t.call(this,e)),"onDragStart",(function(e){i.connectToSortable&&(i.container.connectedSortables=[],B(document,i.connectToSortable).forEach((function(t){var n=t[Nu];n&&!n.disabled&&(i.container.connectedSortables.push(n),n.refreshPositions(),n.trigger(new Cu({sortable:n,sensorEvent:e.sensorEvent,draggable:i.container})))})))})),a(c(i),"onDragMove",(function(e){var t=e.sensorEvent;i.connectToSortable&&i.container.connectedSortables.forEach((function(n){var r=!1,o=i.container,a=o.helperSize,s=o.position,l=i.container.offset,u=l.click,c=l.parent;n.helperSize=a,n.offset.click=u,n.position.absolute=s.absolute,n.intersectsWith(n.elementProportions)&&(r=!0,i.container.connectedSortables.forEach((function(e){e.helperSize=a,e.offset.click=u,e.position.absolute=s.absolute,e!==n&&e.intersectsWith(e.elementProportions)&&lu(n.element,e.element)&&(r=!1)}))),r?(n.isDraggableOver||(i.container.previousHelperParent||(i.container.previousHelperParent=i.container.helper.parentNode),i.container.helper[Nu]=n,n.element.appendChild(i.container.helper),n.previousHelper=n.options.helper,n.options.helper=function(){return i.container.helper},n.currentItem=i.container.helper,n.connectedDraggable=i.container,t.target=n.currentItem,n.over(null,i.container),n.isDraggableOver=!0,n.onDragStart({detail:t},!0,!0),n.offset.click=u,n.offset.parent.left-=c.left-n.offset.parent.left,n.offset.parent.top-=c.top-n.offset.parent.top,i.container.connectedSortables.forEach((function(e){return e.refreshPositions()}))),n.currentItem&&(n.onDragMove({detail:t},!1,!0),e.position=n.position.current)):!r&&n.isDraggableOver&&(n.previousRevert=n.options.revert,n.options.revert=!1,n.out(null,i.container),n.isDraggableOver=!1,n.cancelHelperRemoval=n.helper===n.currentItem,n.placeholder&&n.placeholder.parentNode.removeChild(n.placeholder),n.onDragStop({detail:t},!0),n.options.helper=n.previousHelper,n.previousHelper=null,n.options.revert=n.previousRevert,n.previousRevert=null,i.container.previousHelperParent.appendChild(i.container.helper),i.container.helper[Nu]=null,i.container.calculateOffsets(t),i.container.calculatePosition(t),i.container.connectedSortables.forEach((function(e){return e.refreshPositions()})),e.position=i.container.position.current)}))})),a(c(i),"onDragStop",(function(e){var t=e.sensorEvent;i.connectToSortable&&(i.container.cancelHelperRemoval=!1,i.container.connectedSortables.forEach((function(n){n.isDraggableOver?(delete i.container.helper[Nu],i.container.cancelHelperRemoval=!0,n.cancelHelperRemoval=!1,n.options.helper=n.previousHelper,n.previousHelper=null,n.previousRevert=n.options.revert,n.options.revert=!1,e.droppedSortable=n,n.out(null,i.container),n.isDraggableOver=!1,n.currentItemStyle={position:A(n.placeholder,"position"),left:wu(n.placeholder,"left"),top:wu(n.placeholder,"top")},n.onDragStop({detail:t},!0),n.options.revert=n.previousRevert,n.previousRevert=null,n.currentItem=null,n.connectedDraggable=null,i.container.helper[Nu]=null,i.container.connectedSortables.forEach((function(e){return e.refreshPositions()}))):n.cancelHelperRemoval=!1,n.trigger(new Ru({sortable:n,sensorEvent:t,draggable:i.container})),n.currentItem=null,n.connectedDraggable=null})),i.container.connectedSortables=[])})),i.attach(),i}return o(n,[{key:"supported",get:function(){return this.isSortable()}},{key:"connectToSortable",get:function(){return this.container.options.connectToSortable||null}}]),n}(y);Gn({target:"Array",stat:!0},{isArray:er});var Xu=function(e){s(n,e);var t=f(n);function n(e){var i;return r(this,n),a(c(i=t.call(this,e)),"constraintPosition",(function(e){if(i.containment){var t=d(i.containment,4),n=t[0],r=t[1],o=t[2],a=t[3],s=i.container.containmentContainer,l=i.container.offset.click;if(s){var u=V(s);n+=u.left,r+=u.top,o+=u.left,a+=u.top}e.pageX-l.lefto&&(e.pageX=o+l.left),e.pageY-l.top>a&&(e.pageY=a+l.top)}return e})),i.attach(),i}return o(n,[{key:"supported",get:function(){return this.isDraggable()||this.isSortable()}},{key:"containment",get:function(){if(void 0===this.container.containmentCoords){var e=this.container.options.containment,t=this.container.offset,n=t.parent,r=t.relative,i=this.container,o=i.helper,a=i.helperSize,s=i.margins;if("window"===e)this.container.containmentCoords=[window.pageXOffset-n.left-r.left,window.pageYOffset-n.top-r.top,window.pageXOffset+window.innerWidth-a.width-s.left,window.pageYOffset+window.innerHeight-a.height-s.top];else if("document"===e)this.container.containmentCoords=[0,0,re(document)-a.width-s.left,G(document)-a.height-s.top];else if(Array.isArray(e)&&4===e.length)this.container.containmentCoords=e;else{var l="parent"===e?o.parentNode:document.querySelector(e);if(l){var u=/(scroll|auto)/.test(A(l,"overflow"));this.container.containmentContainer=l,this.container.containmentCoords=[wu(l,"borderLeftWidth")+wu(l,"paddingLeft"),wu(l,"borderTopWidth")+wu(l,"paddingTop"),(u?Math.max(l.scrollWidth,l.offsetWidth):l.offsetWidth)-wu(l,"borderRightWidth")-wu(l,"paddingRight")-a.width-s.left-s.right,(u?Math.max(l.scrollHeight,l.offsetHeight):l.offsetHeight)-wu(l,"borderBottomWidth")-wu(l,"paddingBottom")-a.height-s.top-s.bottom]}else this.container.containmentCoords=null}}return this.container.containmentCoords}}]),n}(y),Uu=function(e){s(n,e);var t=f(n);function n(e){var i;return r(this,n),a(c(i=t.call(this,e)),"constraintPosition",(function(e){if(i.grid){var t,n,r,o,a=d(i.grid,2),s=a[0],l=a[1],u=i.container,c=u.containmentCoords,h=u.containmentContainer,f=u.startEvent,p=i.container.offset.click;if(c){var g=d(c,4);if(t=g[0],r=g[1],n=g[2],o=g[3],c&&h){var v=V(h);t+=v.left,r+=v.top,n+=v.left,o+=v.top}}var m=s?f.pageX+Math.round((e.pageX-f.pageX)/s)*s:f.pageX,y=l?f.pageY+Math.round((e.pageY-f.pageY)/l)*l:f.pageY;c?(m-p.left>=t||m-p.left>n?e.pageX=m:e.pageX=m+s,y-p.top>=r||y-p.top>o?e.pageY=y:e.pageY=y+l):(e.pageX=m,e.pageY=y)}return e})),i.attach(),i}return o(n,[{key:"supported",get:function(){return this.isDraggable()||this.isSortable()}},{key:"grid",get:function(){var e=this.container.options;return Array.isArray(e.grid)&&2===e.grid.length?e.grid:null}}]),n}(y),Vu=function(e){s(n,e);var t=f(n);function n(e){var i;return r(this,n),a(c(i=t.call(this,e)),"containmentContainer",null),a(c(i),"containmentAttrs",{offset:null,position:null,size:null}),a(c(i),"onDragStart",(function(e){var t=i.container.helper,n=i.container.options.containment;if("document"===n)i.containmentContainer=document,i.containmentAttrs.offset={left:0,top:0},i.containmentAttrs.position={left:0,top:0},i.containmentAttrs.size={width:re(document),height:G(document)||document.body.parentNode.scrollHeight};else{var r=[],o="parent"===n?t.parentNode:document.querySelector(n);o&&(i.containmentContainer=o,["Top","Right","Bottom","Left"].forEach((function(e){r[e.toLowerCase()]=wu(o,"padding".concat(e))})),i.containmentAttrs.offset=V(o),i.containmentAttrs.position=Q(o),i.containmentAttrs.size={width:re(o)-r.left-r.right,height:G(o)-r.top-r.bottom})}})),a(c(i),"onDragMove",(function(e){var t=i.container.offset.helper,n={left:0,top:0},r=e.size,o=e.position,a=i.container,s=a.aspectRatio,l=a.helper,u=i.container.options.containment,h=i.container.currentAttrs,f=h.size,p=h.position,d=c(i).containmentContainer,g=i.containmentAttrs,v=g.size,m=g.offset;d&&(d!==document&&"static"===A(d,"position")&&(n=m),p.left<0&&(r.width+=p.left,s&&(r.height=r.width/s),o.left=0),p.top<0&&(r.height+=p.top,s&&(r.width=r.height*s),o.top=0),"parent"===u&&/absolute|relative/.test(A(d,"position"))?(t.left=n.left+p.left,t.top=n.top+p.top):t=V(l),f.width+(t.left-n.left)>=v.width&&(r.width=v.width-(t.left-n.left),s&&(r.height=f.width/s)),f.height+(t.top-n.top)>=v.height&&(r.height=v.height-(t.top-n.top),s&&(r.width=f.height*s)))})),i.attach(),i}return o(n,[{key:"supported",get:function(){return this.isResizable()}}]),n}(y),Gu=function(e){s(n,e);var t=f(n);function n(e){var i;return r(this,n),a(c(i=t.call(this,e)),"onDragMove",(function(e){if(i.grid){var t=d(i.grid,2),n=t[0],r=t[1],o=e.size,a=e.position,s=i.container,l=s.currentDirection,u=s.helper,c=i.container.originalAttrs,h=c.size,f=c.position,p=i.container.options,g=p.minWidth,v=p.maxWidth,m=p.minHeight,y=p.maxHeight,b={x:h.width+Math.round((o.width-h.width)/n)*n,y:h.height+Math.round((o.height-h.height)/r)*r},w={width:b.x,height:b.y};if(g&&g>w.width&&(w.width+=n),v&&vw.height&&(w.height+=r),y&&y0?(o.width=w.width,a.left=f.left-b.x):(o.width=n-x.width,a.left=f.left+h.width-w.width),w.height-r>0?(o.height=w.height,a.top=f.top-b.y):(o.height=r-x.height,a.top=f.top+h.height-w.height)}}})),i.attach(),i}return o(n,[{key:"supported",get:function(){return this.isResizable()}},{key:"grid",get:function(){var e=this.container.options;return Array.isArray(e.grid)&&2===e.grid.length?e.grid:null}}]),n}(y),qu={update:null,begin:null,loopBegin:null,changeBegin:null,change:null,changeComplete:null,loopComplete:null,complete:null,loop:1,direction:"normal",autoplay:!0,timelineOffset:0},Zu={duration:1e3,delay:0,endDelay:0,easing:"easeOutElastic(1, .5)",round:0},Ku=["translateX","translateY","translateZ","rotate","rotateX","rotateY","rotateZ","scale","scaleX","scaleY","scaleZ","skew","skewX","skewY","perspective","matrix","matrix3d"],Qu={CSS:{},springs:{}};function Ju(e,t,n){return Math.min(Math.max(e,t),n)}function ec(e,t){return e.indexOf(t)>-1}function tc(e,t){return e.apply(null,t)}var nc={arr:function(e){return Array.isArray(e)},obj:function(e){return ec(Object.prototype.toString.call(e),"Object")},pth:function(e){return nc.obj(e)&&e.hasOwnProperty("totalLength")},svg:function(e){return e instanceof SVGElement},inp:function(e){return e instanceof HTMLInputElement},dom:function(e){return e.nodeType||nc.svg(e)},str:function(e){return"string"==typeof e},fnc:function(e){return"function"==typeof e},und:function(e){return void 0===e},nil:function(e){return nc.und(e)||null===e},hex:function(e){return/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(e)},rgb:function(e){return/^rgb/.test(e)},hsl:function(e){return/^hsl/.test(e)},col:function(e){return nc.hex(e)||nc.rgb(e)||nc.hsl(e)},key:function(e){return!qu.hasOwnProperty(e)&&!Zu.hasOwnProperty(e)&&"targets"!==e&&"keyframes"!==e}};function rc(e){var t=/\(([^)]+)\)/.exec(e);return t?t[1].split(",").map((function(e){return parseFloat(e)})):[]}function ic(e,t){var n=rc(e),r=Ju(nc.und(n[0])?1:n[0],.1,100),i=Ju(nc.und(n[1])?100:n[1],.1,100),o=Ju(nc.und(n[2])?10:n[2],.1,100),a=Ju(nc.und(n[3])?0:n[3],.1,100),s=Math.sqrt(i/r),l=o/(2*Math.sqrt(i*r)),u=l<1?s*Math.sqrt(1-l*l):0,c=l<1?(l*s-a)/u:-a+s;function h(e){var n=t?t*e/1e3:e;return n=l<1?Math.exp(-n*l*s)*(1*Math.cos(u*n)+c*Math.sin(u*n)):(1+c*n)*Math.exp(-n*s),0===e||1===e?e:1-n}return t?h:function(){var t=Qu.springs[e];if(t)return t;for(var n=1/6,r=0,i=0;;)if(1===h(r+=n)){if(++i>=16)break}else i=0;var o=r*n*1e3;return Qu.springs[e]=o,o}}function oc(e){return void 0===e&&(e=10),function(t){return Math.ceil(Ju(t,1e-6,1)*e)*(1/e)}}var ac,sc,lc=function(){var e=.1;function t(e,t){return 1-3*t+3*e}function n(e,t){return 3*t-6*e}function r(e){return 3*e}function i(e,i,o){return((t(i,o)*e+n(i,o))*e+r(i))*e}function o(e,i,o){return 3*t(i,o)*e*e+2*n(i,o)*e+r(i)}return function(t,n,r,a){if(0<=t&&t<=1&&0<=r&&r<=1){var s=new Float32Array(11);if(t!==n||r!==a)for(var l=0;l<11;++l)s[l]=i(l*e,t,r);return function(e){return t===n&&r===a||0===e||1===e?e:i(u(e),n,a)}}function u(n){for(var a=0,l=1;10!==l&&s[l]<=n;++l)a+=e;--l;var u=a+(n-s[l])/(s[l+1]-s[l])*e,c=o(u,t,r);return c>=.001?function(e,t,n,r){for(var a=0;a<4;++a){var s=o(t,n,r);if(0===s)return t;t-=(i(t,n,r)-e)/s}return t}(n,u,t,r):0===c?u:function(e,t,n,r,o){var a,s,l=0;do{(a=i(s=t+(n-t)/2,r,o)-e)>0?n=s:t=s}while(Math.abs(a)>1e-7&&++l<10);return s}(n,a,a+e,t,r)}}}(),uc=(ac={linear:function(){return function(e){return e}}},sc={Sine:function(){return function(e){return 1-Math.cos(e*Math.PI/2)}},Circ:function(){return function(e){return 1-Math.sqrt(1-e*e)}},Back:function(){return function(e){return e*e*(3*e-2)}},Bounce:function(){return function(e){for(var t,n=4;e<((t=Math.pow(2,--n))-1)/11;);return 1/Math.pow(4,3-n)-7.5625*Math.pow((3*t-2)/22-e,2)}},Elastic:function(e,t){void 0===e&&(e=1),void 0===t&&(t=.5);var n=Ju(e,1,10),r=Ju(t,.1,2);return function(e){return 0===e||1===e?e:-n*Math.pow(2,10*(e-1))*Math.sin((e-1-r/(2*Math.PI)*Math.asin(1/n))*(2*Math.PI)/r)}}},["Quad","Cubic","Quart","Quint","Expo"].forEach((function(e,t){sc[e]=function(){return function(e){return Math.pow(e,t+2)}}})),Object.keys(sc).forEach((function(e){var t=sc[e];ac["easeIn"+e]=t,ac["easeOut"+e]=function(e,n){return function(r){return 1-t(e,n)(1-r)}},ac["easeInOut"+e]=function(e,n){return function(r){return r<.5?t(e,n)(2*r)/2:1-t(e,n)(-2*r+2)/2}},ac["easeOutIn"+e]=function(e,n){return function(r){return r<.5?(1-t(e,n)(1-2*r))/2:(t(e,n)(2*r-1)+1)/2}}})),ac);function cc(e,t){if(nc.fnc(e))return e;var n=e.split("(")[0],r=uc[n],i=rc(e);switch(n){case"spring":return ic(e,t);case"cubicBezier":return tc(lc,i);case"steps":return tc(oc,i);default:return tc(r,i)}}function hc(e){try{return document.querySelectorAll(e)}catch(e){return}}function fc(e,t){for(var n=e.length,r=arguments.length>=2?arguments[1]:void 0,i=[],o=0;o1&&(n-=1),n<1/6?e+6*(t-e)*n:n<.5?t:n<2/3?e+(t-e)*(2/3-n)*6:e}if(0==a)t=n=r=s;else{var c=s<.5?s*(1+a):s+a-s*a,h=2*s-c;t=u(h,c,o+1/3),n=u(h,c,o),r=u(h,c,o-1/3)}return"rgba("+255*t+","+255*n+","+255*r+","+l+")"}(e):void 0;var t,n}function wc(e){var t=/[+-]?\d*\.?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?(%|px|pt|em|rem|in|cm|mm|ex|ch|pc|vw|vh|vmin|vmax|deg|rad|turn)?$/.exec(e);if(t)return t[1]}function xc(e,t){return nc.fnc(e)?e(t.target,t.id,t.total):e}function Ec(e,t){return e.getAttribute(t)}function kc(e,t,n){if(gc([n,"deg","rad","turn"],wc(t)))return t;var r=Qu.CSS[t+n];if(!nc.und(r))return r;var i=document.createElement(e.tagName),o=e.parentNode&&e.parentNode!==document?e.parentNode:document.body;o.appendChild(i),i.style.position="absolute",i.style.width=100+n;var a=100/i.offsetWidth;o.removeChild(i);var s=a*parseFloat(t);return Qu.CSS[t+n]=s,s}function Sc(e,t,n){if(t in e.style){var r=t.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),i=e.style[t]||getComputedStyle(e).getPropertyValue(r)||"0";return n?kc(e,i,n):i}}function Pc(e,t){return nc.dom(e)&&!nc.inp(e)&&(!nc.nil(Ec(e,t))||nc.svg(e)&&e[t])?"attribute":nc.dom(e)&&gc(Ku,t)?"transform":nc.dom(e)&&"transform"!==t&&Sc(e,t)?"css":null!=e[t]?"object":void 0}function Ic(e){if(nc.dom(e)){for(var t,n=e.style.transform||"",r=/(\w+)\(([^)]*)\)/g,i=new Map;t=r.exec(n);)i.set(t[1],t[2]);return i}}function Oc(e,t,n,r){var i=ec(t,"scale")?1:0+function(e){return ec(e,"translate")||"perspective"===e?"px":ec(e,"rotate")||ec(e,"skew")?"deg":void 0}(t),o=Ic(e).get(t)||i;return n&&(n.transforms.list.set(t,o),n.transforms.last=t),r?kc(e,o,r):o}function Dc(e,t,n,r){switch(Pc(e,t)){case"transform":return Oc(e,t,r,n);case"css":return Sc(e,t,n);case"attribute":return Ec(e,t);default:return e[t]||0}}function Cc(e,t){var n=/^(\*=|\+=|-=)/.exec(e);if(!n)return e;var r=wc(e)||0,i=parseFloat(t),o=parseFloat(e.replace(n[0],""));switch(n[0][0]){case"+":return i+o+r;case"-":return i-o+r;case"*":return i*o+r}}function Ac(e,t){if(nc.col(e))return bc(e);if(/\s/g.test(e))return e;var n=wc(e),r=n?e.substr(0,e.length-n.length):e;return t?r+t:r}function Lc(e,t){return Math.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2))}function zc(e){for(var t,n=e.points,r=0,i=0;i0&&(r+=Lc(t,o)),t=o}return r}function Mc(e){if(e.getTotalLength)return e.getTotalLength();switch(e.tagName.toLowerCase()){case"circle":return function(e){return 2*Math.PI*Ec(e,"r")}(e);case"rect":return function(e){return 2*Ec(e,"width")+2*Ec(e,"height")}(e);case"line":return function(e){return Lc({x:Ec(e,"x1"),y:Ec(e,"y1")},{x:Ec(e,"x2"),y:Ec(e,"y2")})}(e);case"polyline":return zc(e);case"polygon":return function(e){var t=e.points;return zc(e)+Lc(t.getItem(t.numberOfItems-1),t.getItem(0))}(e)}}function jc(e,t){var n=t||{},r=n.el||function(e){for(var t=e.parentNode;nc.svg(t)&&nc.svg(t.parentNode);)t=t.parentNode;return t}(e),i=r.getBoundingClientRect(),o=Ec(r,"viewBox"),a=i.width,s=i.height,l=n.viewBox||(o?o.split(" "):[0,0,a,s]);return{el:r,viewBox:l,x:l[0]/1,y:l[1]/1,w:a,h:s,vW:l[2],vH:l[3]}}function Tc(e,t,n){function r(n){void 0===n&&(n=0);var r=t+n>=1?t+n:0;return e.el.getPointAtLength(r)}var i=jc(e.el,e.svg),o=r(),a=r(-1),s=r(1),l=n?1:i.w/i.vW,u=n?1:i.h/i.vH;switch(e.property){case"x":return(o.x-i.x)*l;case"y":return(o.y-i.y)*u;case"angle":return 180*Math.atan2(s.y-a.y,s.x-a.x)/Math.PI}}function Rc(e,t){var n=/[+-]?\d*\.?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/g,r=Ac(nc.pth(e)?e.totalLength:e,t)+"";return{original:r,numbers:r.match(n)?r.match(n).map(Number):[0],strings:nc.str(e)||t?r.split(n):[]}}function Hc(e){return fc(e?pc(nc.arr(e)?e.map(dc):dc(e)):[],(function(e,t,n){return n.indexOf(e)===t}))}function Nc(e){var t=Hc(e);return t.map((function(e,n){return{target:e,id:n,total:t.length,transforms:{list:Ic(e)}}}))}function _c(e,t){var n=vc(t);if(/^spring/.test(n.easing)&&(n.duration=ic(n.easing)),nc.arr(e)){var r=e.length;2===r&&!nc.obj(e[0])?e={value:e}:nc.fnc(t.duration)||(n.duration=t.duration/r)}var i=nc.arr(e)?e:[e];return i.map((function(e,n){var r=nc.obj(e)&&!nc.pth(e)?e:{value:e};return nc.und(r.delay)&&(r.delay=n?0:t.delay),nc.und(r.endDelay)&&(r.endDelay=n===i.length-1?t.endDelay:0),r})).map((function(e){return yc(e,n)}))}function $c(e,t){var n=[],r=t.keyframes;for(var i in r&&(t=yc(function(e){for(var t=fc(pc(e.map((function(e){return Object.keys(e)}))),(function(e){return nc.key(e)})).reduce((function(e,t){return e.indexOf(t)<0&&e.push(t),e}),[]),n={},r=function(r){var i=t[r];n[i]=e.map((function(e){var t={};for(var n in e)nc.key(n)?n==i&&(t.value=e[n]):t[n]=e[n];return t}))},i=0;i0?requestAnimationFrame(t):void 0}return"undefined"!=typeof document&&document.addEventListener("visibilitychange",(function(){Zc.suspendWhenDocumentHidden&&(qc()?e=cancelAnimationFrame(e):(Vc.forEach((function(e){return e._onDocumentVisibility()})),Gc()))})),function(){e||qc()&&Zc.suspendWhenDocumentHidden||!(Vc.length>0)||(e=requestAnimationFrame(t))}}();function qc(){return!!document&&document.hidden}function Zc(e){void 0===e&&(e={});var t,n=0,r=0,i=0,o=0,a=null;function s(e){var t=window.Promise&&new Promise((function(e){return a=e}));return e.finished=t,t}var l=function(e){var t=mc(qu,e),n=mc(Zu,e),r=$c(n,e),i=Nc(e.targets),o=Fc(i,r),a=Xc(o,n),s=Uc;return Uc++,yc(t,{id:s,children:[],animatables:i,animations:o,duration:a.duration,delay:a.delay,endDelay:a.endDelay})}(e);function u(){var e=l.direction;"alternate"!==e&&(l.direction="normal"!==e?"normal":"reverse"),l.reversed=!l.reversed,t.forEach((function(e){return e.reversed=l.reversed}))}function c(e){return l.reversed?l.duration-e:e}function h(){n=0,r=c(l.currentTime)*(1/Zc.speed)}function f(e,t){t&&t.seek(e-t.timelineOffset)}function p(e){for(var t=0,n=l.animations,r=n.length;t2||(y=Math.round(y*p)/p)),d.push(y)}var x=f.length;if(x){v=f[0];for(var E=0;E0&&(l.began=!0,d("begin")),!l.loopBegan&&l.currentTime>0&&(l.loopBegan=!0,d("loopBegin")),m<=g&&0!==l.currentTime&&p(0),(m>=v&&l.currentTime!==h||!h)&&p(h),m>g&&m=h&&(r=0,l.remaining&&!0!==l.remaining&&l.remaining--,l.remaining?(n=i,d("loopComplete"),l.loopBegan=!1,"alternate"===l.direction&&u()):(l.paused=!0,l.completed||(l.completed=!0,d("loopComplete"),d("complete"),!l.passThrough&&"Promise"in window&&(a(),s(l)))))}return s(l),l.reset=function(){var e=l.direction;l.passThrough=!1,l.currentTime=0,l.progress=0,l.paused=!0,l.began=!1,l.loopBegan=!1,l.changeBegan=!1,l.completed=!1,l.changeCompleted=!1,l.reversePlayback=!1,l.reversed="reverse"===e,l.remaining=l.loop,t=l.children;for(var n=o=t.length;n--;)l.children[n].reset();(l.reversed&&!0!==l.loop||"alternate"===e&&1===l.loop)&&l.remaining++,p(l.reversed?l.duration:0)},l._onDocumentVisibility=h,l.set=function(e,t){return Yc(e,t),l},l.tick=function(e){i=e,n||(n=i),g((i+(r-n))*Zc.speed)},l.seek=function(e){g(c(e))},l.pause=function(){l.paused=!0,h()},l.play=function(){l.paused&&(l.completed&&l.reset(),l.paused=!1,Vc.push(l),h(),Gc())},l.reverse=function(){u(),l.completed=!l.reversed,h()},l.restart=function(){l.reset(),l.play()},l.remove=function(e){Qc(Hc(e),l)},l.reset(),l.autoplay&&l.play(),l}function Kc(e,t){for(var n=t.length;n--;)gc(e,t[n].animatable.target)&&t.splice(n,1)}function Qc(e,t){var n=t.animations,r=t.children;Kc(e,n);for(var i=r.length;i--;){var o=r[i],a=o.animations;Kc(e,a),a.length||o.children.length||r.splice(i,1)}n.length||r.length||t.pause()}Zc.version="3.2.1",Zc.speed=1,Zc.suspendWhenDocumentHidden=!0,Zc.running=Vc,Zc.remove=function(e){for(var t=Hc(e),n=Vc.length;n--;){Qc(t,Vc[n])}},Zc.get=Dc,Zc.set=Yc,Zc.convertPx=kc,Zc.path=function(e,t){var n=nc.str(e)?hc(e)[0]:e,r=t||100;return function(e){return{property:e,el:n,svg:jc(n),totalLength:Mc(n)*(r/100)}}},Zc.setDashoffset=function(e){var t=Mc(e);return e.setAttribute("stroke-dasharray",t),t},Zc.stagger=function(e,t){void 0===t&&(t={});var n=t.direction||"normal",r=t.easing?cc(t.easing):null,i=t.grid,o=t.axis,a=t.from||0,s="first"===a,l="center"===a,u="last"===a,c=nc.arr(e),h=c?parseFloat(e[0]):parseFloat(e),f=c?parseFloat(e[1]):0,p=wc(c?e[1]:e)||0,d=t.start||0+(c?h:0),g=[],v=0;return function(e,t,m){if(s&&(a=0),l&&(a=(m-1)/2),u&&(a=m-1),!g.length){for(var y=0;y-1&&Vc.splice(i,1);for(var s=0;s0){var t=i.container.helper,n=i.stack.sort((function(e,t){return wu(e,"zIndex")-wu(t,"zIndex")})),r=wu(n[0],"zIndex");n.forEach((function(e,t){A(e,{zIndex:r+t})})),A(t,{zIndex:r+n.length})}})),i.attach(),i}return o(n,[{key:"supported",get:function(){return this.isDraggable()}},{key:"stack",get:function(){var e=this.container.options;return e.stack?B(document,e.stack):[]}}]),n}(y),ph=yn,dh=bn,gh=Object.keys||function(e){return ph(e,dh)},vh=We,mh=Fe,yh=gh,bh=le?Object.defineProperties:function(e,t){mh(e);for(var n,r=yh(t),i=r.length,o=0;i>o;)vh.f(e,n=r[o++],t[n]);return e},wh=Zt("document","documentElement"),xh=Fe,Eh=bh,kh=bn,Sh=St,Ph=wh,Ih=Le,Oh=kt("IE_PROTO"),Dh=function(){},Ch=function(e){return"